PageRenderTime 24ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ProtocolBuffers/AbstractMessage.cs

https://code.google.com/p/protobuf-csharp-port/
C# | 291 lines | 193 code | 24 blank | 74 comment | 21 complexity | 8445e80ff41c55d0bf4bc3d3ce8e81cf 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.Collections;
  35. using System.Collections.Generic;
  36. using System.IO;
  37. using System.Text;
  38. using Google.ProtocolBuffers.Collections;
  39. using Google.ProtocolBuffers.Descriptors;
  40. namespace Google.ProtocolBuffers
  41. {
  42. /// <summary>
  43. /// Implementation of the non-generic IMessage interface as far as possible.
  44. /// </summary>
  45. public abstract partial class AbstractMessage<TMessage, TBuilder> : AbstractMessageLite<TMessage, TBuilder>,
  46. IMessage<TMessage, TBuilder>
  47. where TMessage : AbstractMessage<TMessage, TBuilder>
  48. where TBuilder : AbstractBuilder<TMessage, TBuilder>
  49. {
  50. /// <summary>
  51. /// The serialized size if it's already been computed, or null
  52. /// if we haven't computed it yet.
  53. /// </summary>
  54. private int? memoizedSize = null;
  55. #region Unimplemented members of IMessage
  56. public abstract MessageDescriptor DescriptorForType { get; }
  57. public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
  58. public abstract bool HasField(FieldDescriptor field);
  59. public abstract object this[FieldDescriptor field] { get; }
  60. public abstract int GetRepeatedFieldCount(FieldDescriptor field);
  61. public abstract object this[FieldDescriptor field, int index] { get; }
  62. public abstract UnknownFieldSet UnknownFields { get; }
  63. #endregion
  64. /// <summary>
  65. /// Returns true iff all required fields in the message and all embedded
  66. /// messages are set.
  67. /// </summary>
  68. public override bool IsInitialized
  69. {
  70. get
  71. {
  72. // Check that all required fields are present.
  73. foreach (FieldDescriptor field in DescriptorForType.Fields)
  74. {
  75. if (field.IsRequired && !HasField(field))
  76. {
  77. return false;
  78. }
  79. }
  80. // Check that embedded messages are initialized.
  81. foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields)
  82. {
  83. FieldDescriptor field = entry.Key;
  84. if (field.MappedType == MappedType.Message)
  85. {
  86. if (field.IsRepeated)
  87. {
  88. // We know it's an IList<T>, but not the exact type - so
  89. // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
  90. foreach (IMessageLite element in (IEnumerable) entry.Value)
  91. {
  92. if (!element.IsInitialized)
  93. {
  94. return false;
  95. }
  96. }
  97. }
  98. else
  99. {
  100. if (!((IMessageLite) entry.Value).IsInitialized)
  101. {
  102. return false;
  103. }
  104. }
  105. }
  106. }
  107. return true;
  108. }
  109. }
  110. public override sealed string ToString()
  111. {
  112. return TextFormat.PrintToString(this);
  113. }
  114. public override sealed void PrintTo(TextWriter writer)
  115. {
  116. TextFormat.Print(this, writer);
  117. }
  118. /// <summary>
  119. /// Serializes the message and writes it to the given output stream.
  120. /// This does not flush or close the stream.
  121. /// </summary>
  122. /// <remarks>
  123. /// Protocol Buffers are not self-delimiting. Therefore, if you write
  124. /// any more data to the stream after the message, you must somehow ensure
  125. /// that the parser on the receiving end does not interpret this as being
  126. /// part of the protocol message. One way of doing this is by writing the size
  127. /// of the message before the data, then making sure you limit the input to
  128. /// that size when receiving the data. Alternatively, use WriteDelimitedTo(Stream).
  129. /// </remarks>
  130. public override void WriteTo(ICodedOutputStream output)
  131. {
  132. foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields)
  133. {
  134. FieldDescriptor field = entry.Key;
  135. if (field.IsRepeated)
  136. {
  137. // We know it's an IList<T>, but not the exact type - so
  138. // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
  139. IEnumerable valueList = (IEnumerable) entry.Value;
  140. if (field.IsPacked)
  141. {
  142. output.WritePackedArray(field.FieldType, field.FieldNumber, field.Name, valueList);
  143. }
  144. else
  145. {
  146. output.WriteArray(field.FieldType, field.FieldNumber, field.Name, valueList);
  147. }
  148. }
  149. else
  150. {
  151. output.WriteField(field.FieldType, field.FieldNumber, field.Name, entry.Value);
  152. }
  153. }
  154. UnknownFieldSet unknownFields = UnknownFields;
  155. if (DescriptorForType.Options.MessageSetWireFormat)
  156. {
  157. unknownFields.WriteAsMessageSetTo(output);
  158. }
  159. else
  160. {
  161. unknownFields.WriteTo(output);
  162. }
  163. }
  164. /// <summary>
  165. /// Returns the number of bytes required to encode this message.
  166. /// The result is only computed on the first call and memoized after that.
  167. /// </summary>
  168. public override int SerializedSize
  169. {
  170. get
  171. {
  172. if (memoizedSize != null)
  173. {
  174. return memoizedSize.Value;
  175. }
  176. int size = 0;
  177. foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields)
  178. {
  179. FieldDescriptor field = entry.Key;
  180. if (field.IsRepeated)
  181. {
  182. IEnumerable valueList = (IEnumerable) entry.Value;
  183. if (field.IsPacked)
  184. {
  185. int dataSize = 0;
  186. foreach (object element in valueList)
  187. {
  188. dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
  189. }
  190. size += dataSize;
  191. size += CodedOutputStream.ComputeTagSize(field.FieldNumber);
  192. size += CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);
  193. }
  194. else
  195. {
  196. foreach (object element in valueList)
  197. {
  198. size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
  199. }
  200. }
  201. }
  202. else
  203. {
  204. size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, entry.Value);
  205. }
  206. }
  207. UnknownFieldSet unknownFields = UnknownFields;
  208. if (DescriptorForType.Options.MessageSetWireFormat)
  209. {
  210. size += unknownFields.SerializedSizeAsMessageSet;
  211. }
  212. else
  213. {
  214. size += unknownFields.SerializedSize;
  215. }
  216. memoizedSize = size;
  217. return size;
  218. }
  219. }
  220. /// <summary>
  221. /// Compares the specified object with this message for equality.
  222. /// Returns true iff the given object is a message of the same type
  223. /// (as defined by DescriptorForType) and has identical values
  224. /// for all its fields.
  225. /// </summary>
  226. public override bool Equals(object other)
  227. {
  228. if (other == this)
  229. {
  230. return true;
  231. }
  232. IMessage otherMessage = other as IMessage;
  233. if (otherMessage == null || otherMessage.DescriptorForType != DescriptorForType)
  234. {
  235. return false;
  236. }
  237. return Dictionaries.Equals(AllFields, otherMessage.AllFields) &&
  238. UnknownFields.Equals(otherMessage.UnknownFields);
  239. }
  240. /// <summary>
  241. /// Returns the hash code value for this message.
  242. /// TODO(jonskeet): Specify the hash algorithm, but better than the Java one!
  243. /// </summary>
  244. public override int GetHashCode()
  245. {
  246. int hash = 41;
  247. hash = (19*hash) + DescriptorForType.GetHashCode();
  248. hash = (53*hash) + Dictionaries.GetHashCode(AllFields);
  249. hash = (29*hash) + UnknownFields.GetHashCode();
  250. return hash;
  251. }
  252. #region Explicit Members
  253. IBuilder IMessage.WeakCreateBuilderForType()
  254. {
  255. return CreateBuilderForType();
  256. }
  257. IBuilder IMessage.WeakToBuilder()
  258. {
  259. return ToBuilder();
  260. }
  261. IMessage IMessage.WeakDefaultInstanceForType
  262. {
  263. get { return DefaultInstanceForType; }
  264. }
  265. #endregion
  266. }
  267. }