aboutsummaryrefslogtreecommitdiff
path: root/csharp/ProtocolBuffers/AbstractBuilder.cs
blob: 01088f5d9654ab7806ffd096f485e82f5f5cc04d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
using System.Collections;
using System.IO;

namespace Google.ProtocolBuffers {
  /// <summary>
  /// Implementation of the non-generic IMessage interface as far as possible.
  /// </summary>
  public abstract class AbstractBuilder : IBuilder {
    #region Unimplemented members of IBuilder
    public abstract bool Initialized { get; }
    public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
    public abstract object this[FieldDescriptor field] { get; set; }
    public abstract MessageDescriptor DescriptorForType { get; }
    public abstract int GetRepeatedFieldCount(FieldDescriptor field);
    public abstract object this[FieldDescriptor field, int index] { get; set; }
    public abstract bool HasField(FieldDescriptor field);
    #endregion

    #region New abstract methods to be overridden by implementations, allow explicit interface implementation
    protected abstract IMessage BuildImpl();
    protected abstract IMessage BuildPartialImpl();
    protected abstract IBuilder CloneImpl();
    protected abstract IMessage DefaultInstanceForTypeImpl { get; }
    protected abstract IBuilder NewBuilderForFieldImpl<TField>(FieldDescriptor field);
    protected abstract IBuilder ClearFieldImpl();
    protected abstract IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value);
    #endregion

    #region Methods simply proxying to the "Impl" methods, explicitly implementing IBuilder
    IMessage IBuilder.Build() {
      return BuildImpl();
    }

    IMessage IBuilder.BuildPartial() {
      return BuildPartialImpl();
    }

    public IBuilder Clone() {
      return CloneImpl();
    }
    
    public IMessage DefaultInstanceForType {
      get { return DefaultInstanceForTypeImpl; }
    }

    public IBuilder NewBuilderForField<TField>(FieldDescriptor field) {
      return NewBuilderForFieldImpl<TField>(field);
    }

    public IBuilder ClearField(FieldDescriptor field) {
      return ClearFieldImpl();
    }

    public IBuilder AddRepeatedField(FieldDescriptor field, object value) {
      return AddRepeatedFieldImpl(field, value);
    }
    #endregion

    public IBuilder Clear() {
      foreach(FieldDescriptor field in AllFields.Keys) {
        ClearField(field);
      }
      return this;
    }

    public IBuilder MergeFrom(IMessage other) {
      if (other.DescriptorForType != DescriptorForType) {
        throw new ArgumentException("MergeFrom(Message) can only merge messages of the same type.");
      }

      // Note:  We don't attempt to verify that other's fields have valid
      //   types.  Doing so would be a losing battle.  We'd have to verify
      //   all sub-messages as well, and we'd have to make copies of all of
      //   them to insure that they don't change after verification (since
      //   the Message interface itself cannot enforce immutability of
      //   implementations).
      // TODO(jonskeet):  Provide a function somewhere called makeDeepCopy()
      //   which allows people to make secure deep copies of messages.
      foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
        FieldDescriptor field = entry.Key;
        if (field.IsRepeated) {
          // Concatenate repeated fields
          foreach (object element in (IEnumerable) entry.Value) {
            AddRepeatedField(field, element);
          }
        } else if (field.MappedType == MappedType.Message) {
          // Merge singular messages
          IMessage existingValue = (IMessage) this[field];
          if (existingValue == existingValue.DefaultInstanceForType) {
            this[field] = entry.Value;
          } else {
            this[field] = existingValue.CreateBuilderForType()
                                       .MergeFrom(existingValue)
                                       .MergeFrom((IMessage) entry.Value)
                                       .Build();
          }
        } else {
          // Overwrite simple values
          this[field] = entry.Value;
        }
      }
      return this;
    }

    public IBuilder MergeFrom(CodedInputStream input) {
      return MergeFrom(input, ExtensionRegistry.Empty);
    }

    public IBuilder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
      UnknownFieldSet.Builder unknownFields = UnknownFieldSet.CreateBuilder(UnknownFields);
      FieldSet.MergeFrom(input, unknownFields, extensionRegistry, this);
      UnknownFields = unknownFields.Build();
      return this;
    }

    public IBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
      UnknownFields = UnknownFieldSet.CreateBuilder(UnknownFields)
          .MergeFrom(unknownFields)
          .Build();
      return this;
    }

    public UnknownFieldSet UnknownFields { get; set; }

    public IBuilder MergeFrom(ByteString data) {
      CodedInputStream input = data.CreateCodedInput();
      MergeFrom(input);
      input.CheckLastTagWas(0);
      return this;
    }

    public IBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
      CodedInputStream input = data.CreateCodedInput();
      MergeFrom(input, extensionRegistry);
      input.CheckLastTagWas(0);
      return this;
    }

    public IBuilder MergeFrom(byte[] data) {
      CodedInputStream input = CodedInputStream.CreateInstance(data);
      MergeFrom(input);
      input.CheckLastTagWas(0);
      return this;
    }

    public IBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
      CodedInputStream input = CodedInputStream.CreateInstance(data);
      MergeFrom(input, extensionRegistry);
      input.CheckLastTagWas(0);
      return this;
    }

    public IBuilder MergeFrom(Stream input) {
      CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
      MergeFrom(codedInput);
      codedInput.CheckLastTagWas(0);
      return this;
    }

    public IBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry) {
      CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
      MergeFrom(codedInput, extensionRegistry);
      codedInput.CheckLastTagWas(0);
      return this;
    }
  }
}