Exemple #1
0
        /// <summary>
        /// Gets the Thrift wire type associated with the specified type.
        /// </summary>
        public static ThriftType Get(Type type)
        {
            if (!_knownTypes.ContainsKey(type))
            {
                var thriftType = new ThriftType(type);

                _knownTypes.TryAdd(type, thriftType);

                // This has to be done this way because otherwise self-referencing types will loop
                // since they'd call ThriftType.Get before they were themselves added to _knownTypes
                switch (thriftType.Id)
                {
                case ThriftTypeId.Map:
                    thriftType.KeyType   = ThriftType.Get(thriftType._collectionGenericArgs[0]);
                    thriftType.ValueType = ThriftType.Get(thriftType._collectionGenericArgs[1]);
                    break;

                case ThriftTypeId.List:
                case ThriftTypeId.Set:
                    if (thriftType.TypeInfo.IsArray)
                    {
                        thriftType.ElementType = ThriftType.Get(thriftType.TypeInfo.GetElementType());
                    }
                    else
                    {
                        thriftType.ElementType = ThriftType.Get(thriftType._collectionGenericArgs[0]);
                    }
                    break;
                }
            }

            return(_knownTypes[type]);
        }
Exemple #2
0
        /// <summary>
        /// Initializes a new instance of the ThriftWireField class with the specified values.
        /// </summary>
        private ThriftWireField(short id, string name,
                                ThriftType wireType, TypeInfo underlyingTypeInfo,
                                ThriftWireFieldState state, object defaultValue,
                                ThriftConverter converter,
                                Expression getter, Func <Expression, Expression> setter)
        {
            Id                 = id;
            Name               = name;
            WireType           = wireType;
            UnderlyingTypeInfo = underlyingTypeInfo;
            Kind               = state;
            DefaultValue       = defaultValue;
            Converter          = converter;
            Getter             = getter;
            Setter             = setter;

            // NullChecker is required because UWP doesn't implement Equal/NotEqual on nullables.
            if (getter != null)
            {
                if (Nullable.GetUnderlyingType(underlyingTypeInfo.AsType()) == null)
                {
                    if (!underlyingTypeInfo.IsValueType)
                    {
                        NullChecker = Expression.Equal(
                            getter,
                            Expression.Constant(null)
                            );
                    }
                }
                else
                {
                    // Can't use HasValue, not supported by UWP's expression interpreter
                    NullChecker = Expression.Call(
                        typeof(object),
                        "ReferenceEquals",
                        Type.EmptyTypes,
                        Expression.Convert(
                            getter,
                            typeof(object)
                            ),
                        Expression.Constant(null)
                        );
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Creates an expression reading the specified map type.
        /// </summary>
        private static Expression CreateReaderForMap(ParameterExpression protocolParam, ThriftType thriftType)
        {
            var mapType   = thriftType.TypeInfo.AsType();
            var mapVar    = Expression.Variable(mapType);
            var headerVar = Expression.Variable(typeof(ThriftMapHeader));
            var countVar  = Expression.Variable(typeof(int));

            var endOfLoop = Expression.Label();

            return(Expression.Block(
                       mapType,
                       new[] { mapVar, headerVar, countVar },

                       Expression.Assign(
                           mapVar,
                           Expression.New(mapType)
                           ),

                       Expression.Assign(
                           headerVar,
                           Expression.Call(protocolParam, Methods.IThriftProtocol_ReadMapHeader)
                           ),

                       CreateTypeIdAssert(
                           thriftType.KeyType.Id,
                           Expression.Field(headerVar, Fields.ThriftMapHeader_KeyTypeId)
                           ),

                       CreateTypeIdAssert(
                           thriftType.ValueType.Id,
                           Expression.Field(headerVar, Fields.ThriftMapHeader_ValueTypeId)
                           ),

                       Expression.Assign(
                           countVar,
                           Expression.Constant(0)
                           ),

                       Expression.Loop(
                           Expression.IfThenElse(
                               Expression.Equal(
                                   countVar,
                                   Expression.Field(headerVar, Fields.ThriftMapHeader_Count)
                                   ),
                               Expression.Break(endOfLoop),
                               Expression.Block(
                                   Expression.Call(
                                       mapVar,
                                       "Add",
                                       Types.None,
                                       CreateReaderForType(protocolParam, thriftType.KeyType),
                                       CreateReaderForType(protocolParam, thriftType.ValueType)
                                       ),
                                   Expression.PostIncrementAssign(countVar)
                                   )
                               ),
                           endOfLoop
                           ),

                       Expression.Call(protocolParam, Methods.IThriftProtocol_ReadMapEnd),

                       // return value
                       mapVar
                       ));
        }
Exemple #4
0
        /// <summary>
        /// Creates an expression reading for the specified type.
        /// </summary>
        private static Expression CreateReaderForType(ParameterExpression protocolParam, ThriftType thriftType)
        {
            if (thriftType.NullableType != null)
            {
                return(Expression.Convert(
                           CreateReaderForType(protocolParam, thriftType.NullableType),
                           thriftType.TypeInfo.AsType()
                           ));
            }

            switch (thriftType.Id)
            {
            case ThriftTypeId.Boolean:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadBoolean));

            case ThriftTypeId.SByte:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadSByte));

            case ThriftTypeId.Double:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadDouble));

            case ThriftTypeId.Int16:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadInt16));

            case ThriftTypeId.Int32:
                if (thriftType.TypeInfo.IsEnum)
                {
                    return(Expression.Convert(
                               Expression.Call(protocolParam, Methods.IThriftProtocol_ReadInt32),
                               thriftType.TypeInfo.AsType()
                               ));
                }
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadInt32));

            case ThriftTypeId.Int64:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadInt64));

            case ThriftTypeId.Binary:
                if (thriftType.TypeInfo == TypeInfos.String)
                {
                    return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadString));
                }
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_ReadBinary));

            case ThriftTypeId.Map:
                return(CreateReaderForMap(protocolParam, thriftType));

            case ThriftTypeId.Set:
            case ThriftTypeId.List:
                if (thriftType.TypeInfo.IsArray)
                {
                    return(CreateReaderForArray(protocolParam, thriftType));
                }
                return(CreateReaderForListOrSet(protocolParam, thriftType));

            default:
                return(Expression.Call(
                           typeof(ThriftStructReader),
                           "Read",
                           new[] { thriftType.TypeInfo.AsType() },
                           protocolParam
                           ));
            }
        }
