blob: c678d66f11ca425599d06eae540432329f1afd99 [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 Google.ProtocolBuffers.Descriptors;
36using Google.ProtocolBuffers.FieldAccess;
37
38namespace Google.ProtocolBuffers {
39 /// <summary>
40 /// All generated protocol message builder classes extend this class. It implements
41 /// most of the IBuilder interface using reflection. Users can ignore this class
42 /// as an implementation detail.
43 /// </summary>
44 public abstract class GeneratedBuilder<TMessage, TBuilder> : AbstractBuilder<TMessage, TBuilder>
45 where TMessage : GeneratedMessage <TMessage, TBuilder>
46 where TBuilder : GeneratedBuilder<TMessage, TBuilder> {
47
48 /// <summary>
49 /// Returns the message being built at the moment.
50 /// </summary>
51 protected abstract TMessage MessageBeingBuilt { get; }
52
53 protected internal FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors {
54 get { return MessageBeingBuilt.FieldAccessorsFromBuilder; }
55 }
56
57 public override bool IsInitialized {
58 get { return MessageBeingBuilt.IsInitialized; }
59 }
60
61 public override IDictionary<FieldDescriptor, object> AllFields {
62 get { return MessageBeingBuilt.AllFields; }
63 }
64
65 public override object this[FieldDescriptor field] {
66 get {
67 // For repeated fields, the underlying list object is still modifiable at this point.
68 // Make sure not to expose the modifiable list to the caller.
69 return field.IsRepeated
70 ? InternalFieldAccessors[field].GetRepeatedWrapper(ThisBuilder)
71 : MessageBeingBuilt[field];
72 }
73 set {
74 InternalFieldAccessors[field].SetValue(ThisBuilder, value);
75 }
76 }
77
78 /// <summary>
79 /// Adds all of the specified values to the given collection.
80 /// </summary>
Jon Skeet642a8142009-01-27 12:25:21 +000081 /// <exception cref="ArgumentNullException">Any element of the list is null</exception>
Jon Skeet68036862008-10-22 13:30:34 +010082 protected void AddRange<T>(IEnumerable<T> source, IList<T> destination) {
Jon Skeet642a8142009-01-27 12:25:21 +000083 ThrowHelper.ThrowIfNull(source);
84 // We only need to check this for nullable types.
85 if (default(T) == null) {
86 ThrowHelper.ThrowIfAnyNull(source);
87 }
Jon Skeet68036862008-10-22 13:30:34 +010088 List<T> list = destination as List<T>;
89 if (list != null) {
90 list.AddRange(source);
91 } else {
92 foreach (T element in source) {
93 destination.Add(element);
94 }
95 }
96 }
97
98 /// <summary>
99 /// Called by derived classes to parse an unknown field.
100 /// </summary>
101 /// <returns>true unless the tag is an end-group tag</returns>
102 protected virtual bool ParseUnknownField(CodedInputStream input, UnknownFieldSet.Builder unknownFields,
103 ExtensionRegistry extensionRegistry, uint tag) {
104 return unknownFields.MergeFieldFrom(tag, input);
105 }
106
107 public override MessageDescriptor DescriptorForType {
108 get { return MessageBeingBuilt.DescriptorForType; }
109 }
110
111 public override int GetRepeatedFieldCount(FieldDescriptor field) {
112 return MessageBeingBuilt.GetRepeatedFieldCount(field);
113 }
114
115 public override object this[FieldDescriptor field, int index] {
116 get { return MessageBeingBuilt[field, index]; }
117 set { InternalFieldAccessors[field].SetRepeated(ThisBuilder, index, value); }
118 }
119
120 public override bool HasField(FieldDescriptor field) {
121 return MessageBeingBuilt.HasField(field);
122 }
123
124 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
125 return InternalFieldAccessors[field].CreateBuilder();
126 }
127
128 public override TBuilder ClearField(FieldDescriptor field) {
129 InternalFieldAccessors[field].Clear(ThisBuilder);
130 return ThisBuilder;
131 }
132
133 public override TBuilder MergeFrom(TMessage other) {
134 if (other.DescriptorForType != InternalFieldAccessors.Descriptor) {
135 throw new ArgumentException("Message type mismatch");
136 }
137
Jon Skeet20bfd9b2008-10-23 21:05:58 +0100138 foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields) {
Jon Skeet68036862008-10-22 13:30:34 +0100139 FieldDescriptor field = entry.Key;
140 if (field.IsRepeated) {
141 // Concatenate repeated fields
142 foreach (object element in (IEnumerable)entry.Value) {
143 AddRepeatedField(field, element);
144 }
145 } else if (field.MappedType == MappedType.Message && HasField(field)) {
146 // Merge singular embedded messages
147 IMessage oldValue = (IMessage)this[field];
148 this[field] = oldValue.WeakCreateBuilderForType()
149 .WeakMergeFrom(oldValue)
150 .WeakMergeFrom((IMessage)entry.Value)
151 .WeakBuildPartial();
152 } else {
153 // Just overwrite
154 this[field] = entry.Value;
155 }
156 }
157 return ThisBuilder;
158 }
159
160 public override TBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
161 TMessage result = MessageBeingBuilt;
162 result.SetUnknownFields(UnknownFieldSet.CreateBuilder(result.UnknownFields)
163 .MergeFrom(unknownFields)
164 .Build());
165 return ThisBuilder;
166 }
167
168 public override TBuilder AddRepeatedField(FieldDescriptor field, object value) {
169 InternalFieldAccessors[field].AddRepeated(ThisBuilder, value);
170 return ThisBuilder;
171 }
172
173 /// <summary>
174 /// Like Build(), but will wrap UninitializedMessageException in
175 /// InvalidProtocolBufferException.
176 /// </summary>
177 public TMessage BuildParsed() {
178 if (!IsInitialized) {
179 throw new UninitializedMessageException(MessageBeingBuilt).AsInvalidProtocolBufferException();
180 }
181 return BuildPartial();
182 }
183
184 /// <summary>
185 /// Implementation of <see cref="IBuilder{TMessage, TBuilder}.Build" />.
186 /// </summary>
187 public override TMessage Build() {
188 if (!IsInitialized) {
189 throw new UninitializedMessageException(MessageBeingBuilt);
190 }
191 return BuildPartial();
192 }
193
194 public override UnknownFieldSet UnknownFields {
195 get { return MessageBeingBuilt.UnknownFields; }
196 set { MessageBeingBuilt.SetUnknownFields(value); }
197 }
198 }
199}