Esempio n. 1
0
        public override void Write(object value, ProtoWriter dest)
        {
            Action metaWriter =
                () =>
            {
                // we still write length in case it will be read as array
                int length = (value as ICollection)?.Count ?? 0;
                if (length > 0)
                {
                    ProtoWriter.WriteFieldHeader(ListHelpers.FieldLength, WireType.Variant, dest);
                    ProtoWriter.WriteInt32(length, dest);
                }
                if (_writeSubType)
                {
                    Type t = value.GetType();
                    if (_concreteTypeDefault != t)
                    {
                        ProtoWriter.WriteFieldHeaderBegin(ListHelpers.FieldSubtype, dest);
                        _subTypeHelpers.Write(_metaType, t, dest);
                    }
                }
            };

            ListHelpers.Write(value, metaWriter, null, dest);
        }
 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);
 }
Esempio n. 3
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);
 }
Esempio n. 4
0
        public override object Read(object value, ProtoReader source)
        {
            int    trappedKey      = ProtoReader.ReserveNoteObject(source);
            object builderInstance = _builderFactory.Invoke(null, null);

            object[] args = new object[1];

            if (AppendToCollection && value != null && ((IList)value).Count != 0)
            {
                if (_addRange != null)
                {
                    args[0] = value;
                    _addRange.Invoke(builderInstance, args);
                }
                else
                {
                    foreach (object item in (IList)value)
                    {
                        args[0] = item;
                        _add.Invoke(builderInstance, args);
                    }
                }
            }

            ListHelpers.Read(null, null,
                             o =>
            {
                args[0] = o;
                _add.Invoke(builderInstance, args);
            },
                             source);

            var r = _finish.Invoke(builderInstance, null);

            ProtoReader.NoteReservedTrappedObject(trappedKey, r, source);
            return(r);
        }
