Exemple #1
0
        private SimpleField <TMessage> BuildSimpleField <TMessage, TProperty>(FieldHandlerDefinition definition)
        {
            var toReturn          = new SimpleField <TMessage>();
            var messageParameter  = Expression.Parameter(definition.MessageType, "message");
            var datomParameter    = Expression.Parameter(typeof(Datom), "datom");
            var datomValue        = Expression.Property(datomParameter, $"{nameof(Datom.Value)}");
            var deserializedValue = definition.PrimitiveSerializer.GetDeserializeExpression(datomValue);

            if (definition.IsRepeated)
            {
                var datomArrayIndex = Expression.Property(datomParameter, $"{nameof(Datom.ParameterArrayIndex)}");
                var insertIntoRepeatedFieldMethod = definition.PropertyOuterType.GetMethod($"{nameof(RepeatedField<bool>.Insert)}");
                var insertExpression = Expression.Call(
                    messageParameter,
                    insertIntoRepeatedFieldMethod,
                    datomArrayIndex,
                    deserializedValue
                    );
                var insertFunction = Expression.Lambda <Action <TMessage, Datom> >(
                    insertExpression,
                    messageParameter,
                    datomParameter
                    ).Compile();
                toReturn.Deserialize = insertFunction;
                toReturn.Serialize   = BuildSerializeFunction <TMessage, TProperty>(definition);
            }
            else
            {
                var fieldExpression    = Expression.PropertyOrField(messageParameter, definition.Property.Name);
                var setFieldExpression = Expression.Assign(fieldExpression, deserializedValue);
                var setFieldFunction   = Expression.Lambda <Action <TMessage, Datom> >(
                    setFieldExpression,
                    messageParameter,
                    datomParameter
                    ).Compile();
                toReturn.Deserialize = setFieldFunction;
                toReturn.Serialize   = BuildSerializeFunction <TMessage, TProperty>(definition);
            }

            return(toReturn);
        }
