Example #1
0
        /// <summary>
        /// Creates an expression reading the specified struct type.
        /// </summary>
        private static LambdaExpression CreateReaderForStruct(ThriftStruct thriftStruct)
        {
            var protocolParam = Expression.Parameter(typeof(IThriftProtocol));

            var structType = thriftStruct.TypeInfo.AsType();
            var structVar  = Expression.Variable(structType);

            var wireFields = thriftStruct.Fields.Select(f => ThriftWireField.Field(f, structVar)).ToList();

            return(Expression.Lambda(
                       Expression.Block(
                           structType,
                           new[] { structVar },

                           Expression.Assign(
                               structVar,
                               Expression.New(structType)
                               ),

                           CreateReaderForFields(protocolParam, wireFields),

                           // return value
                           structVar
                           ),
                       protocolParam
                       ));
        }
Example #2
0
        /// <summary>
        /// Creates an expression writing the specified struct type.
        /// </summary>
        private static LambdaExpression CreateWriterForStruct(ThriftStruct thriftStruct)
        {
            var valueParam    = Expression.Parameter(thriftStruct.TypeInfo.AsType());
            var protocolParam = Expression.Parameter(typeof(IThriftProtocol));

            var methodContents = new List <Expression>
            {
                Expression.Call(
                    protocolParam,
                    Methods.IThriftProtocol_WriteStructHeader,
                    Expression.New(
                        Constructors.ThriftStructHeader,
                        Expression.Constant(thriftStruct.Header.Name)
                        )
                    )
            };

            foreach (var field in thriftStruct.Fields)
            {
                methodContents.Add(CreateWriterForField(protocolParam, ThriftWireField.Field(field, valueParam)));
            }

            methodContents.Add(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteFieldStop));
            methodContents.Add(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteStructEnd));

            return(Expression.Lambda(
                       Expression.Block(methodContents),
                       valueParam, protocolParam
                       ));
        }
Example #3
0
        /// <summary>
        /// Creates a writer for the specified method.
        /// </summary>
        private static Expression <Action <object[], IThriftProtocol> > CreateWriterForMethod(ThriftMethod method)
        {
            var argsParam     = Expression.Parameter(typeof(object[]));
            var protocolParam = Expression.Parameter(typeof(IThriftProtocol));

            var methodContents = new List <Expression>
            {
                Expression.Call(
                    protocolParam,
                    Methods.IThriftProtocol_WriteMessageHeader,
                    Expression.New(
                        Constructors.ThriftMessageHeader,
                        Expression.Constant(method.Name),
                        Expression.Constant(method.IsOneWay ? ThriftMessageType.OneWay : ThriftMessageType.Call)
                        )
                    ),

                Expression.Call(
                    protocolParam,
                    Methods.IThriftProtocol_WriteStructHeader,
                    Expression.New(
                        Constructors.ThriftStructHeader,
                        Expression.Constant("")
                        )
                    )
            };

            for (int n = 0; n < method.Parameters.Count; n++)
            {
                var wireField = ThriftWireField.Parameter(method.Parameters[n], argsParam, n);
                methodContents.Add(ThriftStructWriter.CreateWriterForField(protocolParam, wireField));
            }

            methodContents.Add(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteFieldStop));
            methodContents.Add(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteStructEnd));
            methodContents.Add(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteMessageEnd));

            return(Expression.Lambda <Action <object[], IThriftProtocol> >(
                       Expression.Block(methodContents),
                       argsParam, protocolParam
                       ));
        }
