blob: 907679297a22fd44c163ed1550981af3fa6236bb [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>
81 protected void AddRange<T>(IEnumerable<T> source, IList<T> destination) {
82 List<T> list = destination as List<T>;
83 if (list != null) {
84 list.AddRange(source);
85 } else {
86 foreach (T element in source) {
87 destination.Add(element);
88 }
89 }
90 }
91
92 /// <summary>
93 /// Called by derived classes to parse an unknown field.
94 /// </summary>
95 /// <returns>true unless the tag is an end-group tag</returns>
96 protected virtual bool ParseUnknownField(CodedInputStream input, UnknownFieldSet.Builder unknownFields,
97 ExtensionRegistry extensionRegistry, uint tag) {
98 return unknownFields.MergeFieldFrom(tag, input);
99 }
100
101 public override MessageDescriptor DescriptorForType {
102 get { return MessageBeingBuilt.DescriptorForType; }
103 }
104
105 public override int GetRepeatedFieldCount(FieldDescriptor field) {
106 return MessageBeingBuilt.GetRepeatedFieldCount(field);
107 }
108
109 public override object this[FieldDescriptor field, int index] {
110 get { return MessageBeingBuilt[field, index]; }
111 set { InternalFieldAccessors[field].SetRepeated(ThisBuilder, index, value); }
112 }
113
114 public override bool HasField(FieldDescriptor field) {
115 return MessageBeingBuilt.HasField(field);
116 }
117
118 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
119 return InternalFieldAccessors[field].CreateBuilder();
120 }
121
122 public override TBuilder ClearField(FieldDescriptor field) {
123 InternalFieldAccessors[field].Clear(ThisBuilder);
124 return ThisBuilder;
125 }
126
127 public override TBuilder MergeFrom(TMessage other) {
128 if (other.DescriptorForType != InternalFieldAccessors.Descriptor) {
129 throw new ArgumentException("Message type mismatch");
130 }
131
Jon Skeet20bfd9b2008-10-23 21:05:58 +0100132 foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields) {
Jon Skeet68036862008-10-22 13:30:34 +0100133 FieldDescriptor field = entry.Key;
134 if (field.IsRepeated) {
135 // Concatenate repeated fields
136 foreach (object element in (IEnumerable)entry.Value) {
137 AddRepeatedField(field, element);
138 }
139 } else if (field.MappedType == MappedType.Message && HasField(field)) {
140 // Merge singular embedded messages
141 IMessage oldValue = (IMessage)this[field];
142 this[field] = oldValue.WeakCreateBuilderForType()
143 .WeakMergeFrom(oldValue)
144 .WeakMergeFrom((IMessage)entry.Value)
145 .WeakBuildPartial();
146 } else {
147 // Just overwrite
148 this[field] = entry.Value;
149 }
150 }
151 return ThisBuilder;
152 }
153
154 public override TBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
155 TMessage result = MessageBeingBuilt;
156 result.SetUnknownFields(UnknownFieldSet.CreateBuilder(result.UnknownFields)
157 .MergeFrom(unknownFields)
158 .Build());
159 return ThisBuilder;
160 }
161
162 public override TBuilder AddRepeatedField(FieldDescriptor field, object value) {
163 InternalFieldAccessors[field].AddRepeated(ThisBuilder, value);
164 return ThisBuilder;
165 }
166
167 /// <summary>
168 /// Like Build(), but will wrap UninitializedMessageException in
169 /// InvalidProtocolBufferException.
170 /// </summary>
171 public TMessage BuildParsed() {
172 if (!IsInitialized) {
173 throw new UninitializedMessageException(MessageBeingBuilt).AsInvalidProtocolBufferException();
174 }
175 return BuildPartial();
176 }
177
178 /// <summary>
179 /// Implementation of <see cref="IBuilder{TMessage, TBuilder}.Build" />.
180 /// </summary>
181 public override TMessage Build() {
182 if (!IsInitialized) {
183 throw new UninitializedMessageException(MessageBeingBuilt);
184 }
185 return BuildPartial();
186 }
187
188 public override UnknownFieldSet UnknownFields {
189 get { return MessageBeingBuilt.UnknownFields; }
190 set { MessageBeingBuilt.SetUnknownFields(value); }
191 }
192 }
193}