public ArrayDecorator(TypeModel model, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, Type arrayType, bool overwriteList, bool supportNull) : base(tail) { Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); Helpers.DebugAssert(arrayType.IsArray && arrayType.GetArrayRank() == 1, "should be single-dimension array; " + arrayType.FullName); this.itemType = arrayType.GetElementType(); #if NO_GENERICS Type underlyingItemType = itemType; #else Type underlyingItemType = supportNull ? itemType : (Helpers.GetUnderlyingType(itemType) ?? itemType); #endif Helpers.DebugAssert(underlyingItemType == Tail.ExpectedType, "invalid tail"); Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer"); if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber"); if (!ListDecorator.CanPack(packedWireType)) { if (writePacked) throw new InvalidOperationException("Only simple data-types can use packed encoding"); packedWireType = WireType.None; } this.fieldNumber = fieldNumber; this.packedWireType = packedWireType; if (writePacked) options |= OPTIONS_WritePacked; if (overwriteList) options |= OPTIONS_OverwriteList; if (supportNull) options |= OPTIONS_SupportNull; this.arrayType = arrayType; }
public ArrayDecorator(TypeModel model, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, Type arrayType, bool overwriteList, bool supportNull) : base(tail) { Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); Helpers.DebugAssert(arrayType.IsArray && arrayType.GetArrayRank() == 1, "should be single-dimension array; " + arrayType.FullName); this.itemType = arrayType.GetElementType(); #if NO_GENERICS Type underlyingItemType = itemType; #else Type underlyingItemType = supportNull ? itemType : (Helpers.GetUnderlyingType(itemType) ?? itemType); #endif Helpers.DebugAssert(underlyingItemType == Tail.ExpectedType, "invalid tail"); Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer"); if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) { throw new ArgumentOutOfRangeException("fieldNumber"); } if (!ListDecorator.CanPack(packedWireType)) { if (writePacked) { throw new InvalidOperationException("Only simple data-types can use packed encoding"); } packedWireType = WireType.None; } this.fieldNumber = fieldNumber; this.packedWireType = packedWireType; if (writePacked) { options |= OPTIONS_WritePacked; } if (overwriteList) { options |= OPTIONS_OverwriteList; } if (supportNull) { options |= OPTIONS_SupportNull; } this.arrayType = arrayType; }
public MultiDimensionalArrayDecorator(TypeModel model, IProtoSerializerWithWireType tail, Type arrayType, bool overwriteList, int readLengthLimit) : base(tail) { Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); _rank = arrayType.GetArrayRank(); if (_rank <= 1) { throw new ArgumentException("should be multi-dimension array; " + arrayType.FullName, nameof(arrayType)); } _itemType = tail.ExpectedType; if (_itemType != arrayType.GetElementType()) { throw new ArgumentException("Expected array type is " + arrayType.GetElementType() + " but tail type is " + _itemType); } _arrayType = arrayType; _overwriteList = overwriteList; _readLengthLimit = readLengthLimit; _listHelpers = new ListHelpers(false, WireType.None, false, tail, true); }
public ArrayDecorator(TypeModel model, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireTypeForRead, Type arrayType, bool overwriteList, int readLengthLimit, bool protoCompatibility) : base(tail) { Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); if (!arrayType.IsArray || arrayType.GetArrayRank() != 1) { throw new ArgumentException("should be single-dimension array; " + arrayType.FullName, nameof(arrayType)); } _itemType = tail.ExpectedType; if (_itemType != arrayType.GetElementType()) { throw new ArgumentException("Expected array type is " + arrayType.GetElementType() + " but tail type is " + _itemType); } Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer"); _writePacked = writePacked; _arrayType = arrayType; _overwriteList = overwriteList; _protoCompatibility = protoCompatibility; _readLengthLimit = readLengthLimit; _listHelpers = new ListHelpers(_writePacked, packedWireTypeForRead, _protoCompatibility, tail, false); }
TypeSpec ImportType (MetaType type, DynamicTypeReader dtype) { if (type.HasElementType) { var element = type.GetElementType (); ++dtype.Position; var spec = ImportType (element, dtype); if (type.IsArray) return ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); if (type.IsByRef) return ReferenceContainer.MakeType (module, spec); if (type.IsPointer) return PointerContainer.MakeType (module, spec); throw new NotImplementedException ("Unknown element type " + type.ToString ()); } return CreateType (type, dtype, true); }
TypeSpec ImportType (MetaType type, DynamicTypeReader dtype) { if (type.HasElementType) { var element = type.GetElementType (); ++dtype.Position; var spec = ImportType (element, dtype); if (type.IsArray) return ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); if (type.IsByRef) return ReferenceContainer.MakeType (module, spec); if (type.IsPointer) return PointerContainer.MakeType (module, spec); throw new NotImplementedException ("Unknown element type " + type.ToString ()); } TypeSpec compiled_type; if (compiled_types.TryGetValue (type, out compiled_type)) { if (compiled_type.BuiltinType == BuiltinTypeSpec.Type.Object && dtype.IsDynamicObject ()) return module.Compiler.BuiltinTypes.Dynamic; return compiled_type; } return CreateType (type, dtype, true); }
internal void ResolveListTypes(Type type, ref Type itemType, ref Type defaultType) { if (type == null) return; if(Helpers.GetTypeCode(type) != ProtoTypeCode.Unknown) return; // don't try this[type] for inbuilts if(this[type].IgnoreListHandling) return; // handle arrays if (type.IsArray) { if (type.GetArrayRank() != 1) { throw new NotSupportedException("Multi-dimension arrays are supported"); } itemType = type.GetElementType(); if (itemType == MapType(typeof(byte))) { defaultType = itemType = null; } else { defaultType = type; } } // handle lists if (itemType == null) { itemType = TypeModel.GetListItemType(this, type); } // check for nested data (not allowed) if (itemType != null) { Type nestedItemType = null, nestedDefaultType = null; ResolveListTypes(itemType, ref nestedItemType, ref nestedDefaultType); if (nestedItemType != null) { throw TypeModel.CreateNestedListsNotSupported(); } } if (itemType != null && defaultType == null) { #if WINRT System.Reflection.TypeInfo typeInfo = System.Reflection.IntrospectionExtensions.GetTypeInfo(type); if (typeInfo.IsClass && !typeInfo.IsAbstract && Helpers.GetConstructor(typeInfo, Helpers.EmptyTypes, true) != null) #else if (type.IsClass && !type.IsAbstract && Helpers.GetConstructor(type, Helpers.EmptyTypes, true) != null) #endif { defaultType = type; } if (defaultType == null) { #if WINRT if (typeInfo.IsInterface) #else if (type.IsInterface) #endif { #if NO_GENERICS defaultType = typeof(ArrayList); #else Type[] genArgs; #if WINRT if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>) && itemType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(genArgs = typeInfo.GenericTypeArguments)) #else if (type.IsGenericType && type.GetGenericTypeDefinition() == MapType(typeof(System.Collections.Generic.IDictionary<,>)) && itemType == MapType(typeof(System.Collections.Generic.KeyValuePair<,>)).MakeGenericType(genArgs = type.GetGenericArguments())) #endif { defaultType = MapType(typeof(System.Collections.Generic.Dictionary<,>)).MakeGenericType(genArgs); } else { defaultType = MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType); } #endif } } // verify that the default type is appropriate if (defaultType != null && !Helpers.IsAssignableFrom(type, defaultType)) { defaultType = null; } } }
// the sections mentioned in comments of this method are from C# specification v1.2 public static Conversion GetImplicit(Operand op, Type to, bool onlyStandard, ITypeMapper typeMapper) { Type from = Operand.GetType(op, typeMapper); Type toUnderlying = Helpers.GetNullableUnderlyingType(to); if (to.Equals(from)) { return(new Direct(typeMapper)); } Type fromUnderlying = Helpers.GetNullableUnderlyingType(@from); if (toUnderlying != null) { if (fromUnderlying != null) { Conversion c = GetImplicit(new FakeTypedOperand(fromUnderlying), toUnderlying, onlyStandard, typeMapper); if (c.IsValid) { return(new ConvertNullable(typeMapper, c)); } } else { Conversion c = GetImplicit(op, toUnderlying, onlyStandard, typeMapper); if (c.IsValid) { return(new WrapNullable(typeMapper, c)); } } } // required for arrays created from TypeBuilder-s if (from != null && to.IsArray && from.IsArray) { if (to.GetArrayRank() == from.GetArrayRank()) { if (to.GetElementType().Equals(from.GetElementType())) { return(new Direct(typeMapper)); } } } TypeCode tcFrom = Type.GetTypeCode(from); TypeCode tcTo = Type.GetTypeCode(to); byte ct = _convTable[(int)tcFrom][(int)tcTo]; // section 6.1.2 - Implicit numeric conversions if (from != null && (from.IsPrimitive || Helpers.AreTypesEqual(from, typeof(decimal), typeMapper)) && (to.IsPrimitive || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper))) { if (ct <= I) { if (Helpers.AreTypesEqual(from, typeof(decimal), typeMapper) || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper)) { // decimal is handled as user-defined conversion, but as it is a standard one, always enable UDC processing onlyStandard = false; } else { return(new Primitive(typeMapper)); } } } IntLiteral intLit = op as IntLiteral; // section 6.1.3 - Implicit enumeration conversions if (!onlyStandard && to.IsEnum && (object)intLit != null && intLit.Value == 0) { return(new Primitive(typeMapper)); } // section 6.1.4 - Implicit reference conversions if ((from == null || !from.IsValueType) && !to.IsValueType) { if (from == null) // from the null type to any reference type { return(new Direct(typeMapper)); } if (to.IsAssignableFrom(from)) // the rest { return(new Direct(typeMapper)); } } if (from == null) // no other conversion from null type is possible { return(new Invalid(typeMapper)); } // section 6.1.5 - Boxing conversions if (from.IsValueType) { if (to.IsAssignableFrom(from)) { return(new Boxing(typeMapper)); } } // section 6.1.6 - Implicit constant expression conversions if ((object)intLit != null && Helpers.AreTypesEqual(from, typeof(int), typeMapper) && to.IsPrimitive) { int val = intLit.Value; switch (tcTo) { case TypeCode.SByte: if (val >= sbyte.MinValue && val <= sbyte.MaxValue) { return(new Direct(typeMapper)); } break; case TypeCode.Byte: if (val >= byte.MinValue && val <= byte.MaxValue) { return(new Direct(typeMapper)); } break; case TypeCode.Int16: if (val >= short.MinValue && val <= short.MaxValue) { return(new Direct(typeMapper)); } break; case TypeCode.UInt16: if (val >= ushort.MinValue && val <= ushort.MaxValue) { return(new Direct(typeMapper)); } break; case TypeCode.UInt32: if (val >= 0) { return(new Direct(typeMapper)); } break; case TypeCode.UInt64: if (val >= 0) { return(new Direct(typeMapper)); } break; } } // section 6.1.7 - User-defined implicit conversions (details in section 6.4.3) if (onlyStandard || Helpers.AreTypesEqual(from, typeof(object), typeMapper) || Helpers.AreTypesEqual(to, typeof(object), typeMapper) || from.IsInterface || to.IsInterface || to.IsSubclassOf(from) || from.IsSubclassOf(to)) { return(new Invalid(typeMapper)); // skip not-permitted conversion attempts (section 6.4.1) } List <UserDefined> candidates = null; FindCandidates(ref candidates, FindImplicitMethods(from, to, typeMapper), op, to, GetImplicit, typeMapper); if (candidates == null) { return(new Invalid(typeMapper)); } if (candidates.Count == 1) { return(candidates[0]); } return(UserDefined.FindImplicit(candidates, @from, to, typeMapper)); }
// the sections mentioned in comments of this method are from C# specification v1.2 public static Conversion GetImplicit(Operand op, Type to, bool onlyStandard, ITypeMapper typeMapper) { Type from = Operand.GetType(op, typeMapper); Type toUnderlying = Helpers.GetNullableUnderlyingType(to); if (to.Equals(from)) return new Direct(typeMapper); Type fromUnderlying = Helpers.GetNullableUnderlyingType(@from); if (toUnderlying != null) { if (fromUnderlying != null) { Conversion c = GetImplicit(new FakeTypedOperand(fromUnderlying), toUnderlying, onlyStandard, typeMapper); if (c.IsValid) return new ConvertNullable(typeMapper, c); } else { Conversion c = GetImplicit(op, toUnderlying, onlyStandard, typeMapper); if (c.IsValid) return new WrapNullable(typeMapper, c); } } // required for arrays created from TypeBuilder-s if (from != null && to.IsArray && from.IsArray) { if (to.GetArrayRank() == from.GetArrayRank()) { if (to.GetElementType().Equals(from.GetElementType())) return new Direct(typeMapper); } } TypeCode tcFrom = Type.GetTypeCode(from); TypeCode tcTo = Type.GetTypeCode(to); byte ct = _convTable[(int)tcFrom][(int)tcTo]; // section 6.1.2 - Implicit numeric conversions if (from != null && (from.IsPrimitive || Helpers.AreTypesEqual(from, typeof(decimal), typeMapper)) && (to.IsPrimitive || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper))) { if (ct <= I) { if (Helpers.AreTypesEqual(from, typeof(decimal), typeMapper) || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper)) // decimal is handled as user-defined conversion, but as it is a standard one, always enable UDC processing onlyStandard = false; else return new Primitive(typeMapper); } } IntLiteral intLit = op as IntLiteral; // section 6.1.3 - Implicit enumeration conversions if (!onlyStandard && to.IsEnum && (object)intLit != null && intLit.Value == 0) return new Primitive(typeMapper); // section 6.1.4 - Implicit reference conversions if ((from == null || !from.IsValueType) && !to.IsValueType) { if (from == null) // from the null type to any reference type return new Direct(typeMapper); if (to.IsAssignableFrom(from)) // the rest return new Direct(typeMapper); } if (from == null) // no other conversion from null type is possible return new Invalid(typeMapper); // section 6.1.5 - Boxing conversions if (from.IsValueType) { if (to.IsAssignableFrom(from)) return new Boxing(typeMapper); } // section 6.1.6 - Implicit constant expression conversions if ((object)intLit != null && Helpers.AreTypesEqual(from, typeof(int), typeMapper) && to.IsPrimitive) { int val = intLit.Value; switch (tcTo) { case TypeCode.SByte: if (val >= sbyte.MinValue && val <= sbyte.MaxValue) return new Direct(typeMapper); break; case TypeCode.Byte: if (val >= byte.MinValue && val <= byte.MaxValue) return new Direct(typeMapper); break; case TypeCode.Int16: if (val >= short.MinValue && val <= short.MaxValue) return new Direct(typeMapper); break; case TypeCode.UInt16: if (val >= ushort.MinValue && val <= ushort.MaxValue) return new Direct(typeMapper); break; case TypeCode.UInt32: if (val >= 0) return new Direct(typeMapper); break; case TypeCode.UInt64: if (val >= 0) return new Direct(typeMapper); break; } } // section 6.1.7 - User-defined implicit conversions (details in section 6.4.3) if (onlyStandard || Helpers.AreTypesEqual(from, typeof(object), typeMapper) || Helpers.AreTypesEqual(to, typeof(object), typeMapper) || from.IsInterface || to.IsInterface || to.IsSubclassOf(from) || from.IsSubclassOf(to)) return new Invalid(typeMapper); // skip not-permitted conversion attempts (section 6.4.1) List<UserDefined> candidates = null; FindCandidates(ref candidates, FindImplicitMethods(from, to, typeMapper), op, to, GetImplicit, typeMapper); if (candidates == null) return new Invalid(typeMapper); if (candidates.Count == 1) return candidates[0]; return UserDefined.FindImplicit(candidates, @from, to, typeMapper); }