Exemple #5
0
        /// <summary>
        /// Creates an expression reading the specified list or set type.
        /// </summary>
        private static Expression CreateReaderForListOrSet(ParameterExpression protocolParam, ThriftType thriftType)
        {
            var collectionType = thriftType.TypeInfo.AsType();
            var collectionVar  = Expression.Variable(collectionType);
            var headerVar      = Expression.Variable(typeof(ThriftCollectionHeader));
            var countVar       = Expression.Variable(typeof(int));

            var endOfLoop = Expression.Label();

            return(Expression.Block(
                       collectionType,
                       new[] { collectionVar, headerVar, countVar },

                       Expression.Assign(
                           headerVar,
                           Expression.Call(
                               protocolParam,
                               thriftType.Id == ThriftTypeId.List ? Methods.IThriftProtocol_ReadListHeader : Methods.IThriftProtocol_ReadSetHeader
                               )
                           ),

                       CreateTypeIdAssert(
                           thriftType.ElementType.Id,
                           Expression.Field(headerVar, Fields.ThriftCollectionHeader_ElementTypeId)
                           ),

                       Expression.Assign(
                           collectionVar,
                           Expression.New(collectionType)
                           ),

                       Expression.Assign(
                           countVar,
                           Expression.Constant(0)
                           ),

                       Expression.Loop(
                           Expression.IfThenElse(
                               Expression.Equal(
                                   countVar,
                                   Expression.Field(headerVar, Fields.ThriftCollectionHeader_Count)
                                   ),
                               Expression.Break(endOfLoop),
                               Expression.Block(
                                   Expression.Call(
                                       collectionVar,
                                       "Add",
                                       Types.None,
                                       CreateReaderForType(protocolParam, thriftType.ElementType)
                                       ),
                                   Expression.PostIncrementAssign(countVar)
                                   )
                               ),
                           endOfLoop
                           ),

                       Expression.Call(
                           protocolParam,
                           thriftType.Id == ThriftTypeId.List ? Methods.IThriftProtocol_ReadListEnd : Methods.IThriftProtocol_ReadSetEnd
                           ),

                       // return value
                       collectionVar
                       ));
        }
