blob: 94948e495c9c22b48e465759d2d178e6af449877 [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
38using System.Collections;
39using System.Collections.Generic;
40using Google.ProtocolBuffers.Descriptors;
41using Google.ProtocolBuffers.FieldAccess;
42
43namespace Google.ProtocolBuffers
44{
45 /// <summary>
46 /// All generated protocol message builder classes extend this class. It implements
47 /// most of the IBuilder interface using reflection. Users can ignore this class
48 /// as an implementation detail.
49 /// </summary>
50 public abstract class GeneratedBuilder<TMessage, TBuilder> : AbstractBuilder<TMessage, TBuilder>
51 where TMessage : GeneratedMessage<TMessage, TBuilder>
csharptestf2925232011-06-11 10:41:57 -050052 where TBuilder : GeneratedBuilder<TMessage, TBuilder>, new()
csharptest71f662c2011-05-20 15:15:34 -050053 {
54 /// <summary>
55 /// Returns the message being built at the moment.
56 /// </summary>
57 protected abstract TMessage MessageBeingBuilt { get; }
58
59 protected internal FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors
60 {
61 get { return MessageBeingBuilt.FieldAccessorsFromBuilder; }
62 }
63
64 public override bool IsInitialized
65 {
66 get { return MessageBeingBuilt.IsInitialized; }
67 }
68
69 public override IDictionary<FieldDescriptor, object> AllFields
70 {
71 get { return MessageBeingBuilt.AllFields; }
72 }
73
74 public override object this[FieldDescriptor field]
75 {
76 get
77 {
78 // For repeated fields, the underlying list object is still modifiable at this point.
79 // Make sure not to expose the modifiable list to the caller.
80 return field.IsRepeated
81 ? InternalFieldAccessors[field].GetRepeatedWrapper(ThisBuilder)
82 : MessageBeingBuilt[field];
83 }
84 set { InternalFieldAccessors[field].SetValue(ThisBuilder, value); }
85 }
86
87 /// <summary>
88 /// Adds all of the specified values to the given collection.
89 /// </summary>
90 /// <exception cref="ArgumentNullException">Any element of the list is null</exception>
91 protected void AddRange<T>(IEnumerable<T> source, IList<T> destination)
92 {
93 ThrowHelper.ThrowIfNull(source);
94 // We only need to check this for nullable types.
95 if (default(T) == null)
96 {
97 ThrowHelper.ThrowIfAnyNull(source);
98 }
99 List<T> list = destination as List<T>;
100 if (list != null)
101 {
102 list.AddRange(source);
103 }
104 else
105 {
106 foreach (T element in source)
107 {
108 destination.Add(element);
109 }
110 }
111 }
112
113 /// <summary>
114 /// Called by derived classes to parse an unknown field.
115 /// </summary>
116 /// <returns>true unless the tag is an end-group tag</returns>
117 [CLSCompliant(false)]
csharptest17699c22011-06-03 21:57:15 -0500118 protected virtual bool ParseUnknownField(ICodedInputStream input, UnknownFieldSet.Builder unknownFields,
csharptestd2af9e92011-06-03 21:35:02 -0500119 ExtensionRegistry extensionRegistry, uint tag, string fieldName)
csharptest71f662c2011-05-20 15:15:34 -0500120 {
121 return unknownFields.MergeFieldFrom(tag, input);
122 }
123
124 public override MessageDescriptor DescriptorForType
125 {
126 get { return MessageBeingBuilt.DescriptorForType; }
127 }
128
129 public override int GetRepeatedFieldCount(FieldDescriptor field)
130 {
131 return MessageBeingBuilt.GetRepeatedFieldCount(field);
132 }
133
134 public override object this[FieldDescriptor field, int index]
135 {
136 get { return MessageBeingBuilt[field, index]; }
137 set { InternalFieldAccessors[field].SetRepeated(ThisBuilder, index, value); }
138 }
139
140 public override bool HasField(FieldDescriptor field)
141 {
142 return MessageBeingBuilt.HasField(field);
143 }
144
145 public override IBuilder CreateBuilderForField(FieldDescriptor field)
146 {
147 return InternalFieldAccessors[field].CreateBuilder();
148 }
149
150 public override TBuilder ClearField(FieldDescriptor field)
151 {
152 InternalFieldAccessors[field].Clear(ThisBuilder);
153 return ThisBuilder;
154 }
155
156 public override TBuilder MergeFrom(TMessage other)
157 {
158 if (other.DescriptorForType != InternalFieldAccessors.Descriptor)
159 {
160 throw new ArgumentException("Message type mismatch");
161 }
162
163 foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields)
164 {
165 FieldDescriptor field = entry.Key;
166 if (field.IsRepeated)
167 {
168 // Concatenate repeated fields
169 foreach (object element in (IEnumerable) entry.Value)
170 {
171 AddRepeatedField(field, element);
172 }
173 }
174 else if (field.MappedType == MappedType.Message && HasField(field))
175 {
176 // Merge singular embedded messages
177 IMessageLite oldValue = (IMessageLite) this[field];
178 this[field] = oldValue.WeakCreateBuilderForType()
179 .WeakMergeFrom(oldValue)
180 .WeakMergeFrom((IMessageLite) entry.Value)
181 .WeakBuildPartial();
182 }
183 else
184 {
185 // Just overwrite
186 this[field] = entry.Value;
187 }
188 }
189
190 //Fix for unknown fields not merging, see java's AbstractMessage.Builder<T> line 236
191 MergeUnknownFields(other.UnknownFields);
192
193 return ThisBuilder;
194 }
195
196 public override TBuilder MergeUnknownFields(UnknownFieldSet unknownFields)
197 {
198 if (unknownFields != UnknownFieldSet.DefaultInstance)
199 {
200 TMessage result = MessageBeingBuilt;
201 result.SetUnknownFields(UnknownFieldSet.CreateBuilder(result.UnknownFields)
202 .MergeFrom(unknownFields)
203 .Build());
204 }
205 return ThisBuilder;
206 }
207
208 public override TBuilder AddRepeatedField(FieldDescriptor field, object value)
209 {
210 InternalFieldAccessors[field].AddRepeated(ThisBuilder, value);
211 return ThisBuilder;
212 }
213
214 /// <summary>
215 /// Like Build(), but will wrap UninitializedMessageException in
216 /// InvalidProtocolBufferException.
217 /// </summary>
218 public TMessage BuildParsed()
219 {
220 if (!IsInitialized)
221 {
222 throw new UninitializedMessageException(MessageBeingBuilt).AsInvalidProtocolBufferException();
223 }
224 return BuildPartial();
225 }
226
227 /// <summary>
228 /// Implementation of <see cref="IBuilder{TMessage, TBuilder}.Build" />.
229 /// </summary>
230 public override TMessage Build()
231 {
232 // If the message is null, we'll throw a more appropriate exception in BuildPartial.
233 if (MessageBeingBuilt != null && !IsInitialized)
234 {
235 throw new UninitializedMessageException(MessageBeingBuilt);
236 }
237 return BuildPartial();
238 }
239
240 public override UnknownFieldSet UnknownFields
241 {
242 get { return MessageBeingBuilt.UnknownFields; }
243 set { MessageBeingBuilt.SetUnknownFields(value); }
244 }
245 }
246}