Example #1
0
        public bool GetMoreSpecificSerializer(object value, out IProtoSerializerWithWireType serializer, out int fieldNumber)
        {
            fieldNumber = 0;
            serializer  = null;
            if (!CanHaveInheritance)
            {
                return(false);
            }
            Type actualType = value.GetType();

            if (actualType == ExpectedType)
            {
                return(false);
            }

            for (int i = 0; i < _serializers.Length; i++)
            {
                IProtoSerializerWithWireType ser = _serializers[i];
                if (ser.ExpectedType != ExpectedType && Helpers.IsAssignableFrom(ser.ExpectedType, actualType))
                {
                    serializer  = ser;
                    fieldNumber = _fieldNumbers[i];
                    return(true);
                }
            }
            if (actualType == _constructType)
            {
                return(false);                                          // needs to be last in case the default concrete type is also a known sub-type
            }
            TypeModel.ThrowUnexpectedSubtype(ExpectedType, actualType); // might throw (if not a proxy)
            return(false);
        }
Example #2
0
        internal static ListDecorator Create(
            RuntimeTypeModel model, Type declaredType, Type concreteTypeDefault, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireType,
            bool overwriteList, bool protoCompatibility, bool writeSubType)
        {
#if !NO_GENERICS
            MethodInfo builderFactory, add, addRange, finish;
            if (ImmutableCollectionDecorator.IdentifyImmutable(model, declaredType, out builderFactory, out add, out addRange, out finish))
            {
                return(new ImmutableCollectionDecorator(
                           model,
                           declaredType,
                           concreteTypeDefault,
                           tail,
                           writePacked,
                           packedWireType,
                           overwriteList,
                           builderFactory,
                           add,
                           addRange,
                           finish,
                           protoCompatibility));
            }
#endif
            return(new ListDecorator(model, declaredType, concreteTypeDefault, tail, writePacked, packedWireType, overwriteList, protoCompatibility, writeSubType));
        }
Example #3
0
        public UriDecorator(AqlaSerializer.Meta.TypeModel model, IProtoSerializerWithWireType tail)
            : base(tail)
        {
            _tail = tail;
#if FEAT_IKVM
            expectedType = model.MapType(typeof(Uri));
#endif
        }
Example #4
0
 public NetObjectValueDecorator(Type type, int baseKey, bool asReference, bool asLateReference, ISerializerProxy concreteSerializerProxy, bool allowNullWireType, RuntimeTypeModel model)
     : this(type : type, asReference : asReference, asLateReference : asLateReference, allowNullWireType : allowNullWireType, model : model)
 {
     if (baseKey < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(baseKey));
     }
     _baseKey           = baseKey;
     _baseKeySerializer = new ModelTypeSerializer(Helpers.GetNullableUnderlyingType(type) ?? type, baseKey, concreteSerializerProxy, model);
 }
        public ReflectedUriDecorator(Type type, Meta.TypeModel model, IProtoSerializerWithWireType tail) : base(tail)
        {
            expectedType = type;
            _tail        = tail;
#if WINRT
            absoluteUriProperty = expectedType.GetTypeInfo().GetDeclaredProperty("AbsoluteUri");
            typeConstructor     = expectedType.GetTypeInfo().DeclaredConstructors.First(c => c.GetParameters().Length == 1 && c.GetParameters()[0].ParameterType == typeof(string));
#else
            absoluteUriProperty = expectedType.GetProperty("AbsoluteUri");
            typeConstructor     = expectedType.GetConstructor(new Type[] { typeof(string) });
#endif
        }
Example #6
0
        public FieldDecorator(Type forType, FieldInfo field, IProtoSerializerWithWireType tail)
            : base(tail)
        {
            Helpers.DebugAssert(forType != null);
            Helpers.DebugAssert(field != null);
            this._forType = forType;
            this._field   = field;
            _tail         = tail;
#if FEAT_COMPILER && !FEAT_IKVM
            _accessors = AccessorsCache.GetAccessors(field);
#endif
        }
Example #7
0
        void EmitReadTail(SerializerCodeGen g, CompilerContext ctx, IProtoSerializerWithWireType ser, Local value, Local outValueBoxed)
        {
            // inputValue may be nullable
            using (ctx.StartDebugBlockAuto(this))
            {
                ser.EmitRead(ctx, ser.RequiresOldValue ? value : null);
                if (ser.EmitReadReturnsValue)
                {
                    g.Assign(value, g.GetStackValueOperand(ser.ExpectedType));
                }

                g.Assign(outValueBoxed, value);
            }
        }
Example #8
0
        public PropertyDecorator(TypeModel model, Type forType, PropertyInfo property, IProtoSerializerWithWireType tail)
            : base(tail)
        {
            Helpers.DebugAssert(forType != null);
            Helpers.DebugAssert(property != null);
            this._forType  = forType;
            this._property = property;
            _tail          = tail;
            SanityCheck(model, property, tail, out _canSetInRuntime, true, true, false);
            _shadowSetter = Helpers.GetShadowSetter(model, property);
#if FEAT_COMPILER && !FEAT_IKVM
            _accessors = AccessorsCache.GetAccessors(property);
            if (_shadowSetter != null)
            {
                _accessors.Set = AccessorsCache.GetShadowSetter(_shadowSetter);
            }
#endif
        }
 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);
 }
