blob: 780d421333d030887ef5b9826eece12c483689e0 [file] [log] [blame]
Jon Skeet60c059b2008-10-23 21:17:56 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// http://github.com/jskeet/dotnet-protobufs/
4// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01005// http://code.google.com/p/protobuf/
6//
Jon Skeet60c059b2008-10-23 21:17:56 +01007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
Jon Skeet68036862008-10-22 13:30:34 +010010//
Jon Skeet60c059b2008-10-23 21:17:56 +010011// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010020//
Jon Skeet60c059b2008-10-23 21:17:56 +010021// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet68036862008-10-22 13:30:34 +010032using System;
33using System.Collections;
34using System.Collections.Generic;
35using System.IO;
36using Google.ProtocolBuffers.Descriptors;
37
38namespace Google.ProtocolBuffers {
39 /// <summary>
40 /// Implementation of the non-generic IMessage interface as far as possible.
41 /// </summary>
42 public abstract class AbstractBuilder<TMessage, TBuilder> : IBuilder<TMessage, TBuilder>
43 where TMessage : AbstractMessage<TMessage, TBuilder>
44 where TBuilder : AbstractBuilder<TMessage, TBuilder> {
45
46 protected abstract TBuilder ThisBuilder { get; }
47
48 #region Unimplemented members of IBuilder
49 public abstract UnknownFieldSet UnknownFields { get; set; }
50 public abstract TBuilder MergeFrom(TMessage other);
51 public abstract bool IsInitialized { get; }
52 public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
53 public abstract object this[FieldDescriptor field] { get; set; }
54 public abstract MessageDescriptor DescriptorForType { get; }
55 public abstract int GetRepeatedFieldCount(FieldDescriptor field);
56 public abstract object this[FieldDescriptor field, int index] { get; set; }
57 public abstract bool HasField(FieldDescriptor field);
58 public abstract TMessage Build();
59 public abstract TMessage BuildPartial();
60 public abstract TBuilder Clone();
61 public abstract TMessage DefaultInstanceForType { get; }
62 public abstract IBuilder CreateBuilderForField(FieldDescriptor field);
63 public abstract TBuilder ClearField(FieldDescriptor field);
64 public abstract TBuilder AddRepeatedField(FieldDescriptor field, object value);
65 #endregion
66
67 #region Implementation of methods which don't require type parameter information
68 public IMessage WeakBuild() {
69 return Build();
70 }
71
72 public IBuilder WeakAddRepeatedField(FieldDescriptor field, object value) {
73 return AddRepeatedField(field, value);
74 }
75
76 public IBuilder WeakClear() {
77 return Clear();
78 }
79
80 public IBuilder WeakMergeFrom(IMessage message) {
81 return MergeFrom(message);
82 }
83
84 public IBuilder WeakMergeFrom(CodedInputStream input) {
85 return MergeFrom(input);
86 }
87
88 public IBuilder WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
89 return MergeFrom(input, registry);
90 }
91
92 public IBuilder WeakMergeFrom(ByteString data) {
93 return MergeFrom(data);
94 }
95
96 public IBuilder WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
97 return MergeFrom(data, registry);
98 }
99
100 public IMessage WeakBuildPartial() {
101 return BuildPartial();
102 }
103
104 public IBuilder WeakClone() {
105 return Clone();
106 }
107
108 public IMessage WeakDefaultInstanceForType {
109 get { return DefaultInstanceForType; }
110 }
111
112 public IBuilder WeakClearField(FieldDescriptor field) {
113 return ClearField(field);
114 }
115 #endregion
116
117 public TBuilder SetUnknownFields(UnknownFieldSet fields) {
118 UnknownFields = fields;
119 return ThisBuilder;
120 }
121
122 public virtual TBuilder Clear() {
123 foreach(FieldDescriptor field in AllFields.Keys) {
124 ClearField(field);
125 }
126 return ThisBuilder;
127 }
128
129 public virtual TBuilder MergeFrom(IMessage other) {
130 if (other.DescriptorForType != DescriptorForType) {
131 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
132 }
133
134 // Note: We don't attempt to verify that other's fields have valid
135 // types. Doing so would be a losing battle. We'd have to verify
136 // all sub-messages as well, and we'd have to make copies of all of
137 // them to insure that they don't change after verification (since
138 // the Message interface itself cannot enforce immutability of
139 // implementations).
140 // TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
141 // which allows people to make secure deep copies of messages.
142 foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields) {
143 FieldDescriptor field = entry.Key;
144 if (field.IsRepeated) {
145 // Concatenate repeated fields
146 foreach (object element in (IEnumerable) entry.Value) {
147 AddRepeatedField(field, element);
148 }
149 } else if (field.MappedType == MappedType.Message) {
150 // Merge singular messages
151 IMessage existingValue = (IMessage) this[field];
152 if (existingValue == existingValue.WeakDefaultInstanceForType) {
153 this[field] = entry.Value;
154 } else {
155 this[field] = existingValue.WeakCreateBuilderForType()
156 .WeakMergeFrom(existingValue)
157 .WeakMergeFrom((IMessage) entry.Value)
158 .WeakBuild();
159 }
160 } else {
161 // Overwrite simple values
162 this[field] = entry.Value;
163 }
164 }
165 return ThisBuilder;
166 }
167
168 public virtual TBuilder MergeFrom(CodedInputStream input) {
169 return MergeFrom(input, ExtensionRegistry.Empty);
170 }
171
172 public virtual TBuilder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
173 UnknownFieldSet.Builder unknownFields = UnknownFieldSet.CreateBuilder(UnknownFields);
174 unknownFields.MergeFrom(input, extensionRegistry, this);
175 UnknownFields = unknownFields.Build();
176 return ThisBuilder;
177 }
178
179 public virtual TBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
180 UnknownFields = UnknownFieldSet.CreateBuilder(UnknownFields)
181 .MergeFrom(unknownFields)
182 .Build();
183 return ThisBuilder;
184 }
185
186 public virtual TBuilder MergeFrom(ByteString data) {
187 CodedInputStream input = data.CreateCodedInput();
188 MergeFrom(input);
189 input.CheckLastTagWas(0);
190 return ThisBuilder;
191 }
192
193 public virtual TBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
194 CodedInputStream input = data.CreateCodedInput();
195 MergeFrom(input, extensionRegistry);
196 input.CheckLastTagWas(0);
197 return ThisBuilder;
198 }
199
200 public virtual TBuilder MergeFrom(byte[] data) {
201 CodedInputStream input = CodedInputStream.CreateInstance(data);
202 MergeFrom(input);
203 input.CheckLastTagWas(0);
204 return ThisBuilder;
205 }
206
207 public virtual TBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
208 CodedInputStream input = CodedInputStream.CreateInstance(data);
209 MergeFrom(input, extensionRegistry);
210 input.CheckLastTagWas(0);
211 return ThisBuilder;
212 }
213
214 public virtual TBuilder MergeFrom(Stream input) {
215 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
216 MergeFrom(codedInput);
217 codedInput.CheckLastTagWas(0);
218 return ThisBuilder;
219 }
220
221 public virtual TBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry) {
222 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
223 MergeFrom(codedInput, extensionRegistry);
224 codedInput.CheckLastTagWas(0);
225 return ThisBuilder;
226 }
227
228 public virtual IBuilder SetField(FieldDescriptor field, object value) {
229 this[field] = value;
230 return ThisBuilder;
231 }
232
233 public virtual IBuilder SetRepeatedField(FieldDescriptor field, int index, object value) {
234 this[field, index] = value;
235 return ThisBuilder;
236 }
237 }
238}