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