Exemple #6
0
        /// <summary>
        /// Creates an expression reading the specified array type.
        /// </summary>
        private static Expression CreateReaderForArray(ParameterExpression protocolParam, ThriftType thriftType)
        {
            var arrayType = thriftType.TypeInfo.AsType();
            var itemType  = thriftType.ElementType.TypeInfo.AsType();
            var arrayVar  = Expression.Variable(arrayType);
            var headerVar = Expression.Variable(typeof(ThriftCollectionHeader));
            var lengthVar = Expression.Variable(typeof(int));

            var endOfLoop = Expression.Label();

            return(Expression.Block(
                       arrayType,
                       new[] { arrayVar, headerVar, lengthVar },

                       Expression.Assign(
                           headerVar,
                           Expression.Call(protocolParam, Methods.IThriftProtocol_ReadListHeader)
                           ),

                       CreateTypeIdAssert(
                           thriftType.ElementType.Id,
                           Expression.Field(headerVar, Fields.ThriftCollectionHeader_ElementTypeId)
                           ),

                       Expression.Assign(
                           arrayVar,
                           Expression.NewArrayBounds(
                               itemType,
                               Expression.Field(headerVar, Fields.ThriftCollectionHeader_Count)
                               )
                           ),

                       Expression.Assign(
                           lengthVar,
                           Expression.Constant(0)
                           ),

                       Expression.Loop(
                           Expression.IfThenElse(
                               Expression.Equal(
                                   lengthVar,
                                   Expression.Field(headerVar, Fields.ThriftCollectionHeader_Count)
                                   ),
                               Expression.Break(endOfLoop),
                               Expression.Block(
                                   Expression.Assign(
                                       Expression.ArrayAccess(
                                           arrayVar,
                                           lengthVar
                                           ),
                                       CreateReaderForType(protocolParam, thriftType.ElementType)
                                       ),
                                   Expression.PostIncrementAssign(lengthVar)
                                   )
                               ),
                           endOfLoop
                           ),

                       Expression.Call(protocolParam, Methods.IThriftProtocol_ReadListEnd),

                       // return value
                       arrayVar
                       ));
        }
Exemple #7
0
        /// <summary>
        /// Initializes a new instance of the ThriftType class from the specified .NET type.
        /// </summary>
        private ThriftType(Type type)
        {
            Id       = ThriftTypeId.Empty;
            TypeInfo = type.GetTypeInfo();

            if (type == typeof(void))
            {
                return;
            }

            var underlyingNullableType = Nullable.GetUnderlyingType(type);

            if (underlyingNullableType != null)
            {
                NullableType = ThriftType.Get(underlyingNullableType);
                Id           = NullableType.Id;
                IsEnum       = NullableType.IsEnum;
                return;
            }

            if (PrimitiveIds.ContainsKey(type))
            {
                Id = PrimitiveIds[type];
                return;
            }

            if (TypeInfo.IsEnum)
            {
                if (TypeInfo.GetCustomAttribute <ThriftEnumAttribute>() == null)
                {
                    throw ThriftParsingException.EnumWithoutAttribute(TypeInfo);
                }
                if (Enum.GetUnderlyingType(type) != typeof(int))
                {
                    throw ThriftParsingException.NonInt32Enum(TypeInfo);
                }

                Id     = ThriftTypeId.Int32;
                IsEnum = true;
                return;
            }

            if (TypeInfo.IsValueType)
            {
                throw ThriftParsingException.UnknownValueType(TypeInfo);
            }

            if (TypeInfo.IsArray)
            {
                Id = ThriftTypeId.List;
                return;
            }

            var mapInterfaceAndArgs = GetInstantiableVersion(TypeInfo, typeof(IDictionary <,>), typeof(Dictionary <,>), p => ThriftParsingException.UnsupportedMap(p));

            if (mapInterfaceAndArgs != null)
            {
                Id       = ThriftTypeId.Map;
                TypeInfo = mapInterfaceAndArgs.Item1;
                _collectionGenericArgs = mapInterfaceAndArgs.Item2;
            }

            var setInterfaceAndArgs = GetInstantiableVersion(TypeInfo, typeof(ISet <>), typeof(HashSet <>), p => ThriftParsingException.UnsupportedSet(p));

            if (setInterfaceAndArgs != null)
            {
                if (mapInterfaceAndArgs != null)
                {
                    throw ThriftParsingException.CollectionWithOrthogonalInterfaces(TypeInfo);
                }

                Id       = ThriftTypeId.Set;
                TypeInfo = setInterfaceAndArgs.Item1;
                _collectionGenericArgs = setInterfaceAndArgs.Item2;
            }

            var listInterfaceAndArgs = GetInstantiableVersion(TypeInfo, typeof(IList <>), typeof(List <>), p => ThriftParsingException.UnsupportedList(p));

            if (listInterfaceAndArgs != null)
            {
                if (mapInterfaceAndArgs != null || setInterfaceAndArgs != null)
                {
                    throw ThriftParsingException.CollectionWithOrthogonalInterfaces(TypeInfo);
                }

                Id       = ThriftTypeId.List;
                TypeInfo = listInterfaceAndArgs.Item1;
                _collectionGenericArgs = listInterfaceAndArgs.Item2;
            }

            if (Id == ThriftTypeId.Empty)
            {
                Id = ThriftTypeId.Struct;
            }
        }
