FieldSet.cs 25 KB

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