void EmitRead_CreateInstance(SerializerCodeGen g, Local valueArr, Local[] lengths, Operand optionalOutOldFirstDimLength, Local outResult) { using (g.ctx.StartDebugBlockAuto(this)) { if (AppendToCollection) { g.If(valueArr.AsOperand != null); { g.AssignAdd(lengths[0], optionalOutOldFirstDimLength.Assign(valueArr.AsOperand.Invoke("GetLength", 0))); } g.End(); } g.Assign(outResult, g.ExpressionFactory.NewArray(_itemType, lengths.Select(l => (Operand)l.AsOperand).ToArray())); g.Reader.NoteObject(outResult); if (AppendToCollection) { g.If(valueArr.AsOperand != null && optionalOutOldFirstDimLength > 0); { g.Invoke(typeof(Array), "Copy", valueArr, outResult, valueArr.AsOperand.Property("Length")); } g.End(); } } }
void EmitWrite(SerializerCodeGen g, Label?endLabel, MetaType metaType, Local actualValue, Local actualType, int recursionLevel = 0) { using (g.ctx.StartDebugBlockAuto(this, metaType.GetFinalSettingsCopy().Name + ", level = " + recursionLevel)) { WriterGen dest = g.Writer; var breakLabel = g.DefineLabel(); g.If(metaType.Type != actualType.AsOperand); { foreach (var subType in metaType.GetSubtypes().OrderBy(st => st.FieldNumber)) { MetaType derivedType = subType.DerivedType; if (derivedType.Type == metaType.Type) { continue; } g.If(actualValue.AsOperand.Is(derivedType.Type)); { if (recursionLevel == 0) { g.If(derivedType.Type == actualType.AsOperand); { dest.WriteFieldHeaderComplete(WireType.Variant); dest.WriteInt32(subType.FieldNumber + 1); g.Goto(endLabel ?? breakLabel); } g.End(); using (var token = g.ctx.Local(typeof(SubItemToken))) { g.Assign(token, g.WriterFunc.StartSubItem(null, true)); dest.WriteFieldHeaderIgnored(WireType.Variant); dest.WriteInt32(subType.FieldNumber + 1); EmitWrite(g, null, derivedType, actualValue, actualType, 1); dest.EndSubItem(token); } } else { dest.WriteFieldHeaderIgnored(WireType.Variant); dest.WriteInt32(subType.FieldNumber + 1); EmitWrite(g, null, derivedType, actualValue, actualType, recursionLevel + 1); } g.Goto(endLabel ?? breakLabel); } g.End(); } } g.End(); g.MarkLabel(breakLabel); if (recursionLevel == 0) { dest.WriteFieldHeaderComplete(WireType.Variant); dest.WriteInt32(0); } } }
void EmitTryRead(SerializerCodeGen g, Local fieldNumber, MetaType metaType, int recursionLevel, Action <MetaType> returnGen) { Debug.Assert(metaType != null); using (g.ctx.StartDebugBlockAuto(this, metaType.GetFinalSettingsCopy().Name + ", level = " + recursionLevel)) { SubType[] subTypes = metaType.GetSubtypes(); if (recursionLevel == 0) { g.If(g.ReaderFunc.WireType() != WireType.String); { g.Assign(fieldNumber, g.ReaderFunc.ReadInt32() - 1); EmitTryRead_GenSwitch(g, fieldNumber, metaType, subTypes, returnGen); } g.End(); } Local token = null; if (recursionLevel == 0) { token = new Local(g.ctx, typeof(SubItemToken)); g.Assign(token, g.ReaderFunc.StartSubItem()); returnGen = (r => g.Reader.EndSubItem(token)) + returnGen; } g.If(!g.ReaderFunc.HasSubValue_bool(WireType.Variant)); { returnGen(metaType); } g.End(); g.Assign(fieldNumber, g.ReaderFunc.ReadInt32() - 1); EmitTryRead_GenSwitch( g, fieldNumber, metaType, subTypes, r => { if (r == metaType) { returnGen(metaType); } else { EmitTryRead(g, fieldNumber, r, recursionLevel + 1, returnGen); } }); token?.Dispose(); } }
void EmitWriteElement(SerializerCodeGen g, Operand obj, Operand fieldNumber, bool pack, Operand isFirst) { if (_protoCompatibility) { if (!pack) { g.Writer.WriteFieldHeaderBegin(fieldNumber); } else { g.Writer.WriteFieldHeaderBeginIgnored(); } } else { // this can only be supported when wire type of elements will be the same each time and no field cancellations // we write only first header to get wire type // the difference between standard pack and this // is that we write wiretype here at the first time if (pack) { g.If(isFirst); } g.Writer.WriteFieldHeaderBegin(fieldNumber); if (pack) { g.Else(); g.Writer.WriteFieldHeaderBeginIgnored(); g.End(); } } g.LeaveNextReturnOnStack(); g.Eval(obj); _tail.EmitWrite(g.ctx, null); }
void EmitWriteContentEnumerable(SerializerCodeGen g, Local enumerable, Operand fieldNumber, bool pack, Action first = null) { Type enumerableGenericType = g.ctx.MapType(typeof(IEnumerable <>)).MakeGenericType(_itemType); bool castNeeded = !Helpers.IsAssignableFrom(enumerableGenericType, enumerable.Type); using (var isFirst = g.ctx.Local(typeof(bool))) { g.Assign(isFirst, true); var el = g.ForEach(castNeeded ? g.ctx.MapType(typeof(object)) : _itemType, enumerable); { g.If(isFirst); { first?.Invoke(); } g.End(); EmitWriteElement(g, castNeeded ? el.Cast(_itemType) : el, fieldNumber, pack, isFirst); g.Assign(isFirst, false); } g.End(); } }
void EmitWriteContent(SerializerCodeGen g, Local enumerable, Operand fieldNumber, bool pack, Action first = null) { Type listType = g.ctx.MapType(typeof(IList <>)).MakeGenericType(_itemType); if (_skipIList || (!enumerable.Type.IsArray && !Helpers.IsAssignableFrom(listType, enumerable.Type))) { EmitWriteContentEnumerable(g, enumerable, fieldNumber, pack, first); return; } using (var list = g.ctx.Local(listType)) using (var len = g.ctx.Local(typeof(int))) using (var i = g.ctx.Local(typeof(int))) { g.Assign(list, enumerable.AsOperand.Cast(listType)); g.Assign(len, list.AsOperand.Property("Count")); g.If(len.AsOperand > 0); { first?.Invoke(); g.For(i.AsOperand.Assign(0), i.AsOperand < len.AsOperand, i.AsOperand.Increment()); { EmitWriteElement(g, list.AsOperand[i], fieldNumber, pack, i.AsOperand == 0); } g.End(); } g.End(); if (enumerable.Type.IsValueType) { g.Assign(enumerable, list); } } }
public void EmitTryRead(SerializerCodeGen g, Local oldValue, MetaType metaType, Action <MetaType> returnGen) { Debug.Assert(metaType != null); using (g.ctx.StartDebugBlockAuto(this, metaType.GetFinalSettingsCopy().Name)) using (var fieldNumber = new Local(g.ctx, typeof(int))) { var jumpOut = g.DefineLabel(); returnGen += mt => { g.ctx.MarkDebug("// jump out of SubTypeHelpers.EmitTryRead"); g.Goto(jumpOut); }; EmitTryRead( g, fieldNumber, metaType, 0, r => { while (r != null && !r.Serializer.CanCreateInstance() && r != metaType) { r = r.BaseType; } if (r == null) { returnGen(null); } else if (!oldValue.IsNullRef()) // check local exists { g.If(oldValue.AsOperand.Is(r.Type)); { returnGen(null); } g.Else(); { returnGen(r); } g.End(); } else { returnGen(r); } }); g.MarkLabel(jumpOut); } }
void EmitRead_CreateInstance(SerializerCodeGen g, Local value, Operand appendCount, Local reservedTrap, Local outOldLen, Local outResult) { using (g.ctx.StartDebugBlockAuto(this)) { g.Assign(outOldLen, AppendToCollection ? (value.AsOperand != null).Conditional(value.AsOperand.Property("Length"), 0) : (Operand)0); g.Assign(outResult, g.ExpressionFactory.NewArray(_itemType, outOldLen + appendCount)); if (!reservedTrap.IsNullRef()) { g.Reader.NoteReservedTrappedObject(reservedTrap, outResult); } else { g.Reader.NoteObject(outResult); } g.If(outOldLen.AsOperand != 0); { g.Invoke(value, "CopyTo", outResult, 0); } g.End(); } }
public void EmitRead(SerializerCodeGen g, EmitReadMetaDelegate readNextMeta, Action prepareInstance, Action <Local> add) { if (readNextMeta == null) { readNextMeta = (s, f) => f(); } using (g.ctx.StartDebugBlockAuto(this)) { WireType packedWireType = _packedWireTypeForRead; bool packedAllowedStatic = (!_protoCompatibility || packedWireType != WireType.None); using (var packed = packedAllowedStatic ? g.ctx.Local(typeof(bool)) : null) using (var token = g.ctx.Local(typeof(SubItemToken))) using (var fieldNumber = _protoCompatibility ? g.ctx.Local(typeof(int)):null) using (var loop = g.ctx.Local(typeof(bool))) { if (!fieldNumber.IsNullRef()) { g.Assign(fieldNumber, g.ReaderFunc.FieldNumber()); } if (packedAllowedStatic) { g.Assign(packed, g.ReaderFunc.WireType() == WireType.String); } bool subItemNeededStatic = !_protoCompatibility; if (subItemNeededStatic || packedAllowedStatic) { if (!subItemNeededStatic) { g.If(packed); } g.Assign(token, g.ReaderFunc.StartSubItem()); if (!subItemNeededStatic) { g.End(); } } g.ctx.MarkDebug("ProtoCompatibility: " + _protoCompatibility); if (_protoCompatibility) { // this is not an error that we don't wait for the first item // if field is present there is at least one element prepareInstance?.Invoke(); if (packedAllowedStatic) { g.If(packed); { g.While(g.ReaderFunc.HasSubValue_bool(packedWireType)); { EmitReadElementContent(g, add); } g.End(); } g.Else(); } g.DoWhile(); { EmitReadElementContent(g, add); } g.EndDoWhile(g.ReaderFunc.TryReadFieldHeader_bool(fieldNumber)); if (packedAllowedStatic) { g.End(); } } else { var breakLabel = g.DefineLabel(); g.DoWhile(); { g.Assign(loop, false); readNextMeta( () => { using (g.ctx.StartDebugBlockAuto(this, "readNextMeta.OnSuccess")) { g.Assign(loop, true); } }, () => { using (g.ctx.StartDebugBlockAuto(this, "readNextMeta.OnFail")) { g.If(!g.ReaderFunc.TryReadFieldHeader_bool(FieldItem)); { g.If(g.ReaderFunc.ReadFieldHeader_int() == 0); { g.Goto(breakLabel); } g.End(); g.Reader.SkipField(); g.Assign(loop, true); } g.End(); } }); } g.EndDoWhile(loop); g.MarkLabel(breakLabel); prepareInstance?.Invoke(); g.If(g.ReaderFunc.FieldNumber() == FieldItem); { g.If(packed); { using (var packedWireTypeDynamic = g.ctx.Local(typeof(WireType))) { g.Assign(packedWireTypeDynamic, g.ReaderFunc.WireType()); g.DoWhile(); { EmitReadElementContent(g, add); } g.EndDoWhile(g.ReaderFunc.HasSubValue_bool(packedWireTypeDynamic)); } } g.Else(); { g.DoWhile(); { EmitReadElementContent(g, add); } g.EndDoWhile(g.ReaderFunc.TryReadFieldHeader_bool(FieldItem)); } g.End(); } g.End(); } if (subItemNeededStatic || packedAllowedStatic) { if (!subItemNeededStatic) { g.If(packed); } g.Reader.EndSubItem(token); if (!subItemNeededStatic) { g.End(); } } } } }