UnknownField.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Collections.Generic;
  36. using System.Collections.ObjectModel;
  37. using Google.ProtocolBuffers.Collections;
  38. namespace Google.ProtocolBuffers
  39. {
  40. /// <summary>
  41. /// Represents a single field in an UnknownFieldSet.
  42. ///
  43. /// An UnknownField consists of five lists of values. The lists correspond
  44. /// to the five "wire types" used in the protocol buffer binary format.
  45. /// The wire type of each field can be determined from the encoded form alone,
  46. /// without knowing the field's declared type. So, we are able to parse
  47. /// unknown values at least this far and separate them. Normally, only one
  48. /// of the five lists will contain any values, since it is impossible to
  49. /// define a valid message type that declares two different types for the
  50. /// same field number. However, the code is designed to allow for the case
  51. /// where the same unknown field number is encountered using multiple different
  52. /// wire types.
  53. ///
  54. /// UnknownField is an immutable class. To construct one, you must use an
  55. /// UnknownField.Builder.
  56. /// </summary>
  57. public sealed class UnknownField
  58. {
  59. public const string UnknownFieldName = "unknown_field";
  60. private static readonly UnknownField defaultInstance = CreateBuilder().Build();
  61. private readonly ReadOnlyCollection<ulong> varintList;
  62. private readonly ReadOnlyCollection<uint> fixed32List;
  63. private readonly ReadOnlyCollection<ulong> fixed64List;
  64. private readonly ReadOnlyCollection<ByteString> lengthDelimitedList;
  65. private readonly ReadOnlyCollection<UnknownFieldSet> groupList;
  66. private UnknownField(ReadOnlyCollection<ulong> varintList,
  67. ReadOnlyCollection<uint> fixed32List,
  68. ReadOnlyCollection<ulong> fixed64List,
  69. ReadOnlyCollection<ByteString> lengthDelimitedList,
  70. ReadOnlyCollection<UnknownFieldSet> groupList)
  71. {
  72. this.varintList = varintList;
  73. this.fixed32List = fixed32List;
  74. this.fixed64List = fixed64List;
  75. this.lengthDelimitedList = lengthDelimitedList;
  76. this.groupList = groupList;
  77. }
  78. public static UnknownField DefaultInstance
  79. {
  80. get { return defaultInstance; }
  81. }
  82. /// <summary>
  83. /// The list of varint values for this field.
  84. /// </summary>
  85. public IList<ulong> VarintList
  86. {
  87. get { return varintList; }
  88. }
  89. /// <summary>
  90. /// The list of fixed32 values for this field.
  91. /// </summary>
  92. public IList<uint> Fixed32List
  93. {
  94. get { return fixed32List; }
  95. }
  96. /// <summary>
  97. /// The list of fixed64 values for this field.
  98. /// </summary>
  99. public IList<ulong> Fixed64List
  100. {
  101. get { return fixed64List; }
  102. }
  103. /// <summary>
  104. /// The list of length-delimited values for this field.
  105. /// </summary>
  106. public IList<ByteString> LengthDelimitedList
  107. {
  108. get { return lengthDelimitedList; }
  109. }
  110. /// <summary>
  111. /// The list of embedded group values for this field. These
  112. /// are represented using UnknownFieldSets rather than Messages
  113. /// since the group's type is presumably unknown.
  114. /// </summary>
  115. public IList<UnknownFieldSet> GroupList
  116. {
  117. get { return groupList; }
  118. }
  119. public override bool Equals(object other)
  120. {
  121. if (ReferenceEquals(this, other))
  122. {
  123. return true;
  124. }
  125. UnknownField otherField = other as UnknownField;
  126. return otherField != null
  127. && Lists.Equals(varintList, otherField.varintList)
  128. && Lists.Equals(fixed32List, otherField.fixed32List)
  129. && Lists.Equals(fixed64List, otherField.fixed64List)
  130. && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList)
  131. && Lists.Equals(groupList, otherField.groupList);
  132. }
  133. public override int GetHashCode()
  134. {
  135. int hash = 43;
  136. hash = hash*47 + Lists.GetHashCode(varintList);
  137. hash = hash*47 + Lists.GetHashCode(fixed32List);
  138. hash = hash*47 + Lists.GetHashCode(fixed64List);
  139. hash = hash*47 + Lists.GetHashCode(lengthDelimitedList);
  140. hash = hash*47 + Lists.GetHashCode(groupList);
  141. return hash;
  142. }
  143. /// <summary>
  144. /// Constructs a new Builder.
  145. /// </summary>
  146. public static Builder CreateBuilder()
  147. {
  148. return new Builder();
  149. }
  150. /// <summary>
  151. /// Constructs a new Builder and initializes it to a copy of <paramref name="copyFrom"/>.
  152. /// </summary>
  153. public static Builder CreateBuilder(UnknownField copyFrom)
  154. {
  155. return new Builder().MergeFrom(copyFrom);
  156. }
  157. /// <summary>
  158. /// Serializes the field, including the field number, and writes it to
  159. /// <paramref name="output"/>.
  160. /// </summary>
  161. public void WriteTo(int fieldNumber, CodedOutputStream output)
  162. {
  163. foreach (ulong value in varintList)
  164. {
  165. output.WriteUInt64(fieldNumber, UnknownFieldName, value);
  166. }
  167. foreach (uint value in fixed32List)
  168. {
  169. output.WriteFixed32(fieldNumber, UnknownFieldName, value);
  170. }
  171. foreach (ulong value in fixed64List)
  172. {
  173. output.WriteFixed64(fieldNumber, UnknownFieldName, value);
  174. }
  175. foreach (ByteString value in lengthDelimitedList)
  176. {
  177. output.WriteBytes(fieldNumber, UnknownFieldName, value);
  178. }
  179. foreach (UnknownFieldSet value in groupList)
  180. {
  181. #pragma warning disable 0612
  182. output.WriteUnknownGroup(fieldNumber, UnknownFieldName, value);
  183. #pragma warning restore 0612
  184. }
  185. }
  186. /// <summary>
  187. /// Computes the number of bytes required to encode this field, including field
  188. /// number.
  189. /// </summary>
  190. public int GetSerializedSize(int fieldNumber)
  191. {
  192. int result = 0;
  193. foreach (ulong value in varintList)
  194. {
  195. result += CodedOutputStream.ComputeUInt64Size(fieldNumber, value);
  196. }
  197. foreach (uint value in fixed32List)
  198. {
  199. result += CodedOutputStream.ComputeFixed32Size(fieldNumber, value);
  200. }
  201. foreach (ulong value in fixed64List)
  202. {
  203. result += CodedOutputStream.ComputeFixed64Size(fieldNumber, value);
  204. }
  205. foreach (ByteString value in lengthDelimitedList)
  206. {
  207. result += CodedOutputStream.ComputeBytesSize(fieldNumber, value);
  208. }
  209. foreach (UnknownFieldSet value in groupList)
  210. {
  211. #pragma warning disable 0612
  212. result += CodedOutputStream.ComputeUnknownGroupSize(fieldNumber, value);
  213. #pragma warning restore 0612
  214. }
  215. return result;
  216. }
  217. /// <summary>
  218. /// Serializes the length-delimited values of the field, including field
  219. /// number, and writes them to <paramref name="output"/> using the MessageSet wire format.
  220. /// </summary>
  221. /// <param name="fieldNumber"></param>
  222. /// <param name="output"></param>
  223. public void WriteAsMessageSetExtensionTo(int fieldNumber, CodedOutputStream output)
  224. {
  225. foreach (ByteString value in lengthDelimitedList)
  226. {
  227. output.WriteRawMessageSetExtension(fieldNumber, value);
  228. }
  229. }
  230. /// <summary>
  231. /// Get the number of bytes required to encode this field, incuding field number,
  232. /// using the MessageSet wire format.
  233. /// </summary>
  234. public int GetSerializedSizeAsMessageSetExtension(int fieldNumber)
  235. {
  236. int result = 0;
  237. foreach (ByteString value in lengthDelimitedList)
  238. {
  239. result += CodedOutputStream.ComputeRawMessageSetExtensionSize(fieldNumber, value);
  240. }
  241. return result;
  242. }
  243. /// <summary>
  244. /// Used to build instances of UnknownField.
  245. /// </summary>
  246. public sealed class Builder
  247. {
  248. private List<ulong> varintList;
  249. private List<uint> fixed32List;
  250. private List<ulong> fixed64List;
  251. private List<ByteString> lengthDelimitedList;
  252. private List<UnknownFieldSet> groupList;
  253. /// <summary>
  254. /// Builds the field. After building, the builder is reset to an empty
  255. /// state. (This is actually easier than making it unusable.)
  256. /// </summary>
  257. public UnknownField Build()
  258. {
  259. return new UnknownField(MakeReadOnly(ref varintList),
  260. MakeReadOnly(ref fixed32List),
  261. MakeReadOnly(ref fixed64List),
  262. MakeReadOnly(ref lengthDelimitedList),
  263. MakeReadOnly(ref groupList));
  264. }
  265. /// <summary>
  266. /// Merge the values in <paramref name="other" /> into this field. For each list
  267. /// of values, <paramref name="other"/>'s values are append to the ones in this
  268. /// field.
  269. /// </summary>
  270. public Builder MergeFrom(UnknownField other)
  271. {
  272. varintList = AddAll(varintList, other.VarintList);
  273. fixed32List = AddAll(fixed32List, other.Fixed32List);
  274. fixed64List = AddAll(fixed64List, other.Fixed64List);
  275. lengthDelimitedList = AddAll(lengthDelimitedList, other.LengthDelimitedList);
  276. groupList = AddAll(groupList, other.GroupList);
  277. return this;
  278. }
  279. /// <summary>
  280. /// Returns a new list containing all of the given specified values from
  281. /// both the <paramref name="current"/> and <paramref name="extras"/> lists.
  282. /// If <paramref name="current" /> is null and <paramref name="extras"/> is empty,
  283. /// null is returned. Otherwise, either a new list is created (if <paramref name="current" />
  284. /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />.
  285. /// </summary>
  286. private static List<T> AddAll<T>(List<T> current, IList<T> extras)
  287. {
  288. if (extras.Count == 0)
  289. {
  290. return current;
  291. }
  292. if (current == null)
  293. {
  294. current = new List<T>(extras);
  295. }
  296. else
  297. {
  298. current.AddRange(extras);
  299. }
  300. return current;
  301. }
  302. /// <summary>
  303. /// Clears the contents of this builder.
  304. /// </summary>
  305. public Builder Clear()
  306. {
  307. varintList = null;
  308. fixed32List = null;
  309. fixed64List = null;
  310. lengthDelimitedList = null;
  311. groupList = null;
  312. return this;
  313. }
  314. /// <summary>
  315. /// Adds a varint value.
  316. /// </summary>
  317. [CLSCompliant(false)]
  318. public Builder AddVarint(ulong value)
  319. {
  320. varintList = Add(varintList, value);
  321. return this;
  322. }
  323. /// <summary>
  324. /// Adds a fixed32 value.
  325. /// </summary>
  326. [CLSCompliant(false)]
  327. public Builder AddFixed32(uint value)
  328. {
  329. fixed32List = Add(fixed32List, value);
  330. return this;
  331. }
  332. /// <summary>
  333. /// Adds a fixed64 value.
  334. /// </summary>
  335. [CLSCompliant(false)]
  336. public Builder AddFixed64(ulong value)
  337. {
  338. fixed64List = Add(fixed64List, value);
  339. return this;
  340. }
  341. /// <summary>
  342. /// Adds a length-delimited value.
  343. /// </summary>
  344. public Builder AddLengthDelimited(ByteString value)
  345. {
  346. lengthDelimitedList = Add(lengthDelimitedList, value);
  347. return this;
  348. }
  349. /// <summary>
  350. /// Adds an embedded group.
  351. /// </summary>
  352. /// <param name="value"></param>
  353. /// <returns></returns>
  354. public Builder AddGroup(UnknownFieldSet value)
  355. {
  356. groupList = Add(groupList, value);
  357. return this;
  358. }
  359. /// <summary>
  360. /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating
  361. /// a new list if <paramref name="list"/> is null. The list is returned - either
  362. /// the original reference or the new list.
  363. /// </summary>
  364. private static List<T> Add<T>(List<T> list, T value)
  365. {
  366. if (list == null)
  367. {
  368. list = new List<T>();
  369. }
  370. list.Add(value);
  371. return list;
  372. }
  373. /// <summary>
  374. /// Returns a read-only version of the given IList, and clears
  375. /// the field used for <paramref name="list"/>. If the value
  376. /// is null, an empty list is produced using Lists.Empty.
  377. /// </summary>
  378. /// <returns></returns>
  379. private static ReadOnlyCollection<T> MakeReadOnly<T>(ref List<T> list)
  380. {
  381. ReadOnlyCollection<T> ret = list == null ? Lists<T>.Empty : new ReadOnlyCollection<T>(list);
  382. list = null;
  383. return ret;
  384. }
  385. }
  386. }
  387. }