blob: 11a82974769afd389814914d22f53acbe1e7a564 [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;
17using System.Collections;
18using System.Collections.Generic;
19using System.IO;
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 AbstractBuilder<TMessage, TBuilder> : IBuilder<TMessage, TBuilder>
27 where TMessage : AbstractMessage<TMessage, TBuilder>
28 where TBuilder : AbstractBuilder<TMessage, TBuilder> {
29
30 protected abstract TBuilder ThisBuilder { get; }
31
32 #region Unimplemented members of IBuilder
33 public abstract UnknownFieldSet UnknownFields { get; set; }
34 public abstract TBuilder MergeFrom(TMessage other);
35 public abstract bool IsInitialized { get; }
36 public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
37 public abstract object this[FieldDescriptor field] { get; set; }
38 public abstract MessageDescriptor DescriptorForType { get; }
39 public abstract int GetRepeatedFieldCount(FieldDescriptor field);
40 public abstract object this[FieldDescriptor field, int index] { get; set; }
41 public abstract bool HasField(FieldDescriptor field);
42 public abstract TMessage Build();
43 public abstract TMessage BuildPartial();
44 public abstract TBuilder Clone();
45 public abstract TMessage DefaultInstanceForType { get; }
46 public abstract IBuilder CreateBuilderForField(FieldDescriptor field);
47 public abstract TBuilder ClearField(FieldDescriptor field);
48 public abstract TBuilder AddRepeatedField(FieldDescriptor field, object value);
49 #endregion
50
51 #region Implementation of methods which don't require type parameter information
52 public IMessage WeakBuild() {
53 return Build();
54 }
55
56 public IBuilder WeakAddRepeatedField(FieldDescriptor field, object value) {
57 return AddRepeatedField(field, value);
58 }
59
60 public IBuilder WeakClear() {
61 return Clear();
62 }
63
64 public IBuilder WeakMergeFrom(IMessage message) {
65 return MergeFrom(message);
66 }
67
68 public IBuilder WeakMergeFrom(CodedInputStream input) {
69 return MergeFrom(input);
70 }
71
72 public IBuilder WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
73 return MergeFrom(input, registry);
74 }
75
76 public IBuilder WeakMergeFrom(ByteString data) {
77 return MergeFrom(data);
78 }
79
80 public IBuilder WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
81 return MergeFrom(data, registry);
82 }
83
84 public IMessage WeakBuildPartial() {
85 return BuildPartial();
86 }
87
88 public IBuilder WeakClone() {
89 return Clone();
90 }
91
92 public IMessage WeakDefaultInstanceForType {
93 get { return DefaultInstanceForType; }
94 }
95
96 public IBuilder WeakClearField(FieldDescriptor field) {
97 return ClearField(field);
98 }
99 #endregion
100
101 public TBuilder SetUnknownFields(UnknownFieldSet fields) {
102 UnknownFields = fields;
103 return ThisBuilder;
104 }
105
106 public virtual TBuilder Clear() {
107 foreach(FieldDescriptor field in AllFields.Keys) {
108 ClearField(field);
109 }
110 return ThisBuilder;
111 }
112
113 public virtual TBuilder MergeFrom(IMessage other) {
114 if (other.DescriptorForType != DescriptorForType) {
115 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
116 }
117
118 // Note: We don't attempt to verify that other's fields have valid
119 // types. Doing so would be a losing battle. We'd have to verify
120 // all sub-messages as well, and we'd have to make copies of all of
121 // them to insure that they don't change after verification (since
122 // the Message interface itself cannot enforce immutability of
123 // implementations).
124 // TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
125 // which allows people to make secure deep copies of messages.
126 foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields) {
127 FieldDescriptor field = entry.Key;
128 if (field.IsRepeated) {
129 // Concatenate repeated fields
130 foreach (object element in (IEnumerable) entry.Value) {
131 AddRepeatedField(field, element);
132 }
133 } else if (field.MappedType == MappedType.Message) {
134 // Merge singular messages
135 IMessage existingValue = (IMessage) this[field];
136 if (existingValue == existingValue.WeakDefaultInstanceForType) {
137 this[field] = entry.Value;
138 } else {
139 this[field] = existingValue.WeakCreateBuilderForType()
140 .WeakMergeFrom(existingValue)
141 .WeakMergeFrom((IMessage) entry.Value)
142 .WeakBuild();
143 }
144 } else {
145 // Overwrite simple values
146 this[field] = entry.Value;
147 }
148 }
149 return ThisBuilder;
150 }
151
152 public virtual TBuilder MergeFrom(CodedInputStream input) {
153 return MergeFrom(input, ExtensionRegistry.Empty);
154 }
155
156 public virtual TBuilder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
157 UnknownFieldSet.Builder unknownFields = UnknownFieldSet.CreateBuilder(UnknownFields);
158 unknownFields.MergeFrom(input, extensionRegistry, this);
159 UnknownFields = unknownFields.Build();
160 return ThisBuilder;
161 }
162
163 public virtual TBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
164 UnknownFields = UnknownFieldSet.CreateBuilder(UnknownFields)
165 .MergeFrom(unknownFields)
166 .Build();
167 return ThisBuilder;
168 }
169
170 public virtual TBuilder MergeFrom(ByteString data) {
171 CodedInputStream input = data.CreateCodedInput();
172 MergeFrom(input);
173 input.CheckLastTagWas(0);
174 return ThisBuilder;
175 }
176
177 public virtual TBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
178 CodedInputStream input = data.CreateCodedInput();
179 MergeFrom(input, extensionRegistry);
180 input.CheckLastTagWas(0);
181 return ThisBuilder;
182 }
183
184 public virtual TBuilder MergeFrom(byte[] data) {
185 CodedInputStream input = CodedInputStream.CreateInstance(data);
186 MergeFrom(input);
187 input.CheckLastTagWas(0);
188 return ThisBuilder;
189 }
190
191 public virtual TBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
192 CodedInputStream input = CodedInputStream.CreateInstance(data);
193 MergeFrom(input, extensionRegistry);
194 input.CheckLastTagWas(0);
195 return ThisBuilder;
196 }
197
198 public virtual TBuilder MergeFrom(Stream input) {
199 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
200 MergeFrom(codedInput);
201 codedInput.CheckLastTagWas(0);
202 return ThisBuilder;
203 }
204
205 public virtual TBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry) {
206 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
207 MergeFrom(codedInput, extensionRegistry);
208 codedInput.CheckLastTagWas(0);
209 return ThisBuilder;
210 }
211
212 public virtual IBuilder SetField(FieldDescriptor field, object value) {
213 this[field] = value;
214 return ThisBuilder;
215 }
216
217 public virtual IBuilder SetRepeatedField(FieldDescriptor field, int index, object value) {
218 this[field, index] = value;
219 return ThisBuilder;
220 }
221 }
222}