ProtobufUtils.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using XGame.Framework.Network.Protobuf;
  2. using System.Collections.Generic;
  3. namespace XGame.Framework.Network
  4. {
  5. public static class ProtobufUtils
  6. {
  7. /// <summary>
  8. /// 为了优化性能,返回的字节流头部预留10个字节给外部使用,外部可以把头部信息写入到这10个预留的位置中
  9. /// 实际是8个字节用于头部,2个字节在body存body长度,因此与proto无关的字节数为前10字节
  10. /// </summary>
  11. private const int HeadOffset = 10;
  12. public static readonly CodedOutputStream CodedOutput = new CodedOutputStream();
  13. public static readonly CodedInputStream CodedInput = new CodedInputStream();
  14. public static BytesWrapper CreateBytesWrapper(IMsgParser parsor)
  15. {
  16. CodedOutput.Buffer = SessionBufferPool.Acquire();
  17. CodedOutput.Reset(HeadOffset);
  18. parsor.WriteTo(CodedOutput);
  19. return BytesWrapperPool.Acquire(CodedOutput.Buffer, HeadOffset, (int)CodedOutput.Position - HeadOffset);
  20. }
  21. public static void ParseFrom(byte[] bytes, int offset, int size, IMsgParser parser)
  22. {
  23. CodedInput.Reset(bytes, offset, size);
  24. parser.MergeFrom(CodedInput);
  25. CodedInput.CheckReadEndOfStreamTag();
  26. }
  27. public static void WriteTo<T>(CodedOutputStream output, FieldCodec<T> codec, List<T> ls)
  28. {
  29. if (ls == null || ls.Count == 0)
  30. return;
  31. var writer = codec.ValueWriter;
  32. var tag = codec.Tag;
  33. if (codec.PackedRepeatedField)
  34. {
  35. uint size = (uint)CalculatePackedDataSize(codec, ls);
  36. output.WriteTag(tag);
  37. output.WriteRawVarint32(size);
  38. for (int i = 0, count = ls.Count; i < count; i++)
  39. {
  40. writer(output, ls[i]);
  41. }
  42. }
  43. else
  44. {
  45. for (int i = 0, count = ls.Count; i < count; i++)
  46. {
  47. output.WriteTag(tag);
  48. writer(output, ls[i]);
  49. }
  50. }
  51. }
  52. private static int CalculatePackedDataSize<T>(FieldCodec<T> codec, List<T> ls)
  53. {
  54. int fixedSize = codec.FixedSize;
  55. if (fixedSize == 0)
  56. {
  57. var calculator = codec.ValueSizeCalculator;
  58. int tmp = 0;
  59. for (int i = 0, count = ls.Count; i < count; i++)
  60. {
  61. tmp += calculator(ls[i]);
  62. }
  63. return tmp;
  64. }
  65. else
  66. {
  67. return fixedSize * ls.Count;
  68. }
  69. }
  70. public static void AddEntriesFrom<T>(CodedInputStream input, FieldCodec<T> codec,
  71. List<T> ls)
  72. {
  73. uint tag = input.LastTag;
  74. var reader = codec.ValueReader;
  75. if (FieldCodec<T>.IsPackedRepeatedField(tag))
  76. {
  77. int length = input.ReadLength();
  78. if (length > 0)
  79. {
  80. int oldLimit = input.PushLimit(length);
  81. while (!input.ReachedLimit)
  82. {
  83. ls.Add(reader(input));
  84. }
  85. input.PopLimit(oldLimit);
  86. }
  87. }
  88. else
  89. {
  90. do
  91. {
  92. ls.Add(reader(input));
  93. } while (input.MaybeConsumeTag(tag));
  94. }
  95. }
  96. public static int CalculateSize<T>(FieldCodec<T> codec, List<T> ls)
  97. {
  98. if (ls == null)
  99. {
  100. return 0;
  101. }
  102. int count = ls.Count;
  103. if (ls.Count == 0)
  104. {
  105. return 0;
  106. }
  107. uint tag = codec.Tag;
  108. if (codec.PackedRepeatedField)
  109. {
  110. int dataSize = CalculatePackedDataSize(codec, ls);
  111. return CodedOutputStream.ComputeRawVarint32Size(tag) +
  112. CodedOutputStream.ComputeLengthSize(dataSize) +
  113. dataSize;
  114. }
  115. else
  116. {
  117. var sizeCalculator = codec.ValueSizeCalculator;
  118. int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
  119. for (int i = 0; i < count; i++)
  120. {
  121. size += sizeCalculator(ls[i]);
  122. }
  123. return size;
  124. }
  125. }
  126. public static void AddEntriesFrom<TKey, TValue>(CodedInputStream input, MapFieldCodec<TKey, TValue> codec, Dictionary<TKey, TValue> map)
  127. {
  128. var adapter = new MapFieldCodec<TKey, TValue>.MessageAdapter(codec);
  129. do
  130. {
  131. adapter.Reset();
  132. input.ReadMessage(adapter);
  133. map.Add(adapter.Key, adapter.Value);
  134. } while (input.MaybeConsumeTag(codec.MapTag));
  135. }
  136. public static void WriteTo<TKey, TValue>(CodedOutputStream output, MapFieldCodec<TKey, TValue> codec, Dictionary<TKey, TValue> map)
  137. {
  138. var message = new MapFieldCodec<TKey, TValue>.MessageAdapter(codec);
  139. foreach (var entry in map)
  140. {
  141. message.Key = entry.Key;
  142. message.Value = entry.Value;
  143. output.WriteTag(codec.MapTag);
  144. output.WriteMessage(message);
  145. }
  146. }
  147. public static int CalculateSize<TKey, TValue>(MapFieldCodec<TKey, TValue> codec, Dictionary<TKey, TValue> map)
  148. {
  149. var message = new MapFieldCodec<TKey, TValue>.MessageAdapter(codec);
  150. int size = 0;
  151. foreach (var entry in map)
  152. {
  153. message.Key = entry.Key;
  154. message.Value = entry.Value;
  155. size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
  156. size += CodedOutputStream.ComputeMessageSize(message);
  157. }
  158. return size;
  159. }
  160. }
  161. }