protected override void EmitWrite(UcAsp.RPC.ProtoBuf.Compiler.CompilerContext ctx, UcAsp.RPC.ProtoBuf.Compiler.Local valueFrom) { // int i and T[] arr using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom)) using (Compiler.Local i = new UcAsp.RPC.ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int)))) { bool writePacked = (options & OPTIONS_WritePacked) != 0; bool fixedLengthPacked = writePacked && CanUsePackedPrefix(); using (Compiler.Local token = (writePacked && !fixedLengthPacked) ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null) { Type mappedWriter = ctx.MapType(typeof(ProtoWriter)); if (writePacked) { ctx.LoadValue(fieldNumber); ctx.LoadValue((int)WireType.String); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader")); if (fixedLengthPacked) { // write directly - no need for buffering ctx.LoadLength(arr, false); ctx.LoadValue((int)packedWireType); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("WritePackedPrefix")); } else { ctx.LoadValue(arr); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("StartSubItem")); ctx.StoreValue(token); } ctx.LoadValue(fieldNumber); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("SetPackedField")); } EmitWriteArrayLoop(ctx, i, arr); if (writePacked) { if (fixedLengthPacked) { ctx.LoadValue(fieldNumber); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("ClearPackedField")); } else { ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("EndSubItem")); } } } } }
protected override void EmitRead(UcAsp.RPC.ProtoBuf.Compiler.CompilerContext ctx, UcAsp.RPC.ProtoBuf.Compiler.Local valueFrom) { Type listType; #if NO_GENERICS listType = typeof(BasicList); #else listType = ctx.MapType(typeof(System.Collections.Generic.List <>)).MakeGenericType(itemType); #endif Type expected = ExpectedType; using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(expected, valueFrom) : null) using (Compiler.Local newArr = new Compiler.Local(ctx, expected)) using (Compiler.Local list = new Compiler.Local(ctx, listType)) { ctx.EmitCtor(listType); ctx.StoreValue(list); ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false); // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList using (Compiler.Local oldLen = AppendToCollection ? new UcAsp.RPC.ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) { Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) }; if (AppendToCollection) { ctx.LoadLength(oldArr, true); ctx.CopyValue(); ctx.StoreValue(oldLen); ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.Add(); ctx.CreateArray(itemType, null); // length is on the stack ctx.StoreValue(newArr); ctx.LoadValue(oldLen); Compiler.CodeLabel nothingToCopy = ctx.DefineLabel(); ctx.BranchIfFalse(nothingToCopy, true); ctx.LoadValue(oldArr); ctx.LoadValue(newArr); ctx.LoadValue(0); // index in target ctx.EmitCall(expected.GetMethod("CopyTo", copyToArrayInt32Args)); ctx.MarkLabel(nothingToCopy); ctx.LoadValue(list); ctx.LoadValue(newArr); ctx.LoadValue(oldLen); } else { ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.CreateArray(itemType, null); ctx.StoreValue(newArr); ctx.LoadAddress(list, listType); ctx.LoadValue(newArr); ctx.LoadValue(0); } copyToArrayInt32Args[0] = expected; // // prefer: CopyTo(T[], int) MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); if (copyTo == null) { // fallback: CopyTo(Array, int) copyToArrayInt32Args[1] = ctx.MapType(typeof(Array)); copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); } ctx.EmitCall(copyTo); } ctx.LoadValue(newArr); } }