blob: d8b9e9e6c9656144e696a4290f555d6f71a524ff [file] [log] [blame]
Jon Skeet68036862008-10-22 13:30:34 +01001// 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.
16using System.Collections;
17using System.Collections.Generic;
18using System.IO;
19using Google.ProtocolBuffers.Collections;
20using Google.ProtocolBuffers.Descriptors;
21
22namespace Google.ProtocolBuffers {
23 /// <summary>
24 /// Implementation of the non-generic IMessage interface as far as possible.
25 /// </summary>
26 public abstract class AbstractMessage<TMessage, TBuilder> : IMessage<TMessage, TBuilder>
27 where TMessage : AbstractMessage<TMessage, TBuilder>
28 where TBuilder : AbstractBuilder<TMessage, TBuilder> {
29 /// <summary>
30 /// The serialized size if it's already been computed, or null
31 /// if we haven't computed it yet.
32 /// </summary>
33 private int? memoizedSize = null;
34
35 #region Unimplemented members of IMessage
36 public abstract MessageDescriptor DescriptorForType { get; }
37 public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
38 public abstract bool HasField(FieldDescriptor field);
39 public abstract object this[FieldDescriptor field] { get; }
40 public abstract int GetRepeatedFieldCount(FieldDescriptor field);
41 public abstract object this[FieldDescriptor field, int index] { get; }
42 public abstract UnknownFieldSet UnknownFields { get; }
43 public abstract TMessage DefaultInstanceForType { get; }
44 public abstract TBuilder CreateBuilderForType();
45 #endregion
46
47 public IBuilder WeakCreateBuilderForType() {
48 return CreateBuilderForType();
49 }
50
51 public IMessage WeakDefaultInstanceForType {
52 get { return DefaultInstanceForType; }
53 }
54
55 public virtual bool IsInitialized {
56 get {
57 // Check that all required fields are present.
58 foreach (FieldDescriptor field in DescriptorForType.Fields) {
59 if (field.IsRequired && !HasField(field)) {
60 return false;
61 }
62 }
63
64 // Check that embedded messages are initialized.
65 foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
66 FieldDescriptor field = entry.Key;
67 if (field.MappedType == MappedType.Message) {
68 if (field.IsRepeated) {
69 // We know it's an IList<T>, but not the exact type - so
70 // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
71 foreach (IMessage element in (IEnumerable) entry.Value) {
72 if (!element.IsInitialized) {
73 return false;
74 }
75 }
76 } else {
77 if (!((IMessage)entry.Value).IsInitialized) {
78 return false;
79 }
80 }
81 }
82 }
83 return true;
84 }
85 }
86
87 public sealed override string ToString() {
88 return TextFormat.PrintToString(this);
89 }
90
91 public virtual void WriteTo(CodedOutputStream output) {
92 foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
93 FieldDescriptor field = entry.Key;
94 if (field.IsRepeated) {
95 // We know it's an IList<T>, but not the exact type - so
96 // IEnumerable is the best we can do. (C# generics aren't covariant yet.)
97 foreach (object element in (IEnumerable)entry.Value) {
98 output.WriteField(field.FieldType, field.FieldNumber, element);
99 }
100 } else {
101 output.WriteField(field.FieldType, field.FieldNumber, entry.Value);
102 }
103 }
104
105 UnknownFieldSet unknownFields = UnknownFields;
106 if (DescriptorForType.Options.MessageSetWireFormat) {
107 unknownFields.WriteAsMessageSetTo(output);
108 } else {
109 unknownFields.WriteTo(output);
110 }
111 }
112
113 public virtual int SerializedSize {
114 get {
115 if (memoizedSize != null) {
116 return memoizedSize.Value;
117 }
118
119 int size = 0;
120 foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
121 FieldDescriptor field = entry.Key;
122 if (field.IsRepeated) {
123 foreach (object element in (IEnumerable) entry.Value) {
124 size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
125 }
126 } else {
127 size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, entry.Value);
128 }
129 }
130
131 UnknownFieldSet unknownFields = UnknownFields;
132 if (DescriptorForType.Options.MessageSetWireFormat) {
133 size += unknownFields.SerializedSizeAsMessageSet;
134 } else {
135 size += unknownFields.SerializedSize;
136 }
137
138 memoizedSize = size;
139 return size;
140 }
141 }
142
143 public ByteString ToByteString() {
144 ByteString.CodedBuilder output = new ByteString.CodedBuilder(SerializedSize);
145 WriteTo(output.CodedOutput);
146 return output.Build();
147 }
148
149 public byte[] ToByteArray() {
150 byte[] result = new byte[SerializedSize];
151 CodedOutputStream output = CodedOutputStream.CreateInstance(result);
152 WriteTo(output);
153 output.CheckNoSpaceLeft();
154 return result;
155 }
156
157 public void WriteTo(Stream output) {
158 CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
159 WriteTo(codedOutput);
160 codedOutput.Flush();
161 }
162
163 public override bool Equals(object other) {
164 if (other == this) {
165 return true;
166 }
167 IMessage otherMessage = other as IMessage;
168 if (otherMessage == null || otherMessage.DescriptorForType != DescriptorForType) {
169 return false;
170 }
171 return Dictionaries.Equals(AllFields, otherMessage.AllFields);
172 }
173
174 public override int GetHashCode() {
175 int hash = 41;
176 hash = (19 * hash) + DescriptorForType.GetHashCode();
177 hash = (53 * hash) + Dictionaries.GetHashCode(AllFields);
178 return hash;
179 }
180 }
181}