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