Exemple #2
0
        private Func <TMessage, Datom, IEnumerable <Datom> > BuildSerializeFunction <TMessage, TProperty>(FieldHandlerDefinition definition)
        {
            var messageParameter   = Expression.Parameter(definition.MessageType, "message");
            var prototypeParameter = Expression.Parameter(typeof(Datom), "prototype");

            var fieldOnMessage = Expression.Property(messageParameter, definition.Property);

            var messageTypeRegistrationType = typeof(TypeRegistration <>).MakeGenericType(definition.MessageType);

            var messageIdGetterExpressionBuilder = (Func <ParameterExpression, Expression>)messageTypeRegistrationType
                                                   .GetField($"{nameof(TypeRegistration<int>.KeyGetterExpressionBuilder)}")
                                                   .GetValue(definition.MessageTypeRegistration);

            var arrayElementParameter = Expression.Parameter(definition.PropertyType, "element");
            var arrayIndexParameter   = Expression.Parameter(typeof(int), "i");
            var arrayIndexAsUInt      = Expression.Convert(arrayIndexParameter, typeof(uint));

            var        parameterIndexExpression   = definition.IsRepeated ? (Expression)arrayIndexAsUInt : (Expression)Expression.Constant((uint)0, typeof(uint));
            var        referencedObjectExpression = definition.IsRepeated ? (Expression)arrayElementParameter : (Expression)fieldOnMessage;
            Expression valueExpression;
            Expression shouldSerializeExpression;

            if (definition.IsReference)
            {
                var propertyTypeRegistration     = (TypeRegistration <TProperty>)_typeRegistry.TypeRegistrationByType(definition.PropertyType);
                var arrayElementIdentityProperty = propertyTypeRegistration.KeyGetterExpressionBuilder(referencedObjectExpression);
                valueExpression           = _primitiveSerializers[typeof(ulong)].GetSerializeExpression(arrayElementIdentityProperty);
                shouldSerializeExpression = Expression.NotEqual(referencedObjectExpression, Expression.Constant(null));
            }
            else
            {
                valueExpression           = definition.PrimitiveSerializer.GetSerializeExpression(referencedObjectExpression);
                shouldSerializeExpression = definition.PrimitiveSerializer.GetShouldSerializeExpression(referencedObjectExpression);
            }

            var messageIdentityExpression = messageIdGetterExpressionBuilder(messageParameter);

            var constructInstance = Expression.New(
                typeof(Datom).GetConstructors().OrderByDescending(x => x.GetParameters().Count()).First(),
                Expression.Property(prototypeParameter, $"{nameof(Datom.AggregateType)}"),                 //ushort aggregateTypeId,
                Expression.Property(prototypeParameter, $"{nameof(Datom.AggregateIdentity)}"),             //ulong aggregateId,
                Expression.Constant(definition.MessageTypeRegistration.TypeId, typeof(ushort)),            //ushort type,
                messageIdentityExpression,                                                                 //ulong identity,
                Expression.Constant((ushort)definition.FieldDescriptor.FieldNumber, typeof(ushort)),       //ushort parameter,
                parameterIndexExpression,                                                                  //uint parameterIndex,
                valueExpression,                                                                           //byte[] value,
                Expression.Property(prototypeParameter, $"{nameof(Datom.TransactionId)}"),                 //ulong transactionId,
                Expression.Property(prototypeParameter, $"{nameof(Datom.Action)}")                         //DatomAction action
                );

            Expression serializeExpression;

            if (definition.IsRepeated)
            {
                var mapperDelegateType = typeof(Func <, ,>).MakeGenericType(definition.PropertyType, typeof(int), typeof(Datom));
                var mapper             = Expression.Lambda(mapperDelegateType, constructInstance, arrayElementParameter, arrayIndexParameter);

                var iEnumerableType             = typeof(IEnumerable <>).MakeGenericType(definition.PropertyType);
                var fieldOnMessageAsIEnumerable = Expression.Convert(fieldOnMessage, iEnumerableType);

                //public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
                var whereMethod = typeof(Enumerable).GetMethods()
                                  .First(x => x.Name == $"{nameof(Enumerable.Where)}" && x.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2)
                                  .MakeGenericMethod(definition.PropertyType);

                //public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector);
                var selectMethod = typeof(Enumerable).GetMethods()
                                   .First(x => x.Name == $"{nameof(Enumerable.Select)}" && x.GetParameters()[1].ParameterType.GetGenericArguments().Length == 3)
                                   .MakeGenericMethod(definition.PropertyType, typeof(Datom));

                var shouldSerializeLambda = Expression.Lambda <Func <TProperty, bool> >(shouldSerializeExpression, arrayElementParameter);

                var whereExpression = Expression.Call(whereMethod, fieldOnMessageAsIEnumerable, shouldSerializeLambda);

                serializeExpression = Expression.Call(selectMethod, whereExpression, mapper);
            }
            else
            {
                var yieldMethod = typeof(ProtobufDatomSerializer)
                                  .GetMethod($"{nameof(ProtobufDatomSerializer.Yield)}", BindingFlags.Static | BindingFlags.NonPublic)
                                  .MakeGenericMethod(typeof(Datom));

                serializeExpression = Expression.Condition(
                    shouldSerializeExpression,
                    Expression.Call(yieldMethod, constructInstance),
                    Expression.Constant(Enumerable.Empty <Datom>(), typeof(IEnumerable <Datom>))
                    );
            }

            return(Expression.Lambda <Func <TMessage, Datom, IEnumerable <Datom> > >(
                       serializeExpression,
                       messageParameter,
                       prototypeParameter
                       ).Compile());
        }
