public void EmitWrite(SerializerCodeGen g, MetaType metaType, Local actualValue) { using (g.ctx.StartDebugBlockAuto(this)) { Debug.Assert(!actualValue.IsNullRef()); var endLabel = g.DefineLabel(); using (var actualType = new Local(g.ctx, typeof(System.Type))) { if (actualValue.IsNullRef()) { g.Assign(actualType, null); } else { //g.If(actualValue.AsOperand != null); { g.Assign(actualType, actualValue.AsOperand.InvokeGetType()); } //g.Else(); //{ // g.Assign(actualType, null); //} //g.End(); } EmitWrite(g, endLabel, metaType, actualValue, actualType); } g.MarkLabel(endLabel); } }
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); } } }
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); } }
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(); } } } } }