/// <summary> /// Writes the specified method call on the specified protocol. /// </summary> public static void Write(ThriftMethod method, object[] args, IThriftProtocol protocol) { if (!_knownWriters.ContainsKey(method)) { _knownWriters.TryAdd(method, CreateWriterForMethod(method).Compile()); } _knownWriters[method](args, protocol); }
/// <summary> /// Reads a ThriftMessage returned by the specified method on the specified protocol. /// </summary> public static T Read <T>(ThriftMethod method, IThriftProtocol protocol) { if (!_knownReaders.ContainsKey(method)) { _knownReaders.TryAdd(method, CreateReaderForMethod(method).Compile()); } return(((Func <IThriftProtocol, T>)_knownReaders[method])(protocol)); }
/// <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 )); }
/// <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 } )); }