AbstractMessage.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.IO;
  20. using System.Text;
  21. using Google.ProtocolBuffers.Descriptors;
  22. namespace Google.ProtocolBuffers {
  23. /// <summary>
  24. /// Implementation of the non-generic IMessage interface as far as possible.
  25. /// </summary>
  26. public abstract class AbstractMessage : IMessage {
  27. // TODO(jonskeet): Cleaner to use a Nullable<int>?
  28. /// <summary>
  29. /// The serialized size if it's already been computed, or -1
  30. /// if we haven't computed it yet.
  31. /// </summary>
  32. private int memoizedSize = -1;
  33. #region Unimplemented members of IMessage
  34. public abstract MessageDescriptor DescriptorForType { get; }
  35. public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
  36. public abstract bool HasField(FieldDescriptor field);
  37. public abstract object this[FieldDescriptor field] { get; }
  38. public abstract int GetRepeatedFieldCount(FieldDescriptor field);
  39. public abstract object this[FieldDescriptor field, int index] { get; }
  40. public abstract UnknownFieldSet UnknownFields { get; }
  41. // FIXME
  42. IMessage IMessage.DefaultInstanceForType { get { return null; } }
  43. IBuilder IMessage.CreateBuilderForType() { return null; }
  44. #endregion
  45. public bool IsInitialized {
  46. get {
  47. // Check that all required fields are present.
  48. foreach (FieldDescriptor field in DescriptorForType.Fields) {
  49. if (field.IsRequired && !HasField(field)) {
  50. return false;
  51. }
  52. }
  53. // Check that embedded messages are initialized.
  54. foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
  55. FieldDescriptor field = entry.Key;
  56. if (field.MappedType == MappedType.Message) {
  57. if (field.IsRepeated) {
  58. // We know it's an IList<T>, but not the exact type - so
  59. // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
  60. foreach (IMessage element in (IEnumerable)entry.Value) {
  61. if (!element.IsInitialized) {
  62. return false;
  63. }
  64. }
  65. } else {
  66. if (!((IMessage)entry.Value).IsInitialized) {
  67. return false;
  68. }
  69. }
  70. }
  71. }
  72. return true;
  73. }
  74. }
  75. public sealed override string ToString() {
  76. return TextFormat.PrintToString(this);
  77. }
  78. public void WriteTo(CodedOutputStream output) {
  79. foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
  80. FieldDescriptor field = entry.Key;
  81. if (field.IsRepeated) {
  82. // We know it's an IList<T>, but not the exact type - so
  83. // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
  84. foreach (object element in (IEnumerable)entry.Value) {
  85. output.WriteField(field.FieldType, field.FieldNumber, element);
  86. }
  87. } else {
  88. output.WriteField(field.FieldType, field.FieldNumber, entry.Value);
  89. }
  90. }
  91. UnknownFieldSet unknownFields = UnknownFields;
  92. if (DescriptorForType.Options.IsMessageSetWireFormat) {
  93. unknownFields.WriteAsMessageSetTo(output);
  94. } else {
  95. unknownFields.WriteTo(output);
  96. }
  97. }
  98. public int SerializedSize {
  99. get {
  100. int size = memoizedSize;
  101. if (size != -1) {
  102. return size;
  103. }
  104. size = 0;
  105. foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
  106. FieldDescriptor field = entry.Key;
  107. if (field.IsRepeated) {
  108. foreach (object element in (IEnumerable)entry.Value) {
  109. size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
  110. }
  111. } else {
  112. size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, entry.Value);
  113. }
  114. }
  115. UnknownFieldSet unknownFields = UnknownFields;
  116. if (DescriptorForType.Options.IsMessageSetWireFormat) {
  117. size += unknownFields.SerializedSizeAsMessageSet;
  118. } else {
  119. size += unknownFields.SerializedSize;
  120. }
  121. memoizedSize = size;
  122. return size;
  123. }
  124. }
  125. public ByteString ToByteString() {
  126. ByteString.CodedBuilder output = new ByteString.CodedBuilder(SerializedSize);
  127. WriteTo(output.CodedOutput);
  128. return output.Build();
  129. }
  130. public byte[] ToByteArray() {
  131. byte[] result = new byte[SerializedSize];
  132. CodedOutputStream output = CodedOutputStream.CreateInstance(result);
  133. WriteTo(output);
  134. output.CheckNoSpaceLeft();
  135. return result;
  136. }
  137. public void WriteTo(Stream output) {
  138. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  139. WriteTo(codedOutput);
  140. codedOutput.Flush();
  141. }
  142. public override bool Equals(object other) {
  143. if (other == this) {
  144. return true;
  145. }
  146. IMessage otherMessage = other as IMessage;
  147. if (otherMessage == null || otherMessage.DescriptorForType != DescriptorForType) {
  148. return false;
  149. }
  150. // TODO(jonskeet): Check that dictionaries support equality appropriately
  151. // (I suspect they don't!)
  152. return AllFields.Equals(otherMessage.AllFields);
  153. }
  154. public override int GetHashCode() {
  155. int hash = 41;
  156. hash = (19 * hash) + DescriptorForType.GetHashCode();
  157. hash = (53 * hash) + AllFields.GetHashCode();
  158. return hash;
  159. }
  160. #region IMessage Members
  161. MessageDescriptor IMessage.DescriptorForType {
  162. get { throw new NotImplementedException(); }
  163. }
  164. IDictionary<FieldDescriptor, object> IMessage.AllFields {
  165. get { throw new NotImplementedException(); }
  166. }
  167. bool IMessage.HasField(FieldDescriptor field) {
  168. throw new NotImplementedException();
  169. }
  170. object IMessage.this[FieldDescriptor field] {
  171. get { throw new NotImplementedException(); }
  172. }
  173. int IMessage.GetRepeatedFieldCount(FieldDescriptor field) {
  174. throw new NotImplementedException();
  175. }
  176. object IMessage.this[FieldDescriptor field, int index] {
  177. get { throw new NotImplementedException(); }
  178. }
  179. UnknownFieldSet IMessage.UnknownFields {
  180. get { throw new NotImplementedException(); }
  181. }
  182. bool IMessage.IsInitialized {
  183. get { throw new NotImplementedException(); }
  184. }
  185. void IMessage.WriteTo(CodedOutputStream output) {
  186. throw new NotImplementedException();
  187. }
  188. int IMessage.SerializedSize {
  189. get { throw new NotImplementedException(); }
  190. }
  191. bool IMessage.Equals(object other) {
  192. throw new NotImplementedException();
  193. }
  194. int IMessage.GetHashCode() {
  195. throw new NotImplementedException();
  196. }
  197. string IMessage.ToString() {
  198. throw new NotImplementedException();
  199. }
  200. ByteString IMessage.ToByteString() {
  201. throw new NotImplementedException();
  202. }
  203. byte[] IMessage.ToByteArray() {
  204. throw new NotImplementedException();
  205. }
  206. void IMessage.WriteTo(Stream output) {
  207. throw new NotImplementedException();
  208. }
  209. #endregion
  210. }
  211. }