Example #10
0
        public NoNullDecorator(TypeModel model, IProtoSerializerWithWireType tail, bool throwIfNull)
            : base(tail)
        {
            _throwIfNull = throwIfNull;
            Type tailType = tail.ExpectedType;

            if (Helpers.IsValueType(tailType))
            {
#if NO_GENERICS
                throw new NotSupportedException("NullDecorator cannot be used with a struct without generics support");
#else
                _expectedType = model.MapType(typeof(Nullable <>)).MakeGenericType(tailType);
#endif
            }
            else
            {
                _expectedType = tailType;
            }
        }
Example #11
0
        public ListHelpers(bool writePacked, WireType packedWireTypeForRead, bool protoCompatibility, IProtoSerializerWithWireType tail, bool skipIList)
        {
            if (protoCompatibility)
            {
                if (ListDecorator.CanPack(packedWireTypeForRead))
                {
                    _packedWireTypeForRead = packedWireTypeForRead;
                }
                else if (writePacked)
                {
                    throw new ArgumentException("For writePacked wire type for read should be specified");
                }

                _writePacked = writePacked;
            }
            _tail               = tail;
            _skipIList          = skipIList;
            _itemType           = tail.ExpectedType;
            _protoCompatibility = protoCompatibility;
        }
Example #12
0
 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);
 }
Example #13
0
 public void WriteDebugSchema(IDebugSchemaBuilder builder)
 {
     using (builder.GroupSerializer(this))
     {
         for (int i = 0; i < _serializers.Length; i++)
         {
             IProtoSerializerWithWireType ser = _serializers[i];
             if (ser.ExpectedType != ExpectedType)
             {
                 using (builder.Field(_fieldNumbers[i], "SubType"))
                     ser.WriteDebugSchema(builder);
             }
         }
         for (int i = 0; i < _serializers.Length; i++)
         {
             IProtoSerializerWithWireType ser = _serializers[i];
             if (ser.ExpectedType == ExpectedType)
             {
                 using (builder.Field(_fieldNumbers[i]))
                     ser.WriteDebugSchema(builder);
             }
         }
     }
 }
Example #14
0
        public DefaultValueDecorator(TypeModel model, object defaultValue, IProtoSerializerWithWireType tail) : base(tail)
        {
            if (defaultValue == null)
            {
                throw new ArgumentNullException(nameof(defaultValue));
            }
            Type type = model.MapType(defaultValue.GetType());
            // if the value is nullable we should check equality with nullable before writing
            var underlying = Helpers.GetNullableUnderlyingType(tail.ExpectedType);

            if (underlying != null)
            {
                type = model.MapType(typeof(Nullable <>)).MakeGenericType(type);
            }
            if (type != tail.ExpectedType
#if FEAT_IKVM // in IKVM, we'll have the default value as an underlying type
                && !(tail.ExpectedType.IsEnum && type == tail.ExpectedType.GetEnumUnderlyingType())
#endif
                )
            {
                throw new ArgumentException(string.Format("Default value is of incorrect type (expected {0}, actaul {1})", tail.ExpectedType, type), nameof(defaultValue));
            }
            this._defaultValue = defaultValue;
        }
