PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ProtocolBuffers/FieldSet.cs

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