Beispiel #1
0
        static public int iter(IntPtr l)
        {
            object o = checkObj(l, 1);

            if (o is IEnumerable)
            {
                IEnumerable e     = o as IEnumerable;
                var         einfo = new EnumerableInfo {
                    Enumerable = e
                };
                einfo.Reset();
                pushValue(l, true);
                pushLightObject(l, einfo);
                LuaDLL.lua_pushcclosure(l, _iter, 1);
                return(2);
            }
            else
            {
                var einfo = new EnumerableInfo {
                    Enumerable = o
                };
                einfo.Reset();
                if (null == einfo.Enumerator)
                {
                    return(error(l, "passed in object isn't enumerable"));
                }
                pushValue(l, true);
                pushLightObject(l, einfo);
                LuaDLL.lua_pushcclosure(l, _iter, 1);
                return(2);
            }
        }
        public void FindMethods()
        {
            var sb = new StringBuilder();

            foreach (var type in new[]
            {
                typeof(List <int>),
                typeof(IEnumerable <int>),
                typeof(ExplicitEnumerableBadCount),
                typeof(ExplicitReadOnlyCollection),
                typeof(ExplicitReadOnlyCollectionImplicitCount),
                typeof(ExplicitReadOnlyCollectionPublicEnumerator),
                typeof(ICollection <short>),
                typeof(IReadOnlyCollection <ushort>),
                typeof(IReadOnlyList <long>),
                typeof(IList <ulong>),
                this.GetType(),                 // throw in something non enumerable
            })
            {
                var methods = EnumerableInfo.FindMethods(type);
                sb.AppendLine("# " + SchemaTest.HumanName(type));
                DescribeMethod(sb, () => methods.GetEnumerator);
                DescribeMethod(sb, () => methods.MoveNext);
                DescribeMethod(sb, () => methods.get_Current);
                DescribeMethod(sb, () => methods.get_Count);
                DescribeMethod(sb, () => methods.Dispose);

                sb.AppendLine();
            }

            ApprovalTests.Approvals.Verify(sb.ToString());
        }
        private void GenerateILForPushingEnumeratorOntoWriteStack(int depth, EnumerableInfo enumerableInfo)
        {
            switch (enumerableInfo.EnumeratorCategory)
            {
            case EnumeratorCategory.Array:
            case EnumeratorCategory.List:
                // _enumerableContextX = -1;
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldc_I4_M1);
                _ilg.Emit(OpCodes.Stfld, enumerableInfo.EnumerableContextField);
                break;

            case EnumeratorCategory.ValueTypeEnumerator:
                // _enumerableContextX = _writeStackX.GetEnumerator();
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldfld, GetWriteStackFieldAtDepth(depth));
                _ilg.Emit(OpCodes.Call, enumerableInfo.GetEnumeratorMethod);     // struct method cannot be virtual
                _ilg.Emit(OpCodes.Stfld, enumerableInfo.EnumerableContextField);
                break;

            case EnumeratorCategory.ReferenceTypeEnumerator:
                // _writeStackX = _writeStackX.GetEnumerator();
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldfld, GetWriteStackFieldAtDepth(depth));
                _ilg.Emit(OpCodes.Callvirt, enumerableInfo.GetEnumeratorMethod);
                _ilg.Emit(OpCodes.Stfld, GetWriteStackFieldAtDepth(depth));
                break;
            }
        }
            static Expression HandleEnumerable(EnumerableInfo enumerableInfo, Expression enumerable, Func <Expression, Expression> body)
            {
                var enumeratorType     = enumerableInfo.GetEnumerator.ReturnType;
                var enumeratorInfo     = enumerableInfo.EnumeratorInfo;
                var enumeratorVariable = Variable(enumeratorType, "enumerator");

                return(Block(
                           new[] { enumeratorVariable },
                           Assign(enumeratorVariable, CallGetEnumerator(enumerableInfo, enumerable)),
                           enumeratorInfo switch
                {
                    { Dispose: null } => NotDisposable(enumeratorInfo, enumeratorVariable, body),
        private void GenerateILForStartEnumerableWhile(int depth, EnumerableInfo enumerableInfo, Label bottomOfIterationLoop)
        {
            switch (enumerableInfo.EnumeratorCategory)
            {
            case EnumeratorCategory.Array:
            case EnumeratorCategory.List:
                // _enumerableContextX++
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldfld, enumerableInfo.EnumerableContextField);
                _ilg.Emit(OpCodes.Ldc_I4_1);
                _ilg.Emit(OpCodes.Add);
                _ilg.Emit(OpCodes.Stfld, enumerableInfo.EnumerableContextField);

                // while (_enumerableContextX < _writeStackX.Length/Count)
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldfld, enumerableInfo.EnumerableContextField);
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldfld, GetWriteStackFieldAtDepth(depth));
                if (enumerableInfo.EnumeratorCategory == EnumeratorCategory.Array)
                {
                    _ilg.Emit(OpCodes.Ldlen);
                }
                else
                {
                    EmitCallVirtIfNeeded(_ilg, enumerableInfo.GetCountMethod);
                }
                _ilg.Emit(OpCodes.Bge, bottomOfIterationLoop);
                break;

            case EnumeratorCategory.ValueTypeEnumerator:
                // while (_enumerableContextX.MoveNext()) {
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldflda, enumerableInfo.EnumerableContextField);
                MethodInfo moveNextInterfaceMethod = typeof(IEnumerator).GetMethod("MoveNext", new Type[] { });
                MethodInfo moveNextMethod          = GetInterfaceMethodImplementation(enumerableInfo.EnumeratorType, moveNextInterfaceMethod);
                _ilg.Emit(OpCodes.Call, moveNextMethod);
                _ilg.Emit(OpCodes.Brfalse, bottomOfIterationLoop);
                break;

            case EnumeratorCategory.ReferenceTypeEnumerator:
                // while (_writeStackX.MoveNext()) {
                _ilg.Emit(OpCodes.Ldarg_0);
                _ilg.Emit(OpCodes.Ldfld, GetWriteStackFieldAtDepth(depth));
                // MoveNext is defined in IEnumerator
                _ilg.Emit(OpCodes.Callvirt, typeof(IEnumerator).GetMethod("MoveNext", new Type[] { }));
                _ilg.Emit(OpCodes.Brfalse, bottomOfIterationLoop);
                break;
            }
        }
        /// <summary>
        /// Creates a <see cref="System.Linq.Expressions.Expression"/> with behaviour similar to the <c>foreach</c> statement in C#.
        /// </summary>
        /// <param name="enumerableInfo">The information returned by a call to <see cref="NetFabric.Reflection.TypeExtensions.IsEnumerable(Type, out EnumerableInfo)"/>.</param>
        /// <param name="enumerable">An <see cref="System.Linq.Expressions.Expression"/> that defines the enumerator.</param>
        /// <param name="body">
        /// A <see cref="System.Func&lt;Expression, Expression&gt;"/> that returns the body, given an
        /// <see cref="System.Linq.Expressions.Expression"/> that defines the item on each loop iteration.
        /// </param>
        /// <returns>The created <see cref="System.Linq.Expressions.Expression"/>.</returns>
        /// <remarks>
        /// <p>
        /// The created <see cref="System.Linq.Expressions.Expression"/> depends on if the object defined in <paramref name="enumerable"/>
        /// is an <c>interface</c>, <c>class</c>, <c>struct</c>, <c>ref struct</c>, and if is disposable.
        /// </p>
        /// </remarks>
        public static Expression ForEach(EnumerableInfo enumerableInfo, Expression enumerable, Func <Expression, Expression> body)
        {
            var enumerableType = enumerable.Type;

            if (enumerableType.IsArray)
            {
                return(HandleArray(enumerable, body));
            }

            if (enumerableType.FullName is not null &&
                (enumerableType.FullName.StartsWith("System.ReadOnlySpan`1") || enumerableType.FullName.StartsWith("System.Span`1")))
            {
                return(HandleSpan(enumerable, body));
            }

            return(HandleEnumerable(enumerableInfo, enumerable, body));
Beispiel #7
0
        static public int iter(IntPtr l)
        {
            object o = checkObj(l, 1);

            if (o is IEnumerable)
            {
                IEnumerable e     = o as IEnumerable;
                IEnumerator iter  = e.GetEnumerator();
                var         einfo = new EnumerableInfo {
                    Enumerable = e, Enumerator = iter
                };
                pushValue(l, true);
                pushLightObject(l, einfo);
                LuaDLL.lua_pushcclosure(l, _iter, 1);
                return(2);
            }
            return(error(l, "passed in object isn't enumerable"));
        }
        private void GenerateILForIEnumerable(Type type, int depth)
        {
            // First argument: Utf8JsonWriter writer
            // Second argument: IEnumerable<T> enumerable

            Type           enumerateeType = GetIEnumerableGenericType(type);
            EnumerableInfo enumerableInfo = new EnumerableInfo(ref this, type, enumerateeType);

            // writer.WriteStartArray();
            _ilg.Emit(OpCodes.Ldarg_1);
            _ilg.Emit(OpCodes.Call, _writeStartArray);

            GenerateILForPushingEnumeratorOntoWriteStack(depth, enumerableInfo);

            Label topOfIterationLoop    = _ilg.DefineLabel();
            Label bottomOfIterationLoop = _ilg.DefineLabel();

            _ilg.MarkLabel(topOfIterationLoop);

            // while (...) {
            GenerateILForStartEnumerableWhile(depth, enumerableInfo, bottomOfIterationLoop);

            Action pushNextElementOntoStack = GeneratePushNextElementOntoStackLambda(depth, enumerateeType, enumerableInfo);

            JsonConverter converter = GetConverterFromOptions(_options, enumerateeType);

            if (converter == null)
            {
                GenerateILForNestedType(enumerateeType, depth + 1, pushNextElementOntoStack);
            }
            else
            {
                GenerateILForCallingConverter(enumerateeType, pushNextElementOntoStack, converter);
            }

            // }
            _ilg.Emit(OpCodes.Br, topOfIterationLoop);
            _ilg.MarkLabel(bottomOfIterationLoop);

            // writer.WriteEndArray();
            _ilg.Emit(OpCodes.Ldarg_1);
            _ilg.Emit(OpCodes.Call, _writeEndArray);
        }
 internal EnumerableNullableReferenceTypeAssertions(TActual actual, EnumerableInfo enumerableInfo)
     : base(actual)
     => EnumerableInfo = enumerableInfo;
Beispiel #10
0
        protected static void AssertIsEnumerable <TActual, TActualItem>(TActual actual, out EnumerableInfo enumerableInfo)
        {
            var actualType = typeof(TActual);

            if (actualType == typeof(TActualItem[])) // convert TActualItem[] to IList<TActualItem>
            {
                actualType = typeof(IList <>).MakeGenericType(typeof(TActualItem));
            }
            if (actualType.IsEnumerable(out var temp, out var errors))
            {
                enumerableInfo = temp;

                var actualItemType = enumerableInfo.EnumeratorInfo.Current.PropertyType;
                if (actualItemType.IsByRef)
                {
                    if (!actualItemType.IsAssignableTo(typeof(TActualItem).MakeByRefType()))
                    {
                        throw new ActualAssertionException <TActual>(actual, $"Expected to be an enumerable of '{typeof(TActualItem)}' but found an enumerable of '{actualItemType}'.");
                    }
                }
                else
                {
                    if (!actualItemType.IsAssignableTo(typeof(TActualItem)))
                    {
                        throw new ActualAssertionException <TActual>(actual, $"Expected to be an enumerable of '{typeof(TActualItem)}' but found an enumerable of '{actualItemType}'.");
                    }
                }
            }
            else
            {
                if (errors.HasFlag(Errors.MissingGetEnumerator))
                {
                    throw new ActualAssertionException <TActual>(actual, $"Expected to be an enumerable but it's missing a valid 'GetEnumerator' method.");
                }
                if (errors.HasFlag(Errors.MissingCurrent))
                {
                    throw new ActualAssertionException <TActual>(actual, $"Expected to be an enumerator but it's missing a valid 'Current' property.");
                }
                if (errors.HasFlag(Errors.MissingMoveNext))
                {
                    throw new ActualAssertionException <TActual>(actual, $"Expected to be an enumerator but it's missing a valid 'MoveNext' method.");
                }

                enumerableInfo = default !;
 internal EnumerableValueTypeAssertions(TActual actual, EnumerableInfo enumerableInfo)
     : base(actual)
     => EnumerableInfo = enumerableInfo;
Beispiel #12
0
        private Action GeneratePushNextElementOntoStackLambda(int depth, Type enumerateeType, EnumerableInfo enumerableInfo)
        {
            ILGenerator  ilg = _ilg;
            FieldBuilder currentWriteStack      = GetWriteStackFieldAtDepth(depth);
            FieldBuilder enumerableContextField = enumerableInfo.EnumerableContextField;
            MethodInfo   getCurrentMethod;

            switch (enumerableInfo.EnumeratorCategory)
            {
            case EnumeratorCategory.Array:
                return(() =>
                {
                    // _writeStackX[_enumerableContextX]
                    ilg.Emit(OpCodes.Ldarg_0);
                    ilg.Emit(OpCodes.Ldfld, currentWriteStack);
                    ilg.Emit(OpCodes.Ldarg_0);
                    ilg.Emit(OpCodes.Ldfld, enumerableContextField);
                    ilg.Emit(OpCodes.Ldelem, enumerateeType);
                });

            case EnumeratorCategory.List:
                getCurrentMethod = enumerableInfo.IndexAccessorMethod;
                return(() =>
                {
                    // _writeStackX[_enumerableContextX]
                    ilg.Emit(OpCodes.Ldarg_0);
                    ilg.Emit(OpCodes.Ldfld, currentWriteStack);
                    ilg.Emit(OpCodes.Ldarg_0);
                    ilg.Emit(OpCodes.Ldfld, enumerableContextField);
                    EmitCallVirtIfNeeded(ilg, getCurrentMethod);
                });

            case EnumeratorCategory.ValueTypeEnumerator:
                getCurrentMethod = enumerableInfo.GetCurrentMethod;
                return(() =>
                {
                    // _enumerableContextX.Current
                    ilg.Emit(OpCodes.Ldarg_0);
                    ilg.Emit(OpCodes.Ldflda, enumerableContextField);
                    ilg.Emit(OpCodes.Call, getCurrentMethod);
                });

            default:     // Supress compiler error
            case EnumeratorCategory.ReferenceTypeEnumerator:
                getCurrentMethod = enumerableInfo.GetCurrentMethod;
                return(() =>
                {
                    // _writeStackX.Current
                    ilg.Emit(OpCodes.Ldarg_0);
                    ilg.Emit(OpCodes.Ldfld, currentWriteStack);
                    ilg.Emit(OpCodes.Callvirt, getCurrentMethod);
                });
            }
        }
Beispiel #13
0
        private void GenerateILForIDictionary(Type type, int depth)
        {
            // First argument: Utf8JsonWriter writer
            // Second argument: IDictionary<string, T> dictionary

            Type           valueType        = GetIDictionaryGenericType(type)?.Value;
            Type           keyValuePairType = typeof(KeyValuePair <,>).MakeGenericType(typeof(string), valueType);
            EnumerableInfo enumerableInfo   = new EnumerableInfo(ref this, type, keyValuePairType);

            // writer.WriteStartObject();
            _ilg.Emit(OpCodes.Ldarg_1);
            _ilg.Emit(OpCodes.Call, _writeStartObject);

            GenerateILForPushingEnumeratorOntoWriteStack(depth, enumerableInfo);

            Label topOfIterationLoop    = _ilg.DefineLabel();
            Label bottomOfIterationLoop = _ilg.DefineLabel();

            _ilg.MarkLabel(topOfIterationLoop);

            // while (...) {
            GenerateILForStartEnumerableWhile(depth, enumerableInfo, bottomOfIterationLoop);

            Action pushNextKeyValuePairOntoStack = GeneratePushNextElementOntoStackLambda(depth, keyValuePairType, enumerableInfo);

            // KeyValuePair<string, T> kvp = _writeStackX.Current;
            LocalBuilder kvpLocal = _ilg.DeclareLocal(keyValuePairType);

            pushNextKeyValuePairOntoStack();
            _ilg.Emit(OpCodes.Stloc, kvpLocal);

            // writer.WritePropertyName(DictionaryKeyPolicyField.ConvertName(Namekvp.Key))
            _ilg.Emit(OpCodes.Ldarg_1);
            if (_dictionaryKeyPolicy != null)
            {
                _ilg.Emit(OpCodes.Ldsfld, _dictionaryKeyPolicyField);
            }
            _ilg.Emit(OpCodes.Ldloca, kvpLocal);
            _ilg.Emit(OpCodes.Call, keyValuePairType.GetProperty("Key").GetMethod);
            if (_dictionaryKeyPolicy != null)
            {
                _ilg.Emit(OpCodes.Callvirt, typeof(JsonNamingPolicy).GetMethod("ConvertName", new Type[] { typeof(string) }));
            }
            _ilg.Emit(OpCodes.Call, _writePropertyNameWithString);

            JsonConverter converter = GetConverterFromOptions(_options, valueType);

            ILGenerator ilg = _ilg;
            Action      pushValueOntoStack = () =>
            {
                // kvp.Value
                ilg.Emit(OpCodes.Ldloca, kvpLocal);
                ilg.Emit(OpCodes.Call, keyValuePairType.GetProperty("Value").GetMethod);
            };

            if (converter == null)
            {
                GenerateILForNestedType(valueType, depth + 1, pushValueOntoStack);
            }
            else
            {
                GenerateILForCallingConverter(valueType, pushValueOntoStack, converter);
            }

            // }
            _ilg.Emit(OpCodes.Br, topOfIterationLoop);
            _ilg.MarkLabel(bottomOfIterationLoop);

            // writer.WriteEndObject();
            _ilg.Emit(OpCodes.Ldarg_1);
            _ilg.Emit(OpCodes.Call, _writeEndObject);
        }