Esempio n. 5
0
        protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                Type voidType = ctx.MapType(typeof(void));
                using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                    using (Compiler.Local builderInstance = new Compiler.Local(ctx, _builderFactory.ReturnType))
                        using (Compiler.Local trappedKey = new Compiler.Local(ctx, typeof(int)))
                        {
                            ctx.G.Assign(trappedKey, ctx.G.ReaderFunc.ReserveNoteObject_int());
                            ctx.EmitCall(_builderFactory);
                            ctx.StoreValue(builderInstance);

                            if (AppendToCollection)
                            {
                                Compiler.CodeLabel done = ctx.DefineLabel();
                                if (!ExpectedType.IsValueType)
                                {
                                    ctx.LoadValue(value);
                                    ctx.BranchIfFalse(done, false); // old value null; nothing to add
                                }
                                PropertyInfo prop = Helpers.GetProperty(ExpectedType, "Length", false) ?? Helpers.GetProperty(ExpectedType, "Count", false);
#if !NO_GENERICS
                                if (prop == null)
                                {
                                    prop = Helpers.GetProperty(ResolveIReadOnlyCollection(ExpectedType, Tail.ExpectedType), "Count", false);
                                }
#endif
                                ctx.LoadAddress(value, value.Type);
                                ctx.EmitCall(Helpers.GetGetMethod(prop, false, false));
                                ctx.BranchIfFalse(done, false); // old list is empty; nothing to add

                                if (_addRange != null)
                                {
                                    ctx.LoadValue(builderInstance);
                                    ctx.LoadValue(value);
                                    ctx.EmitCall(_addRange);
                                    if (_addRange.ReturnType != null && _add.ReturnType != voidType)
                                    {
                                        ctx.DiscardValue();
                                    }
                                }
                                else
                                {
                                    // loop and call Add repeatedly
                                    MethodInfo moveNext, current, getEnumerator = GetEnumeratorInfo(ctx.Model, out moveNext, out current);
                                    Helpers.DebugAssert(moveNext != null);
                                    Helpers.DebugAssert(current != null);
                                    Helpers.DebugAssert(getEnumerator != null);

                                    Type enumeratorType = getEnumerator.ReturnType;
                                    using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType))
                                    {
                                        ctx.LoadAddress(value, ExpectedType);
                                        ctx.EmitCall(getEnumerator);
                                        ctx.StoreValue(iter);
                                        using (ctx.Using(iter))
                                        {
                                            Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel();
                                            ctx.Branch(next, false);

                                            ctx.MarkLabel(body);
                                            ctx.LoadAddress(builderInstance, builderInstance.Type);
                                            ctx.LoadAddress(iter, enumeratorType);
                                            ctx.EmitCall(current);
                                            ctx.EmitCall(_add);
                                            if (_add.ReturnType != null && _add.ReturnType != voidType)
                                            {
                                                ctx.DiscardValue();
                                            }

                                            ctx.MarkLabel(@next);
                                            ctx.LoadAddress(iter, enumeratorType);
                                            ctx.EmitCall(moveNext);
                                            ctx.BranchIfTrue(body, false);
                                        }
                                    }
                                }


                                ctx.MarkLabel(done);
                            }

                            ListHelpers.EmitRead(
                                ctx.G,
                                null,
                                null,
                                o =>
                            {
                                using (ctx.StartDebugBlockAuto(this, "add"))
                                {
                                    ctx.LoadAddress(builderInstance, builderInstance.Type);
                                    ctx.LoadValue(o);
                                    ctx.EmitCall(_add);
                                    if (_add.ReturnType != null && _add.ReturnType != voidType)
                                    {
                                        ctx.DiscardValue();
                                    }
                                }
                            });

                            ctx.LoadAddress(builderInstance, builderInstance.Type);
                            ctx.EmitCall(_finish);
                            if (ExpectedType != _finish.ReturnType)
                            {
                                ctx.Cast(ExpectedType);
                            }
                            ctx.StoreValue(value);
                            ctx.G.Reader.NoteReservedTrappedObject(trappedKey, value);

                            if (EmitReadReturnsValue)
                            {
                                ctx.LoadValue(value);
                            }
                        }
            }
        }
Esempio n. 6
0
        public override object Read(object value, ProtoReader source)
        {
            IList list = null;

            object[] args       = null;
            bool     createdNew = false;
            bool     asList     = IsList && !SuppressIList;

            // can't call clear? => create new!
            bool forceNewInstance = !AppendToCollection && !asList;

            ListHelpers.Read(
                () =>
            {
                if (_metaType != null && source.TryReadFieldHeader(ListHelpers.FieldSubtype))
                {
                    MetaType mt = _subTypeHelpers.TryRead(_metaType, forceNewInstance ? null : value?.GetType(), source);
                    if (mt != null)
                    {
                        value      = mt.Serializer.CreateInstance(source);
                        createdNew = true;
                    }
                    return(true);
                }
                return(false);
            },
                () =>
            {
                if (value == null || (forceNewInstance && !createdNew))
                {
                    createdNew = true;
                    value      = Activator.CreateInstance(_concreteTypeDefault);
                    ProtoReader.NoteObject(value, source);
                    if (asList)
                    {
                        list = (IList)value;
                        Debug.Assert(list != null);
                    }
                }
                else
                {
                    if (!createdNew)
                    {
                        ProtoReader.NoteObject(value, source);
                    }

                    if (asList)
                    {
                        list = (IList)value;
                        Debug.Assert(list != null);
                        if (!AppendToCollection && !createdNew)
                        {
                            list.Clear();
                        }
                    }
                }

                if (!asList)
                {
                    args = new object[1];
                }
            },
                v =>
            {
                if (asList)
                {
                    list.Add(v);
                }
                else
                {
                    args[0] = v;
                    this._add.Invoke(value, args);
                }
            },
                source);

            return(value);
        }
Esempio n. 7
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?
                }
            }
        }