FieldSet.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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;
  36. using System.Collections.Generic;
  37. using Google.ProtocolBuffers.Collections;
  38. using Google.ProtocolBuffers.Descriptors;
  39. namespace Google.ProtocolBuffers {
  40. public interface IFieldDescriptorLite : IComparable<IFieldDescriptorLite> {
  41. bool IsRepeated { get; }
  42. bool IsRequired { get; }
  43. bool IsPacked { get; }
  44. bool IsExtension { get; }
  45. bool MessageSetWireFormat { get; } //field.ContainingType.Options.MessageSetWireFormat
  46. int FieldNumber { get; }
  47. string FullName { get; }
  48. IEnumLiteMap EnumType { get; }
  49. FieldType FieldType { get; }
  50. MappedType MappedType { get; }
  51. object DefaultValue { get; }
  52. }
  53. /// <summary>
  54. /// A class which represents an arbitrary set of fields of some message type.
  55. /// This is used to implement DynamicMessage, and also to represent extensions
  56. /// in GeneratedMessage. This class is internal, since outside users should probably
  57. /// be using DynamicMessage.
  58. ///
  59. /// As in the Java implementation, this class goes against the rest of the framework
  60. /// in terms of mutability. Instead of having a mutable Builder class and an immutable
  61. /// FieldSet class, FieldSet just has a MakeImmutable() method. This is safe so long as
  62. /// all callers are careful not to let a mutable FieldSet escape into the open. This would
  63. /// be impossible to guarantee if this were a public class, of course.
  64. ///
  65. /// All repeated fields are stored as IList[object] even
  66. /// TODO(jonskeet): Finish this comment!
  67. /// </summary>
  68. internal sealed class FieldSet {
  69. private static readonly FieldSet defaultInstance = new FieldSet(new Dictionary<IFieldDescriptorLite, object>()).MakeImmutable();
  70. private IDictionary<IFieldDescriptorLite, object> fields;
  71. private FieldSet(IDictionary<IFieldDescriptorLite, object> fields) {
  72. this.fields = fields;
  73. }
  74. public static FieldSet CreateInstance() {
  75. // Use SortedList to keep fields in the canonical order
  76. return new FieldSet(new SortedList<IFieldDescriptorLite, object>());
  77. }
  78. /// <summary>
  79. /// Makes this FieldSet immutable, and returns it for convenience. Any
  80. /// mutable repeated fields are made immutable, as well as the map itself.
  81. /// </summary>
  82. internal FieldSet MakeImmutable() {
  83. // First check if we have any repeated values
  84. bool hasRepeats = false;
  85. foreach (object value in fields.Values) {
  86. IList<object> list = value as IList<object>;
  87. if (list != null && !list.IsReadOnly) {
  88. hasRepeats = true;
  89. break;
  90. }
  91. }
  92. if (hasRepeats) {
  93. var tmp = new SortedList<IFieldDescriptorLite, object>();
  94. foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
  95. IList<object> list = entry.Value as IList<object>;
  96. tmp[entry.Key] = list == null ? entry.Value : Lists.AsReadOnly(list);
  97. }
  98. fields = tmp;
  99. }
  100. fields = Dictionaries.AsReadOnly(fields);
  101. return this;
  102. }
  103. /// <summary>
  104. /// Returns the default, immutable instance with no fields defined.
  105. /// </summary>
  106. internal static FieldSet DefaultInstance {
  107. get { return defaultInstance; }
  108. }
  109. /// <summary>
  110. /// Returns an immutable mapping of fields. Note that although the mapping itself
  111. /// is immutable, the entries may not be (i.e. any repeated values are represented by
  112. /// mutable lists). The behaviour is not specified if the contents are mutated.
  113. /// </summary>
  114. internal IDictionary<IFieldDescriptorLite, object> AllFields {
  115. get { return Dictionaries.AsReadOnly(fields); }
  116. }
  117. #if !LITE
  118. /// <summary>
  119. /// Force coercion to full descriptor dictionary.
  120. /// </summary>
  121. internal IDictionary<Descriptors.FieldDescriptor, object> AllFieldDescriptors {
  122. get {
  123. SortedList<Descriptors.FieldDescriptor, object> copy = new SortedList<Google.ProtocolBuffers.Descriptors.FieldDescriptor, object>();
  124. foreach (KeyValuePair<IFieldDescriptorLite, object> fd in fields)
  125. copy.Add((Descriptors.FieldDescriptor)fd.Key, fd.Value);
  126. return Dictionaries.AsReadOnly(copy);
  127. }
  128. }
  129. #endif
  130. /// <summary>
  131. /// See <see cref="IMessageLite.HasField"/>.
  132. /// </summary>
  133. public bool HasField(IFieldDescriptorLite field) {
  134. if (field.IsRepeated) {
  135. throw new ArgumentException("HasField() can only be called on non-repeated fields.");
  136. }
  137. return fields.ContainsKey(field);
  138. }
  139. /// <summary>
  140. /// Clears all fields.
  141. /// </summary>
  142. internal void Clear() {
  143. fields.Clear();
  144. }
  145. /// <summary>
  146. /// See <see cref="IMessageLite.Item(IFieldDescriptorLite)"/>
  147. /// </summary>
  148. /// <remarks>
  149. /// If the field is not set, the behaviour when fetching this property varies by field type:
  150. /// <list>
  151. /// <item>For singular message values, null is returned.</item>
  152. /// <item>For singular non-message values, the default value of the field is returned.</item>
  153. /// <item>For repeated values, an empty immutable list is returned. This will be compatible
  154. /// with IList[object], regardless of the type of the repeated item.</item>
  155. /// </list>
  156. /// This method returns null if the field is a singular message type
  157. /// and is not set; in this case it is up to the caller to fetch the
  158. /// message's default instance. For repeated fields of message types,
  159. /// an empty collection is returned. For repeated fields of non-message
  160. /// types, null is returned.
  161. /// <para />
  162. /// When setting this property, any list values are copied, and each element is checked
  163. /// to ensure it is of an appropriate type.
  164. /// </remarks>
  165. ///
  166. internal object this[IFieldDescriptorLite field] {
  167. get {
  168. object result;
  169. if (fields.TryGetValue(field, out result)) {
  170. return result;
  171. }
  172. if (field.MappedType == MappedType.Message) {
  173. if (field.IsRepeated) {
  174. return new List<object>();
  175. } else {
  176. return null;
  177. }
  178. }
  179. return field.DefaultValue;
  180. }
  181. set {
  182. if (field.IsRepeated) {
  183. List<object> list = value as List<object>;
  184. if (list == null) {
  185. throw new ArgumentException("Wrong object type used with protocol message reflection.");
  186. }
  187. // Wrap the contents in a new list so that the caller cannot change
  188. // the list's contents after setting it.
  189. List<object> newList = new List<object>(list);
  190. foreach (object element in newList) {
  191. VerifyType(field, element);
  192. }
  193. value = newList;
  194. }
  195. else {
  196. VerifyType(field, value);
  197. }
  198. fields[field] = value;
  199. }
  200. }
  201. /// <summary>
  202. /// See <see cref="IMessageLite.Item(IFieldDescriptorLite,int)" />
  203. /// </summary>
  204. internal object this[IFieldDescriptorLite field, int index] {
  205. get {
  206. if (!field.IsRepeated) {
  207. throw new ArgumentException("Indexer specifying field and index can only be called on repeated fields.");
  208. }
  209. return ((IList<object>) this[field])[index];
  210. }
  211. set {
  212. if (!field.IsRepeated) {
  213. throw new ArgumentException("Indexer specifying field and index can only be called on repeated fields.");
  214. }
  215. VerifyType(field, value);
  216. object list;
  217. if (!fields.TryGetValue(field, out list)) {
  218. throw new ArgumentOutOfRangeException();
  219. }
  220. ((IList<object>) list)[index] = value;
  221. }
  222. }
  223. /// <summary>
  224. /// See <see cref="IBuilder{TMessage, TBuilder}.AddRepeatedField" />
  225. /// </summary>
  226. internal void AddRepeatedField(IFieldDescriptorLite field, object value) {
  227. if (!field.IsRepeated) {
  228. throw new ArgumentException("AddRepeatedField can only be called on repeated fields.");
  229. }
  230. VerifyType(field, value);
  231. object list;
  232. if (!fields.TryGetValue(field, out list)) {
  233. list = new List<object>();
  234. fields[field] = list;
  235. }
  236. ((IList<object>) list).Add(value);
  237. }
  238. /// <summary>
  239. /// Returns an enumerator for the field map. Used to write the fields out.
  240. /// </summary>
  241. internal IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> GetEnumerator() {
  242. return fields.GetEnumerator();
  243. }
  244. /// <summary>
  245. /// See <see cref="IMessageLite.IsInitialized" />
  246. /// </summary>
  247. /// <remarks>
  248. /// Since FieldSet itself does not have any way of knowing about
  249. /// required fields that aren't actually present in the set, it is up
  250. /// to the caller to check for genuinely required fields. This property
  251. /// merely checks that any messages present are themselves initialized.
  252. /// </remarks>
  253. internal bool IsInitialized {
  254. get {
  255. foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
  256. IFieldDescriptorLite field = entry.Key;
  257. if (field.MappedType == MappedType.Message) {
  258. if (field.IsRepeated) {
  259. foreach(IMessageLite message in (IEnumerable) entry.Value) {
  260. if (!message.IsInitialized) {
  261. return false;
  262. }
  263. }
  264. } else {
  265. if (!((IMessageLite)entry.Value).IsInitialized) {
  266. return false;
  267. }
  268. }
  269. }
  270. }
  271. return true;
  272. }
  273. }
  274. /// <summary>
  275. /// Verifies whether all the required fields in the specified message
  276. /// descriptor are present in this field set, as well as whether
  277. /// all the embedded messages are themselves initialized.
  278. /// </summary>
  279. internal bool IsInitializedWithRespectTo(IEnumerable typeFields) {
  280. foreach (IFieldDescriptorLite field in typeFields) {
  281. if (field.IsRequired && !HasField(field)) {
  282. return false;
  283. }
  284. }
  285. return IsInitialized;
  286. }
  287. /// <summary>
  288. /// See <see cref="IBuilder{TMessage, TBuilder}.ClearField" />
  289. /// </summary>
  290. public void ClearField(IFieldDescriptorLite field) {
  291. fields.Remove(field);
  292. }
  293. /// <summary>
  294. /// See <see cref="IMessageLite.GetRepeatedFieldCount" />
  295. /// </summary>
  296. public int GetRepeatedFieldCount(IFieldDescriptorLite field) {
  297. if (!field.IsRepeated) {
  298. throw new ArgumentException("GetRepeatedFieldCount() can only be called on repeated fields.");
  299. }
  300. return ((IList<object>) this[field]).Count;
  301. }
  302. #if !LITE
  303. /// <summary>
  304. /// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessageLite)" />
  305. /// </summary>
  306. public void MergeFrom(IMessage other) {
  307. foreach (KeyValuePair<Descriptors.FieldDescriptor, object> fd in other.AllFields)
  308. MergeField(fd.Key, fd.Value);
  309. }
  310. #endif
  311. /// <summary>
  312. /// Implementation of both <c>MergeFrom</c> methods.
  313. /// </summary>
  314. /// <param name="otherFields"></param>
  315. public void MergeFrom(FieldSet other) {
  316. // Note: We don't attempt to verify that other's fields have valid
  317. // types. Doing so would be a losing battle. We'd have to verify
  318. // all sub-messages as well, and we'd have to make copies of all of
  319. // them to insure that they don't change after verification (since
  320. // the IMessageLite interface itself cannot enforce immutability of
  321. // implementations).
  322. // TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
  323. // which allows people to make secure deep copies of messages.
  324. foreach (KeyValuePair<IFieldDescriptorLite, object> entry in other.fields) {
  325. MergeField(entry.Key, entry.Value);
  326. }
  327. }
  328. private void MergeField(IFieldDescriptorLite field, object mergeValue) {
  329. object existingValue;
  330. fields.TryGetValue(field, out existingValue);
  331. if (field.IsRepeated) {
  332. if (existingValue == null) {
  333. existingValue = new List<object>();
  334. fields[field] = existingValue;
  335. }
  336. IList<object> list = (IList<object>) existingValue;
  337. foreach (object otherValue in (IEnumerable)mergeValue) {
  338. list.Add(otherValue);
  339. }
  340. } else if (field.MappedType == MappedType.Message && existingValue != null) {
  341. IMessageLite existingMessage = (IMessageLite)existingValue;
  342. IMessageLite merged = existingMessage.WeakToBuilder()
  343. .WeakMergeFrom((IMessageLite)mergeValue)
  344. .WeakBuild();
  345. this[field] = merged;
  346. } else {
  347. this[field] = mergeValue;
  348. }
  349. }
  350. /// <summary>
  351. /// See <see cref="IMessageLite.WriteTo(CodedOutputStream)" />.
  352. /// </summary>
  353. public void WriteTo(CodedOutputStream output) {
  354. foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
  355. WriteField(entry.Key, entry.Value, output);
  356. }
  357. }
  358. /// <summary>
  359. /// Writes a single field to a CodedOutputStream.
  360. /// </summary>
  361. public void WriteField(IFieldDescriptorLite field, Object value, CodedOutputStream output) {
  362. if (field.IsExtension && field.MessageSetWireFormat) {
  363. output.WriteMessageSetExtension(field.FieldNumber, (IMessageLite) value);
  364. } else {
  365. if (field.IsRepeated) {
  366. IEnumerable valueList = (IEnumerable) value;
  367. if (field.IsPacked) {
  368. output.WriteTag(field.FieldNumber, WireFormat.WireType.LengthDelimited);
  369. // Compute the total data size so the length can be written.
  370. int dataSize = 0;
  371. foreach (object element in valueList) {
  372. dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
  373. }
  374. output.WriteRawVarint32((uint)dataSize);
  375. // Write the data itself, without any tags.
  376. foreach (object element in valueList) {
  377. output.WriteFieldNoTag(field.FieldType, element);
  378. }
  379. } else {
  380. foreach (object element in valueList) {
  381. output.WriteField(field.FieldType, field.FieldNumber, element);
  382. }
  383. }
  384. } else {
  385. output.WriteField(field.FieldType, field.FieldNumber, value);
  386. }
  387. }
  388. }
  389. /// <summary>
  390. /// See <see cref="IMessageLite.SerializedSize" />. It's up to the caller to
  391. /// cache the resulting size if desired.
  392. /// </summary>
  393. public int SerializedSize {
  394. get {
  395. int size = 0;
  396. foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
  397. IFieldDescriptorLite field = entry.Key;
  398. object value = entry.Value;
  399. if (field.IsExtension && field.MessageSetWireFormat) {
  400. size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessageLite)value);
  401. } else {
  402. if (field.IsRepeated) {
  403. IEnumerable valueList = (IEnumerable)value;
  404. if (field.IsPacked) {
  405. int dataSize = 0;
  406. foreach (object element in valueList) {
  407. dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
  408. }
  409. size += dataSize + CodedOutputStream.ComputeTagSize(field.FieldNumber) + CodedOutputStream.ComputeRawVarint32Size((uint)dataSize);
  410. } else {
  411. foreach (object element in valueList) {
  412. size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
  413. }
  414. }
  415. } else {
  416. size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, value);
  417. }
  418. }
  419. }
  420. return size;
  421. }
  422. }
  423. /// <summary>
  424. /// Verifies that the given object is of the correct type to be a valid
  425. /// value for the given field.
  426. /// </summary>
  427. /// <remarks>
  428. /// For repeated fields, this checks if the object is of the right
  429. /// element type, not whether it's a list.
  430. /// </remarks>
  431. /// <exception cref="ArgumentException">The value is not of the right type.</exception>
  432. /// <exception cref="ArgumentNullException">The value is null.</exception>
  433. private static void VerifyType(IFieldDescriptorLite field, object value) {
  434. ThrowHelper.ThrowIfNull(value, "value");
  435. bool isValid = false;
  436. switch (field.MappedType) {
  437. case MappedType.Int32: isValid = value is int; break;
  438. case MappedType.Int64: isValid = value is long; break;
  439. case MappedType.UInt32: isValid = value is uint; break;
  440. case MappedType.UInt64: isValid = value is ulong; break;
  441. case MappedType.Single: isValid = value is float; break;
  442. case MappedType.Double: isValid = value is double; break;
  443. case MappedType.Boolean: isValid = value is bool; break;
  444. case MappedType.String: isValid = value is string; break;
  445. case MappedType.ByteString: isValid = value is ByteString; break;
  446. case MappedType.Enum:
  447. IEnumLite enumValue = value as IEnumLite;
  448. isValid = enumValue != null && field.EnumType.IsValidValue(enumValue);
  449. break;
  450. case MappedType.Message:
  451. IMessageLite messageValue = value as IMessageLite;
  452. isValid = messageValue != null;
  453. #if !LITE
  454. if (isValid && messageValue is IMessage && field is FieldDescriptor) {
  455. isValid = ((IMessage) messageValue).DescriptorForType == ((FieldDescriptor) field).MessageType;
  456. }
  457. #endif
  458. break;
  459. }
  460. if (!isValid) {
  461. // When chaining calls to SetField(), it can be hard to tell from
  462. // the stack trace which exact call failed, since the whole chain is
  463. // considered one line of code. So, let's make sure to include the
  464. // field name and other useful info in the exception.
  465. string message = "Wrong object type used with protocol message reflection.";
  466. #if !LITE
  467. Google.ProtocolBuffers.Descriptors.FieldDescriptor fieldinfo = field as Google.ProtocolBuffers.Descriptors.FieldDescriptor;
  468. if (fieldinfo != null) {
  469. message += "Message type \"" + fieldinfo.ContainingType.FullName;
  470. message += "\", field \"" + (fieldinfo.IsExtension ? fieldinfo.FullName : fieldinfo.Name);
  471. message += "\", value was type \"" + value.GetType().Name + "\".";
  472. }
  473. #endif
  474. throw new ArgumentException(message);
  475. }
  476. }
  477. }
  478. }