Example #15
0
        private IProtoTypeSerializer BuildSerializer(bool isRoot)
        {
            // reference tracking decorators (RootDecorator, NetObjectDecorator, NetObjectValueDecorator)
            // should always be applied only one time (otherwise will consider new objects as already written):
            // #1 For collection types references are handled either by RootDecorator or
            // by ValueMember which owns the value (so outside of this scope)
            // because the value is treated as single object
            // #2 For members: ordinal ValueMembers are used and they will handle references when appropriate

            if (Helpers.IsEnum(Type))
            {
                Debug.Assert(IsSimpleValue);
                IProtoTypeSerializer ser = new WireTypeDecorator(WireType.Variant, new EnumSerializer(Type, GetEnumMap()));
                if (isRoot && !GetRootStartsGroup())
                {
                    ser = new RootFieldNumberDecorator(ser, ListHelpers.FieldItem);
                }
                return(ser);
            }

            Type itemType = _settingsValueFinal.Member.Collection.ItemType;

            if (itemType != null)
            {
                if (_surrogate != null)
                {
                    throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot use a surrogate");
                }

                Type defaultType = null;
                ResolveListTypes(_model, Type, ref itemType, ref defaultType);

                if (_fields.Count != 0)
                {
                    throw new ArgumentException("Repeated data (an array, list, etc) has inbuilt behavior and can't have fields");
                }

                // apply default member settings to type settings too
                var s = _settingsValueFinal.Member;
                // but change this:
                s.EffectiveType           = Type;  // not merged with anything so assign
                s.Collection.ConcreteType = _settingsValueFinal.ConstructType ?? defaultType;
                s.Collection.Append       = false; // allowed only on members
                s.WriteAsDynamicType      = false; // allowed only on members
                // this should be handled as collection
                if (s.Collection.ItemType == null)
                {
                    s.Collection.ItemType = itemType;
                }

                var vs = _rootNestedVs.Clone();
                vs.SetSettings(s, 0);
                vs.DefaultLevel = new ValueSerializationSettings.LevelValue(s.MakeDefaultNestedLevel());

                WireType wt;
                var      ser = (IProtoTypeSerializer)_model.ValueSerializerBuilder.BuildValueFinalSerializer(vs, false, out wt);

                // standard root decorator won't start any field
                // in compatibility mode collections won't start subitems like normally
                // so wrap with field
                if (isRoot && !GetRootStartsGroup())
                {
                    ser = new RootFieldNumberDecorator(ser, TypeModel.EnumRootTag);
                }

                return(ser);
            }

            if (BaseType != null && !BaseType.GetFinalSettingsCopy().IgnoreListHandling&& RuntimeTypeModel.CheckTypeIsCollection(_model, BaseType.Type))
            {
                throw new ArgumentException("A subclass of a repeated data (an array, list, etc should be handled too as a collection");
            }

            // #2

            if (_surrogate != null)
            {
                MetaType mt = _model[_surrogate], mtBase;
                while ((mtBase = mt.BaseType) != null)
                {
                    mt = mtBase;
                }
                return(new SurrogateSerializer(_model, Type, _surrogate, mt.Serializer));
            }
            if (_settingsValueFinal.IsAutoTuple)
            {
                if (_tupleCtor == null)
                {
                    throw new InvalidOperationException("Can't find tuple constructor");
                }
                return(new TupleSerializer(_model, _tupleCtor, _tupleFields.ToArray(), _settingsValueFinal.PrefixLength.GetValueOrDefault(true)));
            }


            var fields = new BasicList(_fields.Cast <object>());

            fields.Trim();

            int fieldCount   = fields.Count;
            int subTypeCount = _subTypes?.Count ?? 0;

            int[] fieldNumbers = new int[fieldCount + subTypeCount];
            IProtoSerializerWithWireType[] serializers = new IProtoSerializerWithWireType[fieldCount + subTypeCount];
            int i = 0;

            if (subTypeCount != 0)
            {
                Debug.Assert(_subTypes != null, "_subTypes != null");
                foreach (SubType subType in _subTypes)
                {
#if WINRT
                    if (!subType.DerivedType.IgnoreListHandling && ienumerable.IsAssignableFrom(subType.DerivedType.Type.GetTypeInfo()))
#else
                    if (!subType.DerivedType.IgnoreListHandling && _model.MapType(ienumerable).IsAssignableFrom(subType.DerivedType.Type))
#endif
                    {
                        throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a subclass");
                    }
                    fieldNumbers[i]  = subType.FieldNumber;
                    serializers[i++] = subType.GetSerializer(_model);
                }
            }
            if (fieldCount != 0)
            {
                foreach (ValueMember member in fields)
                {
                    fieldNumbers[i]  = member.FieldNumber;
                    serializers[i++] = member.Serializer;
                }
            }

            BasicList baseCtorCallbacks = null;
            MetaType  tmp = BaseType;

            while (tmp != null)
            {
                MethodInfo method = tmp.HasCallbacks ? tmp.Callbacks.BeforeDeserialize : null;
                if (method != null)
                {
                    if (baseCtorCallbacks == null)
                    {
                        baseCtorCallbacks = new BasicList();
                    }
                    baseCtorCallbacks.Add(method);
                }
                tmp = tmp.BaseType;
            }
            MethodInfo[] arr = null;
            if (baseCtorCallbacks != null)
            {
                arr = new MethodInfo[baseCtorCallbacks.Count];
                baseCtorCallbacks.CopyTo(arr, 0);
                Array.Reverse(arr);
            }
            // root serializer should be always from base type
            Debug.Assert(!OmitTypeSearchForRootSerialization);
            if (isRoot && BaseType != null)
            {
                return(new ForbiddenRootStub(Type));
            }
            return(new TypeSerializer(_model, Type, fieldNumbers, serializers, arr, BaseType == null, !_settingsValueFinal.SkipConstructor, _callbacks, _settingsValueFinal.ConstructType, _factory, _settingsValueFinal.PrefixLength.Value));
        }
