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(); } }
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); } }
static bool GetEnumPassthrough(MetaType metaType) { return(metaType.GetFinalSettingsCopy().EnumPassthru.Value); }