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); }
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); }
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); }
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); } } } }
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); }
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? } } }