Exemple #8
0
 /// <summary>
 /// Initializes a new instance of the ThriftConvertibleValue class with the specified underlying type and converter.
 /// </summary>
 protected ThriftConvertibleValue(TypeInfo typeInfo, ThriftConverter converter)
 {
     WireType  = ThriftType.Get(converter?.FromType ?? typeInfo.AsType());
     Converter = converter;
 }
Exemple #9
0
        /// <summary>
        /// Creates an expression writing the specified array type.
        /// </summary>
        private static Expression CreateWriterForArray(ParameterExpression protocolParam, ThriftType thriftType, Expression value)
        {
            var counterVar = Expression.Variable(typeof(int));

            var endOfLoop = Expression.Label();

            return(Expression.Block(
                       new[] { counterVar },

                       Expression.Call(
                           protocolParam,
                           Methods.IThriftProtocol_WriteListHeader,
                           Expression.New(
                               Constructors.ThriftCollectionHeader,
                               Expression.Property(value, "Length"),
                               Expression.Constant(thriftType.ElementType.Id)
                               )
                           ),

                       Expression.Assign(
                           counterVar,
                           Expression.Constant(0)
                           ),

                       Expression.Loop(
                           Expression.IfThenElse(
                               Expression.LessThan(
                                   counterVar,
                                   Expression.Property(value, "Length")
                                   ),
                               Expression.Block(
                                   CreateWriterForType(
                                       protocolParam, thriftType.ElementType,
                                       Expression.ArrayAccess(value, counterVar)
                                       ),
                                   Expression.PostIncrementAssign(counterVar)
                                   ),
                               Expression.Break(endOfLoop)
                               ),
                           endOfLoop
                           ),

                       Expression.Call(
                           protocolParam,
                           Methods.IThriftProtocol_WriteListEnd
                           )
                       ));
        }
Exemple #10
0
        /// <summary>
        /// Creates an expression writing the specified map type.
        /// </summary>
        private static Expression CreateWriterForMap(ParameterExpression protocolParam, ThriftType thriftType, Expression value)
        {
            // This code does not use IEnumerable.GetEnumerator, in order to use the "better" enumerator on collections
            // that implement their own, e.g. List<T> has a struct-returning GetEnumerator(), and a ref-returning IEnumerable<T>.GetEnumerator()
            var getEnumeratorMethod = thriftType.TypeInfo.AsType().GetRuntimeMethod("GetEnumerator", Types.None);

            var endOfLoop     = Expression.Label();
            var enumeratorVar = Expression.Variable(getEnumeratorMethod.ReturnType);

            return(Expression.Block(
                       new[] { enumeratorVar },

                       Expression.Call(
                           protocolParam,
                           Methods.IThriftProtocol_WriteMapHeader,
                           Expression.New(
                               Constructors.ThriftMapHeader,
                               Expression.Property(value, "Count"),
                               Expression.Constant(thriftType.KeyType.Id),
                               Expression.Constant(thriftType.ValueType.Id)
                               )
                           ),

                       Expression.Assign(
                           enumeratorVar,
                           Expression.Call(value, getEnumeratorMethod)
                           ),

                       Expression.Loop(
                           Expression.IfThenElse(
                               // Do not use IsTrue, not supported by UWP's expression interpreter
                               Expression.Equal(
                                   Expression.Call(enumeratorVar, "MoveNext", Types.None),
                                   Expression.Constant(true)
                                   ),
                               Expression.Block(
                                   CreateWriterForType(
                                       protocolParam, thriftType.KeyType,
                                       Expression.Property(
                                           Expression.Property(enumeratorVar, "Current"),
                                           "Key"
                                           )
                                       ),
                                   CreateWriterForType(
                                       protocolParam, thriftType.ValueType,
                                       Expression.Property(
                                           Expression.Property(enumeratorVar, "Current"),
                                           "Value"
                                           )
                                       )
                                   ),
                               Expression.Break(endOfLoop)
                               ),
                           endOfLoop
                           ),

                       Expression.Call(protocolParam, Methods.IThriftProtocol_WriteMapEnd)
                       ));
        }
