예제 #1
0
        private SerializerPair CreateCustomScalar <T>()
        {
            if (typeof(IRdBindable).IsAssignableFrom(typeof(T)))
            {
                Assertion.Fail($"Invalid scalar type: {typeof(T).ToString(true)}. Scalar types cannot be IRdBindable.");
            }
            if (typeof(T).IsInterface || typeof(T).IsAbstract)
            {
                Assertion.Fail($"Invalid scalar type: {typeof(T).ToString(true)}. Scalar types should be concrete types.");
            }

            TypeInfo typeInfo      = typeof(T).GetTypeInfo();
            var      allowNullable = ReflectionSerializerVerifier.CanBeNull(typeInfo);

            var memberInfos   = SerializerReflectionUtil.GetBindableMembers(typeInfo);
            var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
            var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();

            // todo: consider using IL emit
            var memberDeserializers = new CtxReadDelegate <object> [memberInfos.Length];
            var memberSerializers   = new CtxWriteDelegate <object> [memberInfos.Length];

            CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) =>
            {
                if (allowNullable && !unsafeReader.ReadNullness())
                {
                    return(default);
예제 #2
0
        internal static void FillBindableFields(IReflectionBindable instance)
        {
            var type = instance.GetType();
            Action <IReflectionBindable> fillBindableFields;

            lock (ourFillBindableChildren)
            {
                ourFillBindableChildren.TryGetValue(type, out fillBindableFields);
            }

            if (fillBindableFields == null)
            {
                var t = type;
                var bindableMembers = SerializerReflectionUtil.GetBindableMembers(t.GetTypeInfo()).ToArray();
                var getters         = bindableMembers.Select(ReflectionUtil.GetGetter).ToArray();

                fillBindableFields = (obj) =>
                {
                    for (int i = 0; i < bindableMembers.Length; i++)
                    {
                        var value = getters[i](obj);
                        obj.BindableChildren.Add(new KeyValuePair <string, object>(bindableMembers[i].Name, value));
                    }
                };
                lock (ourFillBindableChildren)
                {
                    ourFillBindableChildren[t] = fillBindableFields;
                }
            }

            fillBindableFields(instance);
        }
        public static void AssertValidRdModel([NotNull] TypeInfo type)
        {
            var isDataModel = HasRdModelAttribute(type);

            Assertion.Assert(isDataModel, $"Error in {type.ToString(true)} model: no {nameof(RdModelAttribute)} attribute specified");
            Assertion.Assert(typeof(RdReflectionBindableBase).GetTypeInfo().IsAssignableFrom(type.AsType()), $"Error in {type.ToString(true)} model: should be inherited from {nameof(RdReflectionBindableBase)}");

            // No way to prevent serialization errors for intrinsic serializers, just skip for now
            if (HasIntrinsic(type))
            {
                return;
            }

            foreach (var member in SerializerReflectionUtil.GetBindableMembers(type))
            {
                AssertDataMemberDeclaration(member);
            }
        }
        public static void AssertValidRdExt(TypeInfo type)
        {
            var isRdModel = HasRdExtAttribute(type);

            Assertion.Assert(isRdModel, $"Error in {type.ToString(true)} model: no {nameof(RdExtAttribute)} attribute specified");
            Assertion.Assert(!type.IsValueType, $"Error in {type.ToString(true)} model: can't be ValueType");
            Assertion.Assert(typeof(RdExtReflectionBindableBase).GetTypeInfo().IsAssignableFrom(type.AsType()), $"Error in {type.ToString(true)} model: should be inherited from {nameof(RdExtReflectionBindableBase)}");

            // actually, it is possible, but error-prone.
            // you may have non-rdmodel base class and several sealed derivatives from it.
            // commented sealed check to avoid annoying colleagues.
            // Assertion.Assert(type.IsSealed, $"Error in {type.ToString(true)} model: RdModels must be sealed.");

            foreach (var member in SerializerReflectionUtil.GetBindableMembers(type))
            {
                AssertMemberDeclaration(member);
            }
        }
예제 #5
0
        /// <summary>
        /// Register serializers for either <see cref="RdExtAttribute"/> or <see cref="RdModelAttribute"/>
        /// </summary>
        private void RegisterModelSerializer <T>()
        {
            Assertion.Assert(!ReflectionSerializerVerifier.IsScalar(typeof(T)), "Type {0} should be either RdModel or RdExt.", typeof(T));
            // place null marker to detect circular dependencies
            mySerializers.Add(typeof(T), null);

            TypeInfo typeInfo = typeof(T).GetTypeInfo();

            ReflectionSerializerVerifier.AssertRoot(typeInfo);
            var  isScalar      = ReflectionSerializerVerifier.IsScalar(typeInfo);
            bool allowNullable = ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo) || (isScalar && ReflectionSerializerVerifier.CanBeNull(typeInfo));

/*      var intrinsicSerializer = TryGetIntrinsicSerializer(typeInfo);
 *    if (intrinsicSerializer != null)
 *    {
 *      mySerializers[typeof(T)] = intrinsicSerializer;
 *      return;
 *    }*/

            var memberInfos   = SerializerReflectionUtil.GetBindableMembers(typeInfo);
            var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
            var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();

            // todo: consider using IL emit
            var memberDeserializers = new CtxReadDelegate <object> [memberInfos.Length];
            var memberSerializers   = new CtxWriteDelegate <object> [memberInfos.Length];

            for (var index = 0; index < memberInfos.Length; index++)
            {
                var mi         = memberInfos[index];
                var returnType = ReflectionUtil.GetReturnType(mi);
                var serPair    = GetOrCreateMemberSerializer(mi, serializerType: returnType, allowNullable: allowNullable);
                memberDeserializers[index] = SerializerReflectionUtil.ConvertReader(returnType, serPair.Reader);
                memberSerializers[index]   = SerializerReflectionUtil.ConvertWriter(returnType, serPair.Writer);
            }

            var type = typeInfo.AsType();

            CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) =>
            {
                if (allowNullable && !unsafeReader.ReadNullness())
                {
                    return(default);
예제 #6
0
        internal static void PrettyPrint(PrettyPrinter p, IReflectionBindable instance)
        {
            Action <IReflectionBindable, PrettyPrinter> prettyPrinter;

            lock (ourPrettyPrintersLock)
            {
                ourPrettyPrinters.TryGetValue(instance.GetType(), out prettyPrinter);
            }

            if (prettyPrinter == null)
            {
                var t               = instance.GetType();
                var header          = t.Name + " (";
                var bindableMembers = SerializerReflectionUtil.GetBindableMembers(t.GetTypeInfo());
                var getters         = bindableMembers.Select(ReflectionUtil.GetGetter).ToArray();
                var intros          = bindableMembers.Select(mi => $"{mi.Name} = ").ToArray();

                prettyPrinter = (o, printer) =>
                {
                    printer.Print(header);
                    using (printer.IndentCookie())
                    {
                        for (int i = 0; i < getters.Length; i++)
                        {
                            printer.Print(intros[i]);
                            getters[i](o).PrintEx(printer);
                            printer.Println();
                        }
                    }

                    printer.Print(")");
                };
                lock (ourPrettyPrintersLock)
                {
                    ourPrettyPrinters[t] = prettyPrinter;
                }
            }

            prettyPrinter(instance, p);
        }
예제 #7
0
        private object ReflectionInitInternal(object instance)
        {
            var typeInfo = instance.GetType().GetTypeInfo();

            if (ReflectionSerializerVerifier.HasRdExtAttribute(instance.GetType().GetTypeInfo()))
            {
                ReflectionSerializerVerifier.AssertValidRdExt(typeInfo);
            }

            foreach (var mi in SerializerReflectionUtil.GetBindableMembers(typeInfo))
            {
                ReflectionSerializerVerifier.AssertMemberDeclaration(mi);
                var currentValue = ReflectionUtil.GetGetter(mi)(instance);
                if (currentValue == null)
                {
                    currentValue = ActivateRdExtMember(mi);

                    var memberSetter = ReflectionUtil.GetSetter(mi);
                    memberSetter(instance, currentValue);
                }
                else
                {
                    var implementingType = ReflectionSerializerVerifier.GetImplementingType(ReflectionUtil.GetReturnType(mi).GetTypeInfo());
                    Assertion.Assert(currentValue.GetType() == implementingType,
                                     "Bindable field {0} was initialized with incompatible type. Expected type {1}, actual {2}",
                                     mi,
                                     implementingType.ToString(true),
                                     currentValue.GetType().ToString(true));
                }
            }

            // Add RdEndpoint for Impl class (counterpart of Proxy)
            var  interfaces   = typeInfo.GetInterfaces();
            bool isProxy      = interfaces.Contains(typeof(IProxyTypeMarker));
            var  rpcInterface = ReflectionSerializersFactory.GetRpcInterface(typeInfo);

            if (!isProxy && rpcInterface != null)
            {
                var bindableChildren = ((IReflectionBindable)instance).BindableChildren;

                var interfaceMap     = typeInfo.GetInterfaceMap(rpcInterface);
                var interfaceMethods = interfaceMap.InterfaceMethods;

                // Dynamic adapters for Properties are not required, so skip them
                var ignoreMethods = new HashSet <string>(StringComparer.Ordinal);
                foreach (var propertyInfo in rpcInterface.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    ignoreMethods.Add(propertyInfo.GetSetMethod()?.Name);
                    ignoreMethods.Add(propertyInfo.GetGetMethod()?.Name);
                }

                foreach (var interfaceMethod in interfaceMethods)
                {
                    if (ignoreMethods.Contains(interfaceMethod.Name))
                    {
                        continue;
                    }

                    var adapter = myProxyGenerator.CreateAdapter(rpcInterface, interfaceMethod);

                    var name        = ProxyGenerator.ProxyFieldName(interfaceMethod);
                    var requestType = ProxyGenerator.GetRequstType(interfaceMethod)[0];
                    EnsureFakeTupleRegistered(requestType);

                    var responseNonTaskType = ProxyGenerator.GetResponseType(interfaceMethod, unwrapTask: true);
                    var responseType        = ProxyGenerator.GetResponseType(interfaceMethod, unwrapTask: false);
                    var endPointType        = typeof(RdCall <,>).MakeGenericType(requestType, responseNonTaskType);
                    var endpoint            = ActivateGenericMember(name, endPointType.GetTypeInfo());
                    SetAsync(interfaceMethod, endpoint);
                    if (endpoint is RdReactiveBase reactiveBase)
                    {
                        reactiveBase.ValueCanBeNull = true;
                    }
                    if (ProxyGenerator.IsSync(interfaceMethod))
                    {
                        var delType    = typeof(Func <, ,>).MakeGenericType(typeof(Lifetime), requestType, typeof(RdTask <>).MakeGenericType(responseNonTaskType));
                        var @delegate  = adapter.CreateDelegate(delType, instance);
                        var methodInfo = typeof(ReflectionRdActivator).GetMethod(nameof(SetHandler)).NotNull().MakeGenericMethod(requestType, responseNonTaskType);
                        methodInfo.Invoke(null, new[] { endpoint, @delegate });
                    }
                    else
                    {
                        if (responseType == typeof(Task))
                        {
                            var delType    = typeof(Func <, ,>).MakeGenericType(typeof(Lifetime), requestType, typeof(Task));
                            var @delegate  = adapter.CreateDelegate(delType, instance);
                            var methodInfo = typeof(ReflectionRdActivator).GetMethod(nameof(SetHandlerTaskVoid)).NotNull().MakeGenericMethod(requestType);
                            methodInfo.Invoke(null, new[] { endpoint, @delegate });
                        }
                        else
                        {
                            var delType    = typeof(Func <, ,>).MakeGenericType(typeof(Lifetime), requestType, typeof(Task <>).MakeGenericType(responseNonTaskType));
                            var @delegate  = adapter.CreateDelegate(delType, instance);
                            var methodInfo = typeof(ReflectionRdActivator).GetMethod(nameof(SetHandlerTask)).NotNull().MakeGenericMethod(requestType, responseNonTaskType);
                            methodInfo.Invoke(null, new[] { endpoint, @delegate });
                        }
                    }

                    bindableChildren.Add(new KeyValuePair <string, object>(name, endpoint));
                }
            }
            else if (rpcInterface != null)
            {
                foreach (var interfaceMethod in rpcInterface.GetMethods())
                {
                    var requestType = ProxyGenerator.GetRequstType(interfaceMethod)[0];
                    EnsureFakeTupleRegistered(requestType);
                }
            }

            // Allow initialize to setup bindings to composite properties.
            if (instance is IReflectionBindable reflectionBindable)
            {
                reflectionBindable.OnActivated();
            }

            return(instance);
        }
예제 #8
0
파일: Intrinsic.cs 프로젝트: Tryweirder/rd
        public static SerializerPair TryGetIntrinsicSerializer(TypeInfo typeInfo, Func <Type, SerializerPair> getInstanceSerializer)
        {
            if (ReflectionSerializerVerifier.HasIntrinsicNonProtocolMethods(typeInfo))
            {
                var genericArguments = typeInfo.GetGenericArguments();

                /*
                 * if (genericArguments.Length == 1)
                 * {
                 * var argument = genericArguments[0];
                 * var staticRead = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo, argument);
                 * var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo);
                 * return SerializerPair.CreateFromMethods(staticRead, staticWrite, getInstanceSerializer(argument));
                 * }
                 */
                if (genericArguments.Length == 0)
                {
                    var staticRead     = SerializerReflectionUtil.GetReadStaticNonProtocolSerializer(typeInfo);
                    var instanceWriter = SerializerReflectionUtil.GetWriteNonProtocolDeserializer(typeInfo);
                    return(SerializerPair.CreateFromNonProtocolMethods(staticRead, instanceWriter));
                }

                return(null);
            }

            if (ReflectionSerializerVerifier.HasIntrinsicProtocolMethods(typeInfo))
            {
                var genericArguments = typeInfo.GetGenericArguments();
                if (genericArguments.Length == 1)
                {
                    var argument    = genericArguments[0];
                    var staticRead  = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo, argument);
                    var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo);
                    return(SerializerPair.CreateFromMethods(staticRead, staticWrite, getInstanceSerializer(argument)));
                }

                if (genericArguments.Length == 0)
                {
                    var staticRead  = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo);
                    var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo);
                    return(SerializerPair.CreateFromMethods(staticRead, staticWrite));
                }

                return(null);
            }
            else if (ReflectionSerializerVerifier.HasIntrinsicFields(typeInfo))
            {
                var readField  = typeInfo.GetField("Read", BindingFlags.Public | BindingFlags.Static);
                var writeField = typeInfo.GetField("Write", BindingFlags.Public | BindingFlags.Static);
                if (readField == null)
                {
                    Assertion.Fail($"Invalid intrinsic serializer for type {typeInfo}. Static field 'Read' with type {typeof(CtxReadDelegate<>).ToString(true)} not found");
                }
                if (writeField == null)
                {
                    Assertion.Fail($"Invalid intrinsic serializer for type {typeInfo}. Static field 'Write' with type {typeof(CtxWriteDelegate<>).ToString(true)} not found");
                }
                var reader = readField.GetValue(null);
                var writer = writeField.GetValue(null);
                return(new SerializerPair(reader, writer));
            }
            else if (ReflectionSerializerVerifier.HasIntrinsicAttribute(typeInfo))
            {
                var marshallerType = typeInfo.GetCustomAttribute <RdScalarAttribute>().NotNull().Marshaller;
                var marshaller     = Activator.CreateInstance(marshallerType);
                return((SerializerPair)ReflectionUtil.InvokeStaticGeneric(typeof(SerializerPair), nameof(SerializerPair.FromMarshaller), typeInfo, marshaller));
            }

            return(null);
        }