Exemple #3
0
        private ReferenceField <TMessage> BuildReferenceField <TMessage, TProperty>(FieldHandlerDefinition definition)
        {
            var toReturn                    = new ReferenceField <TMessage>();
            var messageParameter            = Expression.Parameter(definition.MessageType, "message");
            var fieldOnMessage              = Expression.Property(messageParameter, definition.Property);
            var repeatedFieldIndexParameter = Expression.Parameter(typeof(int), "repeatedFieldIndex");
            var referencedObjectParameter   = Expression.Parameter(typeof(object), "referencedObject");
            var referencedObjectCasted      = Expression.Convert(referencedObjectParameter, definition.PropertyType);

            if (definition.IsRepeated)
            {
                var insertIntoRepeatedFieldMethod = definition.PropertyOuterType.GetMethod($"{nameof(RepeatedField<bool>.Insert)}");
                var insertExpression = Expression.Call(
                    fieldOnMessage,
                    insertIntoRepeatedFieldMethod,
                    repeatedFieldIndexParameter,
                    referencedObjectCasted
                    );
                var insertFunction = Expression.Lambda <Action <TMessage, int, object> >(
                    insertExpression,
                    messageParameter,
                    repeatedFieldIndexParameter,
                    referencedObjectParameter
                    ).Compile();
                toReturn.SetReference = insertFunction;

                var fieldOnMessageAsIEnumerableObject = Expression.Convert(fieldOnMessage, typeof(IEnumerable <object>));
                toReturn.Follow = Expression.Lambda <Func <TMessage, IEnumerable <object> > >(fieldOnMessageAsIEnumerableObject, messageParameter).Compile();

                toReturn.Serialize = BuildSerializeFunction <TMessage, TProperty>(definition);
            }
            else
            {
                var setFieldExpression = Expression.Assign(fieldOnMessage, referencedObjectCasted);
                var setFieldFunction   = Expression.Lambda <Action <TMessage, int, object> >(
                    setFieldExpression,
                    messageParameter,
                    repeatedFieldIndexParameter,
                    referencedObjectParameter
                    ).Compile();
                toReturn.SetReference = setFieldFunction;

                var yieldMethod = typeof(ProtobufDatomSerializer)
                                  .GetMethod($"{nameof(ProtobufDatomSerializer.Yield)}", BindingFlags.Static | BindingFlags.NonPublic)
                                  .MakeGenericMethod(typeof(object));

                var yieldReferencedObject = Expression.Call(yieldMethod, Expression.Convert(fieldOnMessage, typeof(object)));
                toReturn.Follow = Expression.Lambda <Func <TMessage, IEnumerable <object> > >(yieldReferencedObject, messageParameter).Compile();

                toReturn.Serialize = BuildSerializeFunction <TMessage, TProperty>(definition);
            }

            //var datomParameter = Expression.Parameter(typeof(Datom), "datom");
            //var datomValueAccess = Expression.Property(datomParameter, $"{nameof(Datom.Value)}");
            //var convertToULongMethod = typeof(BitConverter).GetMethod($"{nameof(BitConverter.ToUInt64)}");
            //var getReferencedId = Expression.Call(convertToULongMethod, datomValueAccess, Expression.Constant(0));
            //toReturn.DeserializeIdentity = Expression.Lambda<Func<Datom, ulong>>(getReferencedId, datomParameter).Compile();
            toReturn.DeserializeIdentity = (datom) => BitConverter.ToUInt64(datom.Value, 0);
            if (!_typeRegistry.IsTypeRegistered(definition.PropertyType))
            {
                throw new InvalidOperationException($"Unable to create reference {definition.MessageType.FullName}.{definition.Property.Name}"
                                                    + $" because the type {definition.PropertyType.FullName} is not registered. ");
            }
            toReturn.ReferencedTypeId = _typeRegistry.TypeRegistrationByType(definition.PropertyType).TypeId;

            return(toReturn);
        }
