using XGame.Framework.Network.Protobuf; using System.Collections.Generic; namespace XGame.Framework.Network { public static class ProtobufUtils { /// /// 为了优化性能,返回的字节流头部预留10个字节给外部使用,外部可以把头部信息写入到这10个预留的位置中 /// 实际是8个字节用于头部,2个字节在body存body长度,因此与proto无关的字节数为前10字节 /// private const int HeadOffset = 10; public static readonly CodedOutputStream CodedOutput = new CodedOutputStream(); public static readonly CodedInputStream CodedInput = new CodedInputStream(); public static BytesWrapper CreateBytesWrapper(IMsgParser parsor) { CodedOutput.Buffer = SessionBufferPool.Acquire(); CodedOutput.Reset(HeadOffset); parsor.WriteTo(CodedOutput); return BytesWrapperPool.Acquire(CodedOutput.Buffer, HeadOffset, (int)CodedOutput.Position - HeadOffset); } public static void ParseFrom(byte[] bytes, int offset, int size, IMsgParser parser) { CodedInput.Reset(bytes, offset, size); parser.MergeFrom(CodedInput); CodedInput.CheckReadEndOfStreamTag(); } public static void WriteTo(CodedOutputStream output, FieldCodec codec, List ls) { if (ls == null || ls.Count == 0) return; var writer = codec.ValueWriter; var tag = codec.Tag; if (codec.PackedRepeatedField) { uint size = (uint)CalculatePackedDataSize(codec, ls); output.WriteTag(tag); output.WriteRawVarint32(size); for (int i = 0, count = ls.Count; i < count; i++) { writer(output, ls[i]); } } else { for (int i = 0, count = ls.Count; i < count; i++) { output.WriteTag(tag); writer(output, ls[i]); } } } private static int CalculatePackedDataSize(FieldCodec codec, List ls) { int fixedSize = codec.FixedSize; if (fixedSize == 0) { var calculator = codec.ValueSizeCalculator; int tmp = 0; for (int i = 0, count = ls.Count; i < count; i++) { tmp += calculator(ls[i]); } return tmp; } else { return fixedSize * ls.Count; } } public static void AddEntriesFrom(CodedInputStream input, FieldCodec codec, List ls) { uint tag = input.LastTag; var reader = codec.ValueReader; if (FieldCodec.IsPackedRepeatedField(tag)) { int length = input.ReadLength(); if (length > 0) { int oldLimit = input.PushLimit(length); while (!input.ReachedLimit) { ls.Add(reader(input)); } input.PopLimit(oldLimit); } } else { do { ls.Add(reader(input)); } while (input.MaybeConsumeTag(tag)); } } public static int CalculateSize(FieldCodec codec, List ls) { if (ls == null) { return 0; } int count = ls.Count; if (ls.Count == 0) { return 0; } uint tag = codec.Tag; if (codec.PackedRepeatedField) { int dataSize = CalculatePackedDataSize(codec, ls); return CodedOutputStream.ComputeRawVarint32Size(tag) + CodedOutputStream.ComputeLengthSize(dataSize) + dataSize; } else { var sizeCalculator = codec.ValueSizeCalculator; int size = count * CodedOutputStream.ComputeRawVarint32Size(tag); for (int i = 0; i < count; i++) { size += sizeCalculator(ls[i]); } return size; } } public static void AddEntriesFrom(CodedInputStream input, MapFieldCodec codec, Dictionary map) { var adapter = new MapFieldCodec.MessageAdapter(codec); do { adapter.Reset(); input.ReadMessage(adapter); map.Add(adapter.Key, adapter.Value); } while (input.MaybeConsumeTag(codec.MapTag)); } public static void WriteTo(CodedOutputStream output, MapFieldCodec codec, Dictionary map) { var message = new MapFieldCodec.MessageAdapter(codec); foreach (var entry in map) { message.Key = entry.Key; message.Value = entry.Value; output.WriteTag(codec.MapTag); output.WriteMessage(message); } } public static int CalculateSize(MapFieldCodec codec, Dictionary map) { var message = new MapFieldCodec.MessageAdapter(codec); int size = 0; foreach (var entry in map) { message.Key = entry.Key; message.Value = entry.Value; size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag); size += CodedOutputStream.ComputeMessageSize(message); } return size; } } }