Example #16
0
        IProtoSerializerWithWireType BuildSerializer()
        {
            if (_serializer != null)
            {
                return(_serializer);
            }

            int opaqueToken = 0;

            try
            {
                // this lock is for whole model, not just this value member
                // so it should be taken anyway, right?
                _model.TakeLock(ref opaqueToken); // check nobody is still adding this type

                if (_serializer != null)
                {
                    return(_serializer);                     // double check
                }
                FinalizingSettings?.Invoke(this, new FinalizingSettingsArgs(this));

                if (FieldNumber < 1 && !Helpers.IsEnum(ParentType) && !_isAccessHandledOutside)
                {
                    throw new ProtoException("FieldNumber < 1 for member " + Member);
                }

                if (Helpers.IsNullOrEmpty(_main.Name))
                {
                    _main.Name = Member.Name;
                }

                _vsFinal = _vsByClient.Clone();

                var level0 = _vsFinal.GetSettingsCopy(0);
                if (level0.Basic.EffectiveType == null)
                {
                    level0.Basic.EffectiveType = MemberType;
                }
                if (!level0.IsNotAssignable)
                {
                    level0.IsNotAssignable = !Helpers.CanWrite(_model, Member);
                }
                _vsFinal.SetSettings(level0, 0);

                if (_vsFinal.DefaultValue != null && _getSpecified != null)
                {
                    throw new ProtoException("Can't use default value \"" + _vsFinal.DefaultValue + "\" on member with *Specified or ShouldSerialize check " + Member);
                }

                if (_vsFinal.DefaultValue != null && IsRequired)
                {
                    throw new ProtoException("Can't use default value \"" + _vsFinal.DefaultValue + "\" on Required member " + Member);
                }

                if (_getSpecified == null && !IsRequired && _vsFinal.DefaultValue == null)
                {
                    if (_model.UseImplicitZeroDefaults)
                    {
                        switch (Helpers.GetTypeCode(MemberType))
                        {
                        case ProtoTypeCode.Boolean:
                            _vsFinal.DefaultValue = false;
                            break;

                        case ProtoTypeCode.Decimal:
                            _vsFinal.DefaultValue = (decimal)0;
                            break;

                        case ProtoTypeCode.Single:
                            _vsFinal.DefaultValue = (float)0;
                            break;

                        case ProtoTypeCode.Double:
                            _vsFinal.DefaultValue = (double)0;
                            break;

                        case ProtoTypeCode.Byte:
                            _vsFinal.DefaultValue = (byte)0;
                            break;

                        case ProtoTypeCode.Char:
                            _vsFinal.DefaultValue = (char)0;
                            break;

                        case ProtoTypeCode.Int16:
                            _vsFinal.DefaultValue = (short)0;
                            break;

                        case ProtoTypeCode.Int32:
                            _vsFinal.DefaultValue = (int)0;
                            break;

                        case ProtoTypeCode.Int64:
                            _vsFinal.DefaultValue = (long)0;
                            break;

                        case ProtoTypeCode.SByte:
                            _vsFinal.DefaultValue = (sbyte)0;
                            break;

                        case ProtoTypeCode.UInt16:
                            _vsFinal.DefaultValue = (ushort)0;
                            break;

                        case ProtoTypeCode.UInt32:
                            _vsFinal.DefaultValue = (uint)0;
                            break;

                        case ProtoTypeCode.UInt64:
                            _vsFinal.DefaultValue = (ulong)0;
                            break;

                        case ProtoTypeCode.TimeSpan:
                            _vsFinal.DefaultValue = TimeSpan.Zero;
                            break;

                        case ProtoTypeCode.Guid:
                            _vsFinal.DefaultValue = Guid.Empty;
                            break;
                        }
                    }
                }

#if !DEBUG
                try
#endif
                {
                    WireType wt;
                    var      ser = _model.ValueSerializerBuilder.BuildValueFinalSerializer(
                        _vsFinal,
                        true,
                        out wt);

                    if (!_isAccessHandledOutside)
                    {
                        PropertyInfo prop = Member as PropertyInfo;
                        if (prop != null)
                        {
                            ser = new PropertyDecorator(_model, ParentType, (PropertyInfo)Member, ser);
                        }
                        else
                        {
                            FieldInfo fld = Member as FieldInfo;
                            if (fld != null)
                            {
                                ser = new FieldDecorator(ParentType, (FieldInfo)Member, ser);
                            }
                            else
                            {
                                throw new InvalidOperationException();
                            }
                        }

                        if (_getSpecified != null || _setSpecified != null)
                        {
                            ser = new MemberSpecifiedDecorator(_getSpecified, _setSpecified, ser);
                        }
                    }
                    _serializer = ser;

                    return(ser);
                }
#if !DEBUG
                catch (ProtoException ex)
                {
                    throw new ProtoException(GetRethrowExceptionText(ex), ex);
                }
                catch (InvalidOperationException ex)
                {
                    throw new InvalidOperationException(GetRethrowExceptionText(ex), ex);
                }
                catch (NotSupportedException ex)
                {
                    throw new InvalidOperationException(GetRethrowExceptionText(ex), ex);
                }
                catch (NotImplementedException ex)
                {
                    throw new NotImplementedException(GetRethrowExceptionText(ex), ex);
                }
                catch (ArgumentNullException ex)
                {
                    throw new ArgumentNullException(GetRethrowExceptionText(ex), ex);
                }
                catch (ArgumentOutOfRangeException ex)
                {
                    throw new ArgumentOutOfRangeException(GetRethrowExceptionText(ex), ex);
                }
                catch (ArgumentException ex)
                {
#if SILVERLIGHT || PORTABLE
                    throw new ArgumentException(GetRethrowExceptionText(ex), ex);
#else
                    throw new ArgumentException(GetRethrowExceptionText(ex), ex.ParamName, ex);
#endif
                }
                catch (System.MissingMemberException ex)
                {
                    throw new System.MissingMemberException(GetRethrowExceptionText(ex), ex);
                }
                catch (MemberAccessException ex)
                {
                    throw new MemberAccessException(GetRethrowExceptionText(ex), ex);
                }
                catch (Exception ex)
                {
                    throw new ProtoException(GetRethrowExceptionText(ex), ex);
                }
#endif
            }
            finally
            {
                _model.ReleaseLock(opaqueToken);
            }
        }
        IProtoSerializerWithWireType DecorateValueSerializer(Type type, BinaryDataFormat?dynamicTypeDataFormat, ref ValueFormat format, IProtoSerializerWithWireType ser)
        {
            // Uri decorator is applied after default value
            // because default value for Uri is treated as string

            if (ser.ExpectedType == _model.MapType(typeof(string)) && type == _model.MapType(typeof(Uri)))
            {
                ser = new UriDecorator(_model, ser);
            }
#if PORTABLE
            else if (ser.ExpectedType == _model.MapType(typeof(string)) && type.FullName == typeof(Uri).FullName)
            {
                // In PCLs, the Uri type may not match (WinRT uses Internal/Uri, .Net uses System/Uri)
                ser = new ReflectedUriDecorator(type, _model, ser);
            }
#endif
            if (dynamicTypeDataFormat != null)
            {
                ser = new NetObjectValueDecorator(type, format == ValueFormat.Reference || format == ValueFormat.LateReference, dynamicTypeDataFormat.Value, !_model.ProtoCompatibility.SuppressNullWireType, _model);
            }
            else if (MetaType.IsNetObjectValueDecoratorNecessary(_model, format))
            {
                ser = new NetObjectValueDecorator(
                    ser,
                    Helpers.GetNullableUnderlyingType(type) != null,
                    format == ValueFormat.Reference || format == ValueFormat.LateReference,
                    format == ValueFormat.LateReference && CanTypeBeAsLateReferenceOnBuildStage(_model.GetKey(type, false, true), _model),
                    !_model.ProtoCompatibility.SuppressNullWireType,
                    _model);
            }
            else
            {
                format = ValueFormat.Compact;
            }

            return(ser);
        }
        public IProtoSerializerWithWireType TryGetCoreSerializer(BinaryDataFormat dataFormat, Type type, out WireType defaultWireType,
                                                                 ref ValueFormat format, bool dynamicType, bool appendCollection, bool isPackedCollection, bool allowComplexTypes, ref object defaultValue)
        {
            if (format == ValueFormat.NotSpecified)
            {
                throw new ArgumentException("Format should be specified for TryGetCoreSerializer", nameof(format));
            }
            if (format != ValueFormat.Compact && _model.ProtoCompatibility.SuppressValueEnhancedFormat)
            {
                throw new InvalidOperationException("TryGetCoreSerializer should receive final format with ProtoCompatibility already taken into account");
            }
            Type originalType = type;

#if !NO_GENERICS
            {
                Type tmp = Helpers.GetNullableUnderlyingType(type);
                if (tmp != null)
                {
                    type = tmp;
                }
            }
#endif
            defaultWireType = WireType.None;
            IProtoSerializerWithWireType ser = null;

            if (Helpers.IsEnum(type))
            {
                if (allowComplexTypes && _model != null)
                {
                    // need to do this before checking the typecode; an int enum will report Int32 etc
                    defaultWireType = WireType.Variant;
                    ser             = new WireTypeDecorator(defaultWireType, new EnumSerializer(type, _model.GetEnumMap(type)));
                }
                else
                { // enum is fine for adding as a meta-type
                    defaultWireType = WireType.None;
                    return(null);
                }
            }
            if (ser == null)
            {
                ser = TryGetBasicTypeSerializer(dataFormat, type, out defaultWireType, !appendCollection);
                if (ser != null && Helpers.GetTypeCode(type) == ProtoTypeCode.Uri)
                {
                    // should be after uri but uri should always be before collection
                    if (defaultValue != null)
                    {
                        ser          = new DefaultValueDecorator(_model, defaultValue, ser);
                        defaultValue = null;
                    }
                }
            }
            if (ser == null)
            {
                var parseable = _model.AllowParseableTypes ? ParseableSerializer.TryCreate(type, _model) : null;
                if (parseable != null)
                {
                    defaultWireType = WireType.String;
                    ser             = new WireTypeDecorator(defaultWireType, parseable);
                }
            }

            if (ser != null)
            {
                return((isPackedCollection || !allowComplexTypes) ? ser : DecorateValueSerializer(originalType, dynamicType ? dataFormat : (BinaryDataFormat?)null, ref format, ser));
            }

            if (allowComplexTypes)
            {
                int baseKey = _model.GetKey(type, false, true);

                defaultWireType = WireType.StartGroup;

                if (baseKey >= 0 || dynamicType)
                {
                    if (dynamicType)
                    {
                        return(new NetObjectValueDecorator(originalType, format == ValueFormat.Reference || format == ValueFormat.LateReference, dataFormat, !_model.ProtoCompatibility.SuppressNullWireType, _model));
                    }
                    else if (format == ValueFormat.LateReference && CanTypeBeAsLateReferenceOnBuildStage(baseKey, _model))
                    {
                        return(new NetObjectValueDecorator(originalType, baseKey, true, true, _model[type], !_model.ProtoCompatibility.SuppressNullWireType, _model));
                    }
                    else if (MetaType.IsNetObjectValueDecoratorNecessary(_model, format))
                    {
                        return(new NetObjectValueDecorator(originalType, baseKey, format == ValueFormat.Reference || format == ValueFormat.LateReference, false, _model[type], !_model.ProtoCompatibility.SuppressNullWireType, _model));
                    }
                    else
                    {
                        return(new ModelTypeSerializer(type, baseKey, _model[type], _model));
                    }
                }
            }
            defaultWireType = WireType.None;
            return(null);
        }
        IProtoSerializerWithWireType BuildValueFinalSerializer(ValueSerializationSettings settings, bool isMemberOrNested, out WireType wireType, int levelNumber)
        {
            object defaultValue;
            var    l = CompleteLevel(settings, levelNumber, out defaultValue).Basic;

            // to ensure that model can be copied and used again
            for (int i = 1; i <= 3; i++)
            {
                var l2 = CompleteLevel(settings, levelNumber, out defaultValue);
                Debug.Assert(l.Equals(l2.Basic));
            }

            Debug.Assert(l.ContentBinaryFormatHint != null, "l.ContentBinaryFormatHint != null");
            Debug.Assert(l.WriteAsDynamicType != null, "l.WriteAsDynamicType != null");
            Debug.Assert(l.Collection.Append != null, "l.Collection.Append != null");

            // postpone all checks for types when adding member till BuildSerializer, resolve everything only on buildserializer! till that have only local not inherited settings.
            // do not allow EnumPassthru and other settings to affect anything until buildling serializer
            wireType = 0;
            Type itemType = l.Collection.ItemType ?? l.EffectiveType;

            bool itemTypeCanBeNull = CanTypeBeNull(itemType);

            bool isPacked = CanBePackedCollection(l);

            IProtoSerializerWithWireType ser = null;

            if (l.Collection.IsCollection)
            {
                Type     nestedItemType    = null;
                Type     nestedDefaultType = null;
                int      idx  = _model.FindOrAddAuto(itemType, false, true, false);
                MetaType type = idx < 0 ? null : _model[itemType];
                if (!type?.GetFinalSettingsCopy().IgnoreListHandling ?? true)
                {
                    MetaType.ResolveListTypes(_model, itemType, ref nestedItemType, ref nestedDefaultType);
                }

                bool itemIsNestedCollection = nestedItemType != null;

                // primitive types except System.Object may be handled as nested through recursion
                bool tryHandleAsRegistered = !isMemberOrNested || itemType == _model.MapType(typeof(object));

                if (tryHandleAsRegistered)
                {
                    var nestedLevel = settings.GetSettingsCopy(levelNumber + 1);
                    nestedLevel = PrepareNestedLevelForBuild(nestedLevel, itemType);
                    settings.SetSettings(nestedLevel, levelNumber + 1);
                    // should use its level settings and merge from type, ...
                    ser = BuildValueFinalSerializer(settings, true, out wireType, levelNumber + 1);

                    //object dummy = null;

                    //ser = TryGetCoreSerializer(l.ContentBinaryFormatHint.Value, nestedLevel.Basic.EffectiveType, out wireType, ref nestedLevel.Basic.Format, nestedLevel.Basic.WriteAsDynamicType.GetValueOrDefault(), l.Collection.Append.Value, isPacked, true, ref dummy);
                    //if (ser != null)
                    //    ThrowIfHasMoreLevels(settings, levelNumber + 1, l, ", no more nested type detected");
                }
                else if (!itemIsNestedCollection)
                {
                    var nestedLevel = settings.GetSettingsCopy(levelNumber + 1);
                    nestedLevel = PrepareNestedLevelForBuild(nestedLevel, itemType);
                    nestedLevel.Basic.Collection.ItemType = null; // IgnoreListHandling or not a collection
                    settings.SetSettings(nestedLevel, levelNumber + 1);

                    ser = BuildValueFinalSerializer(settings, true, out wireType, levelNumber + 1);
                }

                if (ser == null && itemIsNestedCollection)
                {
                    // if we already tried to lookup registered type no need to do it again

                    MetaType metaType;
                    if (_model.FindOrAddAuto(itemType, false, true, false, out metaType) >= 0)
                    {
                        nestedDefaultType = metaType.GetFinalSettingsCopy().ConstructType ?? nestedDefaultType ?? metaType.Type;
                    }

                    var nestedLevel = settings.GetSettingsCopy(levelNumber + 1);

                    if (nestedLevel.Basic.Collection.ConcreteType == null)
                    {
                        nestedLevel.Basic.Collection.ConcreteType = nestedDefaultType;
                    }

                    if (nestedLevel.IsNotAssignable)
                    {
                        throw new ProtoException("Nested collection item should be assignable");
                    }

                    nestedLevel.Basic.Collection.Append = false;
                    // TODO throw if set to true: throw new ProtoException("AppendCollection is not supported for nested types: " + objectType.Name);

                    if (nestedLevel.Basic.Collection.ItemType == null)
                    {
                        nestedLevel.Basic.Collection.ItemType = nestedItemType;
                    }
                    else if (!Helpers.IsAssignableFrom(nestedItemType, nestedLevel.Basic.Collection.ItemType))
                    {
                        throw new ProtoException(
                                  "Nested collection item type " + nestedLevel.Basic.Collection.ItemType + " is not assignable to " + nestedItemType + " for declared collection type " +
                                  l.EffectiveType);
                    }

                    nestedLevel = PrepareNestedLevelForBuild(nestedLevel, itemType);

                    settings.SetSettings(nestedLevel, levelNumber + 1);

                    WireType wt;
                    ser = BuildValueFinalSerializer(
                        settings,
                        true,
                        out wt,
                        levelNumber + 1);

                    isPacked = false;
                }
            }
            else
            {
                // handled outside and not wrapped with collection
                if (!isMemberOrNested)
                {
                    l.Format = ValueFormat.Compact;
                }

                isPacked = false; // it's not even a collection
                ser      = TryGetCoreSerializer(l.ContentBinaryFormatHint.Value, itemType, out wireType, ref l.Format, l.WriteAsDynamicType.Value, l.Collection.Append.Value, isPacked, true, ref defaultValue);
                if (ser != null)
                {
                    ThrowIfHasMoreLevels(settings, levelNumber, l, ", no more nested type detected");
                }
            }

            if (ser == null)
            {
                throw new InvalidOperationException("No serializer defined for type: " + itemType.FullName);
            }

            if (itemTypeCanBeNull &&
                (
                    (Helpers.GetNullableUnderlyingType(itemType) != null && Helpers.GetNullableUnderlyingType(ser.ExpectedType) == null)
                    // TODO get rid of ugly casting, maybe use builder pattern
                    || (!Helpers.IsValueType(itemType) && !(ser is NetObjectValueDecorator))
                ))
            {
                // nested level may be not collection and already wrapped with nonull, may later add check whether handled as registered vs as nested
                if (!(ser is NoNullDecorator))
                {
                    // if not wrapped with net obj - wrap with write-null check
                    ser = new NoNullDecorator(_model, ser, l.Collection.ItemType != null); // throw only for collection elements, otherwise don't write
                }
            }

            if (itemType != ser.ExpectedType && (!l.WriteAsDynamicType.Value || !Helpers.IsAssignableFrom(ser.ExpectedType, itemType)))
            {
                throw new ProtoException(string.Format("Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, itemType));
            }

            // apply lists if appropriate
            if (l.Collection.IsCollection)
            {
                bool protoCompatibility = l.Collection.Format == CollectionFormat.Protobuf || l.Collection.Format == CollectionFormat.ProtobufNotPacked;

                WireType packedReadWt;
                if (!protoCompatibility)
                {
                    packedReadWt = WireType.None;
                    Debug.Assert(!isPacked); // should be determinated before passing to TryGetCoreSerializer
                    isPacked = false;
                }
                else
                {
                    packedReadWt = CanPack(l.Collection.ItemType, l.ContentBinaryFormatHint)
                                       ? l.Collection.PackedWireTypeForRead.GetValueOrDefault(wireType)
                                       : WireType.None;
                }

                if (l.EffectiveType.IsArray)
                {
                    if (l.EffectiveType.GetArrayRank() == 1)
                    {
                        ser = new ArrayDecorator(
                            _model,
                            ser,
                            isPacked,
                            packedReadWt,
                            l.EffectiveType,
                            !l.Collection.Append.Value,
                            l.Collection.ArrayLengthReadLimit.Value,
                            protoCompatibility);
                    }
                    else
                    {
                        if (protoCompatibility)
                        {
                            throw new NotSupportedException("Multi-dimensional arrays are supported only in Enhanced collection format");
                        }

                        ser = new MultiDimensionalArrayDecorator(
                            _model,
                            ser,
                            l.EffectiveType,
                            !l.Collection.Append.Value,
                            l.Collection.ArrayLengthReadLimit.Value);
                    }
                }
                else
                {
                    ser = ListDecorator.Create(
                        _model,
                        l.EffectiveType,
                        l.Collection.ConcreteType,
                        ser,
                        isPacked,
                        packedReadWt,
                        !l.Collection.Append.Value,
                        protoCompatibility,
                        true);
                }

                if (isMemberOrNested)
                {
                    if (MetaType.IsNetObjectValueDecoratorNecessary(_model, l.Format))
                    {
                        ser = new NetObjectValueDecorator(
                            ser,
                            Helpers.GetNullableUnderlyingType(l.EffectiveType) != null,
                            l.Format == ValueFormat.Reference || l.Format == ValueFormat.LateReference,
                            l.Format == ValueFormat.LateReference && CanTypeBeAsLateReferenceOnBuildStage(_model.GetKey(l.EffectiveType, false, true), _model),
                            !_model.ProtoCompatibility.SuppressNullWireType,
                            _model);
                    }
                    else if (!Helpers.IsValueType(l.EffectiveType) || Helpers.GetNullableUnderlyingType(l.EffectiveType) != null)
                    {
                        ser = new NoNullDecorator(_model, ser, false);
                    }
                }


                if (l.EffectiveType != ser.ExpectedType && (!l.WriteAsDynamicType.Value || !Helpers.IsAssignableFrom(ser.ExpectedType, itemType)))
                {
                    throw new ProtoException(string.Format("Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, itemType));
                }
            }

            if (levelNumber == 0 && defaultValue != null)
            {
                ser = new DefaultValueDecorator(_model, defaultValue, ser);
            }

            return(ser);
        }
Example #20
0
 internal IProtoSerializerWithWireType GetSerializer(RuntimeTypeModel model) => _serializer ?? (_serializer = BuildSerializer(model));
Example #21
0
 public NetObjectValueDecorator(IProtoSerializerWithWireType tail, bool returnNullable, bool asReference, bool asLateReference, bool allowNullWireType, RuntimeTypeModel model)
     : this(type : MakeReturnNullable(tail.ExpectedType, returnNullable, model), asReference : asReference, asLateReference : asLateReference, allowNullWireType : allowNullWireType, model : model)
 {
     _tail            = tail;
     RequiresOldValue = _tail.RequiresOldValue || (_lateReferenceTail?.RequiresOldValue ?? false);
 }
Example #22
0
 public MemberSpecifiedDecorator(MethodInfo getSpecified, MethodInfo setSpecified, IProtoSerializerWithWireType tail)
     : base(tail)
 {
     if (getSpecified == null && setSpecified == null)
     {
         throw new InvalidOperationException();
     }
     this._getSpecified = getSpecified;
     this._setSpecified = setSpecified;
 }
Example #23
0
 internal ImmutableCollectionDecorator(RuntimeTypeModel model, Type declaredType, Type concreteType, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireType, bool overwriteList,
                                       MethodInfo builderFactory, MethodInfo add, MethodInfo addRange, MethodInfo finish, bool protoCompatibility)
     : base(model, declaredType, concreteType, tail, writePacked, packedWireType, overwriteList, protoCompatibility, false)
 {
     this._builderFactory = builderFactory;
     this._add            = add;
     this._addRange       = addRange;
     this._finish         = finish;
 }
Example #24
0
        protected ListDecorator(
            RuntimeTypeModel model, Type declaredType, Type concreteTypeDefault, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireType,
            bool overwriteList, bool protoCompatibility, bool writeSubType)
            : base(tail)
        {
            if (overwriteList)
            {
                _options |= OPTIONS_OverwriteList;
            }

            PackedWireTypeForRead = packedWireType;
            _protoCompatibility   = protoCompatibility;
            _writeSubType         = writeSubType && !protoCompatibility;

            if (writePacked)
            {
                _options |= OPTIONS_WritePacked;
            }
            if (declaredType == null)
            {
                throw new ArgumentNullException(nameof(declaredType));
            }
            if (declaredType.IsArray)
            {
                throw new ArgumentException("Cannot treat arrays as lists", nameof(declaredType));
            }
            this.ExpectedType         = declaredType;
            this._concreteTypeDefault = concreteTypeDefault ?? declaredType;

            // look for a public list.Add(typedObject) method
            if (RequireAdd)
            {
                bool isList;
                _add = TypeModel.ResolveListAdd(model, declaredType, tail.ExpectedType, out isList);
                if (isList)
                {
                    _options |= OPTIONS_IsList;
                    string fullName = declaredType.FullName;
                    if (fullName != null && fullName.StartsWith("System.Data.Linq.EntitySet`1[[", StringComparison.Ordinal))
                    { // see http://stackoverflow.com/questions/6194639/entityset-is-there-a-sane-reason-that-ilist-add-doesnt-set-assigned
                        _options |= OPTIONS_SuppressIList;
                    }
                }
                if (_add == null)
                {
                    throw new InvalidOperationException("Unable to resolve a suitable Add method for " + declaredType.FullName);
                }
            }

            ListHelpers = new ListHelpers(WritePacked, PackedWireTypeForRead, _protoCompatibility, tail, false);

            if (!protoCompatibility)
            {
                int key = model.GetKey(declaredType, false, false);
                if (key >= 0)
                {
                    _metaType = model[key];
                }
                else
                {
                    _writeSubType = false; // warn?
                }
            }
        }