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