Exemple #11
0
        /// <summary>
        /// Creates an expression writing the specified type.
        /// </summary>
        private static Expression CreateWriterForType(ParameterExpression protocolParam, ThriftType thriftType, Expression value)
        {
            switch (thriftType.Id)
            {
            case ThriftTypeId.Boolean:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteBoolean, value));

            case ThriftTypeId.SByte:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteSByte, value));

            case ThriftTypeId.Double:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteDouble, value));

            case ThriftTypeId.Int16:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteInt16, value));

            case ThriftTypeId.Int32:
                if (thriftType.IsEnum)
                {
                    value = Expression.Convert(value, typeof(int));
                }
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteInt32, value));

            case ThriftTypeId.Int64:
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteInt64, value));

            case ThriftTypeId.Binary:
                if (thriftType.TypeInfo == TypeInfos.String)
                {
                    return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteString, value));
                }
                return(Expression.Call(protocolParam, Methods.IThriftProtocol_WriteBinary, value));

            case ThriftTypeId.Map:
                return(CreateWriterForMap(protocolParam, thriftType, value));

            case ThriftTypeId.Set:
            case ThriftTypeId.List:
                if (thriftType.TypeInfo.IsArray)
                {
                    return(CreateWriterForArray(protocolParam, thriftType, value));
                }
                return(CreateWriterForListOrSet(protocolParam, thriftType, value));

            default:
                return(Expression.Call(
                           typeof(ThriftStructWriter),
                           "Write",
                           new[] { value.Type },
                           value, protocolParam
                           ));
            }
        }
Exemple #12
0
        /// <summary>
        /// Creates an expression writing the specified list or set type.
        /// </summary>
        private static Expression CreateWriterForListOrSet(ParameterExpression protocolParam, ThriftType thriftType, Expression value)
        {
            // same remark as in CreateWriterForMap
            var getEnumeratorMethod = thriftType.TypeInfo.AsType().GetRuntimeMethod("GetEnumerator", Types.None);

            var enumeratorVar = Expression.Variable(getEnumeratorMethod.ReturnType);

            var endOfLoop = Expression.Label();

            return(Expression.Block(
                       new[] { enumeratorVar },

                       Expression.Call(
                           protocolParam,
                           thriftType.Id == ThriftTypeId.List ? Methods.IThriftProtocol_WriteListHeader : Methods.IThriftProtocol_WriteSetHeader,
                           Expression.New(
                               Constructors.ThriftCollectionHeader,
                               Expression.Property(value, "Count"),
                               Expression.Constant(thriftType.ElementType.Id)
                               )
                           ),

                       Expression.Assign(
                           enumeratorVar,
                           Expression.Call(value, getEnumeratorMethod)
                           ),

                       Expression.Loop(
                           Expression.IfThenElse(
                               // Do not use IsTrue, not supported by UWP's expression interpreter
                               Expression.Equal(
                                   Expression.Call(enumeratorVar, "MoveNext", Types.None),
                                   Expression.Constant(true)
                                   ),
                               CreateWriterForType(
                                   protocolParam, thriftType.ElementType,
                                   Expression.Property(enumeratorVar, "Current")
                                   ),
                               Expression.Break(endOfLoop)
                               ),
                           endOfLoop
                           ),

                       Expression.Call(
                           protocolParam,
                           thriftType.Id == ThriftTypeId.List ? Methods.IThriftProtocol_WriteListEnd : Methods.IThriftProtocol_WriteSetEnd
                           )
                       ));
        }