Example #4
0
        /// <summary>
        /// Creates a reader for the specified method.
        /// </summary>
        private static LambdaExpression CreateReaderForMethod(ThriftMethod method)
        {
            var protocolParam = Expression.Parameter(typeof(IThriftProtocol));

            var headerVariable = Expression.Variable(typeof(ThriftMessageHeader));
            ParameterExpression hasReturnVariable = null;
            ParameterExpression returnVariable    = null;

            if (method.ReturnValue.UnderlyingTypeInfo != TypeInfos.Void)
            {
                hasReturnVariable = Expression.Variable(typeof(bool));
                returnVariable    = Expression.Variable(method.ReturnValue.UnderlyingTypeInfo.AsType());
            }

            var wireFields = new List <ThriftWireField>();

            if (returnVariable != null)
            {
                wireFields.Add(ThriftWireField.ReturnValue(method.ReturnValue, returnVariable, hasReturnVariable));
            }
            foreach (var exception in method.Exceptions)
            {
                wireFields.Add(ThriftWireField.ThrowsClause(exception));
            }

            var statements = new List <Expression>
            {
                Expression.Assign(
                    headerVariable,
                    Expression.Call(
                        protocolParam,
                        Methods.IThriftProtocol_ReadMessageHeader
                        )
                    ),

                Expression.IfThen(
                    // Do not use IsFalse, not supported by UWP's expression interpreter
                    Expression.Equal(
                        Expression.Call(
                            Methods.Enum_IsDefined,
                            // The second argument is absolutely crucial here.
                            // System.Type is an abstract class, implemented by an internal framework class System.RuntimeType
                            // Not specifying the argument leads to the expression's type being typeof(System.RuntimeType),
                            // which crashes on frameworks that restrict access to non-public framework types, such as Windows Phone 8.1
                            Expression.Constant(typeof(ThriftMessageType), typeof(Type)),
                            Expression.Convert(
                                Expression.Field(headerVariable, Fields.ThriftMessageHeader_MessageType),
                                typeof(object)
                                )
                            ),
                        Expression.Constant(false)
                        ),
                    Expression.Throw(
                        Expression.New(
                            Constructors.ThriftProtocolException,
                            Expression.Constant(ThriftProtocolExceptionType.InvalidMessageType)
                            )
                        )
                    ),

                Expression.IfThen(
                    Expression.Equal(
                        Expression.Field(headerVariable, Fields.ThriftMessageHeader_MessageType),
                        Expression.Constant(ThriftMessageType.Exception)
                        ),
                    Expression.Throw(
                        Expression.Call(
                            typeof(ThriftStructReader),
                            "Read",
                            new[] { typeof(ThriftProtocolException) },
                            protocolParam
                            )
                        )
                    ),

                ThriftStructReader.CreateReaderForFields(protocolParam, wireFields),

                Expression.Call(protocolParam, Methods.IThriftProtocol_ReadMessageEnd)
            };

            if (returnVariable != null)
            {
                statements.Add(
                    Expression.IfThen(
                        Expression.Equal(
                            hasReturnVariable,
                            Expression.Constant(false)
                            ),
                        Expression.Throw(
                            Expression.New(
                                Constructors.ThriftProtocolException,
                                Expression.Constant(ThriftProtocolExceptionType.MissingResult)
                                )
                            )
                        )
                    );
            }

            if (returnVariable == null)
            {
                statements.Add(Expression.Constant(null));
            }
            else
            {
                statements.Add(returnVariable);
            }

            return(Expression.Lambda(
                       Expression.Block(
                           returnVariable?.Type ?? typeof(object),
                           returnVariable == null ? new[] { headerVariable } : new[] { headerVariable, hasReturnVariable, returnVariable },
                           statements
                           ),
                       new[] { protocolParam }
                       ));
        }
Example #5
0
        /// <summary>
        /// Creates an expression writing the specified field.
        /// </summary>
        public static Expression CreateWriterForField(ParameterExpression protocolParam, ThriftWireField field)
        {
            Expression getter = field.Getter;
            bool       isUnderlyingNullable = Nullable.GetUnderlyingType(field.UnderlyingTypeInfo.AsType()) != null;

            if (isUnderlyingNullable)
            {
                getter = Expression.Property(getter, "Value");
            }
            if (field.Converter != null)
            {
                getter = field.Converter.CreateCall("ConvertBack", getter);
            }

            var writingExpr = Expression.Block(
                Expression.Call(
                    protocolParam,
                    Methods.IThriftProtocol_WriteFieldHeader,
                    Expression.New(
                        Constructors.ThriftFieldHeader,
                        Expression.Constant(field.Id),
                        Expression.Constant(field.Name),
                        Expression.Constant(field.WireType.Id)
                        )
                    ),
                CreateWriterForType(
                    protocolParam,
                    field.WireType,
                    getter
                    ),
                Expression.Call(protocolParam, Methods.IThriftProtocol_WriteFieldEnd)
                );

            switch (field.Kind)
            {
            case ThriftWireFieldState.AlwaysPresent:
                return(writingExpr);

            case ThriftWireFieldState.Required:
                // It's possible to have a nullable required field if it's converted to a class
                if (field.UnderlyingTypeInfo.IsClass || isUnderlyingNullable)
                {
                    return(Expression.IfThenElse(
                               field.NullChecker,
                               Expression.Throw(
                                   Expression.Call(
                                       Methods.ThriftSerializationException_RequiredFieldIsNull,
                                       Expression.Constant(field.Name)
                                       )
                                   ),
                               writingExpr
                               ));
                }
                return(writingExpr);

            default:
                if (field.DefaultValue == null && (field.UnderlyingTypeInfo.IsClass || isUnderlyingNullable))
                {
                    return(Expression.IfThen(
                               // Do not use IsFalse, not supported by UWP's expression interpreter
                               Expression.Equal(
                                   field.NullChecker,
                                   Expression.Constant(false)
                                   ),
                               writingExpr
                               ));
                }

                var condition = Expression.NotEqual(
                    getter,
                    Expression.Constant(field.DefaultValue)
                    );

                if (field.UnderlyingTypeInfo.IsClass || isUnderlyingNullable)
                {
                    condition = Expression.AndAlso(
                        // Do not use IsTrue, not supported by UWP's expression interpreter
                        Expression.Equal(
                            field.NullChecker,
                            Expression.Constant(false)
                            ),
                        condition
                        );
                }

                return(Expression.IfThen(condition, writingExpr));
            }
        }