Exemple #4
0
        private Func <FieldDescriptor, int, KeyValuePair <ushort, FieldHandler> > FieldHandlerBuilder(BaseTypeRegistration typeRegistration)
        {
            return((discriptor, fieldIndex) =>
            {
                var messageType = typeRegistration.Type;
                var titleCaseName = $"{discriptor.Name.Substring(0, 1).ToUpper()}{discriptor.Name.Substring(1)}";
                var property = messageType.GetProperty(titleCaseName);

                Type propertyOuterType = null;
                Type propertyType;
                var isRepeated = property.PropertyType.GetTypeInfo().IsGenericType
                    ? property.PropertyType.GetGenericTypeDefinition() == typeof(RepeatedField <>)
                    : false;

                if (isRepeated)
                {
                    propertyOuterType = property.PropertyType;
                    propertyType = propertyOuterType.GetGenericArguments()[0];
                }
                else
                {
                    propertyType = property.PropertyType;
                }
                var isReference = typeof(IMessage).IsAssignableFrom(propertyType);
                var isPrimitive = _primitiveSerializers.ContainsKey(propertyType);

                if (!isReference && !isPrimitive)
                {
                    throw new InvalidOperationException($"Unable to find a primitive serializer for type {property.PropertyType.FullName}.");
                }

                var definition = new FieldHandlerDefinition()
                {
                    FieldDescriptor = discriptor,
                    MessageTypeRegistration = typeRegistration,
                    Property = property,
                    MessageType = messageType,
                    PropertyOuterType = propertyOuterType,
                    PropertyType = propertyType,
                    IsReference = isReference,
                    IsRepeated = isRepeated,
                    PrimitiveSerializer = isPrimitive ? _primitiveSerializers[propertyType] : null
                };

                FieldHandler toReturn;
                if (isReference)
                {
                    var buildBuildReferenceField = typeof(ProtobufDatomSerializer)
                                                   .GetMethod($"{nameof(ProtobufDatomSerializer.BuildReferenceField)}", PrivateInstance)
                                                   .MakeGenericMethod(messageType, propertyType);

                    toReturn = buildBuildReferenceField.Invoke(this, new object[] { definition }) as FieldHandler;
                }
                else
                {
                    var buildBuildSimpleField = typeof(ProtobufDatomSerializer)
                                                .GetMethod($"{nameof(ProtobufDatomSerializer.BuildSimpleField)}", PrivateInstance)
                                                .MakeGenericMethod(messageType, propertyType);

                    toReturn = buildBuildSimpleField.Invoke(this, new object[] { definition }) as FieldHandler;
                }

                Func <byte[], string> debugDeserializer;
                if (isPrimitive)
                {
                    var valueParameter = Expression.Parameter(typeof(byte[]), "value");
                    var deserialize = _primitiveSerializers[propertyType].GetDeserializeExpression(valueParameter);
                    var toStringMethod = propertyType.GetMethods().First(x => x.Name == "ToString");
                    var deserializeToString = Expression.Call(deserialize, toStringMethod);
                    debugDeserializer = Expression.Lambda <Func <byte[], string> >(deserializeToString, valueParameter).Compile();
                }
                else
                {
                    debugDeserializer = (value) => BitConverter.ToUInt64(value, 0).ToString();
                }

                _debugFormatters[new Tuple <ushort, ushort>(typeRegistration.TypeId, (ushort)discriptor.FieldNumber)] = (datom) => {
                    var valueFormat = isReference ? $"{propertyType.Name}[{{0}}]" : "{0}";
                    var fieldArrayIndex = isRepeated ? $"[{datom.ParameterArrayIndex}]": string.Empty;
                    return $"TX[{datom.TransactionId}] {datom.Action} {typeRegistration.Type.Name}[{datom.Identity}]"
                    + $".{discriptor.Name}{fieldArrayIndex} = {string.Format(valueFormat, debugDeserializer(datom.Value))}";
                };

                return new KeyValuePair <ushort, FieldHandler>((ushort)discriptor.FieldNumber, toReturn);
            });
        }