aboutsummaryrefslogtreecommitdiff
path: root/csharp/ProtocolBuffers
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2008-08-14 20:33:33 +0100
committerJon Skeet <skeet@pobox.com>2008-08-14 20:33:33 +0100
commit621bb698e54a7e0d2fdf74ab1f380183461ce7fa (patch)
treef1750773eee92541401126c66c811a382b0b22a7 /csharp/ProtocolBuffers
parenta7246897ab87bc52951cc208f3775c7dfc1d6e09 (diff)
downloadprotobuf-621bb698e54a7e0d2fdf74ab1f380183461ce7fa.tar.gz
protobuf-621bb698e54a7e0d2fdf74ab1f380183461ce7fa.tar.bz2
protobuf-621bb698e54a7e0d2fdf74ab1f380183461ce7fa.zip
Some work on AbstractBuilder, and complete implementation of UnknownField and UnknownFieldSet
Diffstat (limited to 'csharp/ProtocolBuffers')
-rw-r--r--csharp/ProtocolBuffers/AbstractBuilder.cs195
-rw-r--r--csharp/ProtocolBuffers/AbstractMessage.cs84
-rw-r--r--csharp/ProtocolBuffers/ByteString.cs9
-rw-r--r--csharp/ProtocolBuffers/CodedInputStream.cs2
-rw-r--r--csharp/ProtocolBuffers/CodedOutputStream.cs6
-rw-r--r--csharp/ProtocolBuffers/Collections/Lists.cs21
-rw-r--r--csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs12
-rw-r--r--csharp/ProtocolBuffers/Descriptors/MappedType.cs10
-rw-r--r--csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs1
-rw-r--r--csharp/ProtocolBuffers/ExtensionInfo.cs25
-rw-r--r--csharp/ProtocolBuffers/ExtensionRegistry.cs162
-rw-r--r--csharp/ProtocolBuffers/FieldAccess/Delegates.cs12
-rw-r--r--csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs25
-rw-r--r--csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs34
-rw-r--r--csharp/ProtocolBuffers/FieldAccess/SingularFieldAccessor.cs65
-rw-r--r--csharp/ProtocolBuffers/FieldSet.cs33
-rw-r--r--csharp/ProtocolBuffers/GeneratedExtension.cs34
-rw-r--r--csharp/ProtocolBuffers/GeneratedMessage.cs71
-rw-r--r--csharp/ProtocolBuffers/IBuilder.cs86
-rw-r--r--csharp/ProtocolBuffers/IMessage.cs12
-rw-r--r--csharp/ProtocolBuffers/ProtocolBuffers.csproj11
-rw-r--r--csharp/ProtocolBuffers/TextFormat.cs4
-rw-r--r--csharp/ProtocolBuffers/UnknownField.cs306
-rw-r--r--csharp/ProtocolBuffers/UnknownFieldSet.cs394
-rw-r--r--csharp/ProtocolBuffers/WireFormat.cs4
25 files changed, 1553 insertions, 65 deletions
diff --git a/csharp/ProtocolBuffers/AbstractBuilder.cs b/csharp/ProtocolBuffers/AbstractBuilder.cs
new file mode 100644
index 00000000..a76e3479
--- /dev/null
+++ b/csharp/ProtocolBuffers/AbstractBuilder.cs
@@ -0,0 +1,195 @@
+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 {
+
+ public bool Initialized {
+ get { throw new NotImplementedException(); }
+ }
+
+ public IDictionary<FieldDescriptor, object> AllFields {
+ get { throw new NotImplementedException(); }
+ }
+
+ public object this[FieldDescriptor field] {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public MessageDescriptor DescriptorForType {
+ get { throw new NotImplementedException(); }
+ }
+
+ public int GetRepeatedFieldCount(FieldDescriptor field) {
+ throw new NotImplementedException();
+ }
+
+ public object this[FieldDescriptor field, int index] {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public bool HasField(FieldDescriptor field) {
+ throw new NotImplementedException();
+ }
+
+ 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 IMessage Build() {
+ throw new NotImplementedException();
+ }
+
+ public IMessage BuildPartial() {
+ throw new NotImplementedException();
+ }
+
+ public IBuilder Clone() {
+ throw new NotImplementedException();
+ }
+
+ 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 IMessage DefaultInstanceForType {
+ get { throw new NotImplementedException(); }
+ }
+
+ public IBuilder NewBuilderForField<TField>(FieldDescriptor field) {
+ throw new NotImplementedException();
+ }
+
+ public IBuilder ClearField(FieldDescriptor field) {
+ throw new NotImplementedException();
+ }
+
+ public IBuilder AddRepeatedField(FieldDescriptor field, object value) {
+ throw new NotImplementedException();
+ }
+
+ public IBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
+ UnknownFields = UnknownFieldSet.CreateBuilder(UnknownFields)
+ .MergeFrom(unknownFields)
+ .Build();
+ return this;
+ }
+
+ public UnknownFieldSet UnknownFields {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/AbstractMessage.cs b/csharp/ProtocolBuffers/AbstractMessage.cs
index 562214a0..e1d5f883 100644
--- a/csharp/ProtocolBuffers/AbstractMessage.cs
+++ b/csharp/ProtocolBuffers/AbstractMessage.cs
@@ -34,13 +34,15 @@ namespace Google.ProtocolBuffers {
#region Unimplemented members of IMessage
public abstract MessageDescriptor DescriptorForType { get; }
- public abstract IDictionary<Descriptors.FieldDescriptor, object> AllFields { get; }
- public abstract bool HasField(Descriptors.FieldDescriptor field);
- public abstract object this[Descriptors.FieldDescriptor field] { get; }
- public abstract int GetRepeatedFieldCount(Descriptors.FieldDescriptor field);
- public abstract object this[Descriptors.FieldDescriptor field, int index] { get; }
+ public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
+ public abstract bool HasField(FieldDescriptor field);
+ public abstract object this[FieldDescriptor field] { get; }
+ public abstract int GetRepeatedFieldCount(FieldDescriptor field);
+ public abstract object this[FieldDescriptor field, int index] { get; }
public abstract UnknownFieldSet UnknownFields { get; }
- public abstract IMessage DefaultInstanceForType { get; }
+ // FIXME
+ IMessage IMessage.DefaultInstanceForType { get { return null; } }
+ IBuilder IMessage.CreateBuilderForType() { return null; }
#endregion
public bool IsInitialized {
@@ -152,8 +154,6 @@ namespace Google.ProtocolBuffers {
codedOutput.Flush();
}
- public abstract IBuilder CreateBuilderForType();
-
public override bool Equals(object other) {
if (other == this) {
return true;
@@ -173,5 +173,73 @@ namespace Google.ProtocolBuffers {
hash = (53 * hash) + AllFields.GetHashCode();
return hash;
}
+
+ #region IMessage Members
+
+ MessageDescriptor IMessage.DescriptorForType {
+ get { throw new NotImplementedException(); }
+ }
+
+ IDictionary<FieldDescriptor, object> IMessage.AllFields {
+ get { throw new NotImplementedException(); }
+ }
+
+ bool IMessage.HasField(FieldDescriptor field) {
+ throw new NotImplementedException();
+ }
+
+ object IMessage.this[FieldDescriptor field] {
+ get { throw new NotImplementedException(); }
+ }
+
+ int IMessage.GetRepeatedFieldCount(FieldDescriptor field) {
+ throw new NotImplementedException();
+ }
+
+ object IMessage.this[FieldDescriptor field, int index] {
+ get { throw new NotImplementedException(); }
+ }
+
+ UnknownFieldSet IMessage.UnknownFields {
+ get { throw new NotImplementedException(); }
+ }
+
+ bool IMessage.IsInitialized {
+ get { throw new NotImplementedException(); }
+ }
+
+ void IMessage.WriteTo(CodedOutputStream output) {
+ throw new NotImplementedException();
+ }
+
+ int IMessage.SerializedSize {
+ get { throw new NotImplementedException(); }
+ }
+
+ bool IMessage.Equals(object other) {
+ throw new NotImplementedException();
+ }
+
+ int IMessage.GetHashCode() {
+ throw new NotImplementedException();
+ }
+
+ string IMessage.ToString() {
+ throw new NotImplementedException();
+ }
+
+ ByteString IMessage.ToByteString() {
+ throw new NotImplementedException();
+ }
+
+ byte[] IMessage.ToByteArray() {
+ throw new NotImplementedException();
+ }
+
+ void IMessage.WriteTo(Stream output) {
+ throw new NotImplementedException();
+ }
+
+ #endregion
}
}
diff --git a/csharp/ProtocolBuffers/ByteString.cs b/csharp/ProtocolBuffers/ByteString.cs
index 34aea2df..94eb45e3 100644
--- a/csharp/ProtocolBuffers/ByteString.cs
+++ b/csharp/ProtocolBuffers/ByteString.cs
@@ -105,6 +105,15 @@ namespace Google.ProtocolBuffers {
return ToString(Encoding.UTF8);
}
+ /// <summary>
+ /// Creates a CodedInputStream from this ByteString's data.
+ /// </summary>
+ public CodedInputStream CreateCodedInput() {
+
+ // We trust CodedInputStream not to reveal the provided byte array or modify it
+ return CodedInputStream.CreateInstance(bytes);
+ }
+
// TODO(jonskeet): CopyTo, Equals, GetHashCode if they turn out to be required
/// <summary>
diff --git a/csharp/ProtocolBuffers/CodedInputStream.cs b/csharp/ProtocolBuffers/CodedInputStream.cs
index cdad2440..d2a3657b 100644
--- a/csharp/ProtocolBuffers/CodedInputStream.cs
+++ b/csharp/ProtocolBuffers/CodedInputStream.cs
@@ -321,7 +321,7 @@ namespace Google.ProtocolBuffers {
/// Reads a field of any primitive type. Enums, groups and embedded
/// messages are not handled by this method.
/// </summary>
- public object readPrimitiveField(FieldType fieldType) {
+ public object ReadPrimitiveField(FieldType fieldType) {
switch (fieldType) {
case FieldType.Double: return ReadDouble();
case FieldType.Float: return ReadFloat();
diff --git a/csharp/ProtocolBuffers/CodedOutputStream.cs b/csharp/ProtocolBuffers/CodedOutputStream.cs
index bb160319..5fec5274 100644
--- a/csharp/ProtocolBuffers/CodedOutputStream.cs
+++ b/csharp/ProtocolBuffers/CodedOutputStream.cs
@@ -271,7 +271,7 @@ namespace Google.ProtocolBuffers {
case FieldType.SFixed64: WriteSFixed64(fieldNumber, (long)value); break;
case FieldType.SInt32: WriteSInt32(fieldNumber, (int)value); break;
case FieldType.SInt64: WriteSInt64(fieldNumber, (long)value); break;
- case FieldType.Enum: WriteEnum(fieldNumber, ((Descriptors.EnumValueDescriptor)value).Number);
+ case FieldType.Enum: WriteEnum(fieldNumber, ((EnumValueDescriptor)value).Number);
break;
}
}
@@ -615,7 +615,7 @@ namespace Google.ProtocolBuffers {
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
- * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * {@link Message#getField(FieldDescriptor)} for
* this field.
*/
public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value) {
@@ -637,7 +637,7 @@ namespace Google.ProtocolBuffers {
case FieldType.SFixed64: return ComputeSFixed64Size(fieldNumber, (long)value);
case FieldType.SInt32: return ComputeSInt32Size(fieldNumber, (int)value);
case FieldType.SInt64: return ComputeSInt64Size(fieldNumber, (long)value);
- case FieldType.Enum: return ComputeEnumSize(fieldNumber, ((Descriptors.EnumValueDescriptor)value).Number);
+ case FieldType.Enum: return ComputeEnumSize(fieldNumber, ((EnumValueDescriptor)value).Number);
default:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
}
diff --git a/csharp/ProtocolBuffers/Collections/Lists.cs b/csharp/ProtocolBuffers/Collections/Lists.cs
new file mode 100644
index 00000000..6d27142f
--- /dev/null
+++ b/csharp/ProtocolBuffers/Collections/Lists.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+
+namespace Google.ProtocolBuffers.Collections {
+ /// <summary>
+ /// Utilities class for dealing with lists.
+ /// </summary>
+ static class Lists<T> {
+
+ static readonly ReadOnlyCollection<T> empty = new ReadOnlyCollection<T>(new T[0]);
+
+ /// <summary>
+ /// Returns an immutable empty list.
+ /// </summary>
+ internal static ReadOnlyCollection<T> Empty {
+ get { return empty; }
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
index c5c9bbe4..8eb19d53 100644
--- a/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
+++ b/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
@@ -13,5 +13,17 @@ namespace Google.ProtocolBuffers.Descriptors {
public FieldType FieldType { get; set; }
public int FieldNumber { get; set; }
+
+ public bool IsExtension { get; set; }
+
+ public MessageDescriptor ContainingType { get; set; }
+
+ public string FullName { get; set; }
+
+ public bool IsOptional { get; set; }
+
+ public MessageDescriptor MessageType { get; set; }
+
+ public MessageDescriptor ExtensionScope { get; set; }
}
}
diff --git a/csharp/ProtocolBuffers/Descriptors/MappedType.cs b/csharp/ProtocolBuffers/Descriptors/MappedType.cs
index 4ee2d341..4d2d8e51 100644
--- a/csharp/ProtocolBuffers/Descriptors/MappedType.cs
+++ b/csharp/ProtocolBuffers/Descriptors/MappedType.cs
@@ -7,6 +7,14 @@ namespace Google.ProtocolBuffers.Descriptors {
/// Type as it's mapped onto a .NET type.
/// </summary>
public enum MappedType {
- Message
+ Int32,
+ Int64,
+ Single,
+ Double,
+ Boolean,
+ String,
+ ByteString,
+ Message,
+ Enum
}
}
diff --git a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
index 1475d711..4e0834f0 100644
--- a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
+++ b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
@@ -5,5 +5,6 @@ namespace Google.ProtocolBuffers.Descriptors {
public class MessageDescriptor {
public IList<FieldDescriptor> Fields;
public DescriptorProtos.MessageOptions Options;
+ public string FullName;
}
}
diff --git a/csharp/ProtocolBuffers/ExtensionInfo.cs b/csharp/ProtocolBuffers/ExtensionInfo.cs
new file mode 100644
index 00000000..a4936104
--- /dev/null
+++ b/csharp/ProtocolBuffers/ExtensionInfo.cs
@@ -0,0 +1,25 @@
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers
+{
+ public sealed class ExtensionInfo {
+ /// <summary>
+ /// The extension's descriptor
+ /// </summary>
+ public FieldDescriptor Descriptor { get; private set; }
+
+ /// <summary>
+ /// A default instance of the extensions's type, if it has a message type,
+ /// or null otherwise.
+ /// </summary>
+ public IMessage DefaultInstance { get; private set; }
+
+ internal ExtensionInfo(FieldDescriptor descriptor) : this(descriptor, null) {
+ }
+
+ internal ExtensionInfo(FieldDescriptor descriptor, IMessage defaultInstance) {
+ Descriptor = descriptor;
+ DefaultInstance = defaultInstance;
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/ProtocolBuffers/ExtensionRegistry.cs b/csharp/ProtocolBuffers/ExtensionRegistry.cs
index a8ed661d..6c36aff4 100644
--- a/csharp/ProtocolBuffers/ExtensionRegistry.cs
+++ b/csharp/ProtocolBuffers/ExtensionRegistry.cs
@@ -13,7 +13,167 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Descriptors;
+using System;
+
namespace Google.ProtocolBuffers {
- public class ExtensionRegistry {
+ /// <summary>
+ /// TODO(jonskeet): Copy docs from Java
+ /// </summary>
+ public sealed class ExtensionRegistry {
+
+ private static readonly ExtensionRegistry empty = new ExtensionRegistry(
+ new Dictionary<string, ExtensionInfo>(),
+ new Dictionary<DescriptorIntPair, ExtensionInfo>(),
+ true);
+
+ private readonly IDictionary<string, ExtensionInfo> extensionsByName;
+ private readonly IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+ private readonly bool readOnly;
+
+ private ExtensionRegistry(IDictionary<String, ExtensionInfo> extensionsByName,
+ IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber,
+ bool readOnly) {
+ this.extensionsByName = extensionsByName;
+ this.extensionsByNumber = extensionsByNumber;
+ this.readOnly = readOnly;
+ }
+
+ /// <summary>
+ /// Construct a new, empty instance.
+ /// </summary>
+ public static ExtensionRegistry CreateInstance() {
+ return new ExtensionRegistry(new Dictionary<string, ExtensionInfo>(),
+ new Dictionary<DescriptorIntPair, ExtensionInfo>(), false);
+ }
+
+ /// <summary>
+ /// Get the unmodifiable singleton empty instance.
+ /// </summary>
+ public static ExtensionRegistry Empty {
+ get { return empty; }
+ }
+
+ public ExtensionRegistry AsReadOnly() {
+ return new ExtensionRegistry(extensionsByName, extensionsByNumber, true);
+ }
+
+ /// <summary>
+ /// Finds an extension by fully-qualified field name, in the
+ /// proto namespace, i.e. result.Descriptor.FullName will match
+ /// <paramref name="fullName"/> if a match is found. A null
+ /// reference is returned if the extension can't be found.
+ /// </summary>
+ public ExtensionInfo this[string fullName] {
+ get {
+ ExtensionInfo ret;
+ extensionsByName.TryGetValue(fullName, out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Finds an extension by containing type and field number.
+ /// A null reference is returned if the extension can't be found.
+ /// </summary>
+ public ExtensionInfo this[MessageDescriptor containingType, int fieldNumber] {
+ get {
+ ExtensionInfo ret;
+ extensionsByNumber.TryGetValue(new DescriptorIntPair(containingType, fieldNumber), out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Add an extension from a generated file to the registry.
+ /// </summary>
+ public void Add<TContainer, TExtension> (GeneratedExtension<TContainer, TExtension> extension)
+ where TContainer : IMessage<TContainer> {
+ if (extension.Descriptor.MappedType == MappedType.Message) {
+ Add(new ExtensionInfo(extension.Descriptor, extension.MessageDefaultInstance));
+ } else {
+ Add(new ExtensionInfo(extension.Descriptor, null));
+ }
+ }
+
+ /// <summary>
+ /// Adds a non-message-type extension to the registry by descriptor.
+ /// </summary>
+ /// <param name="type"></param>
+ public void Add(FieldDescriptor type) {
+ if (type.MappedType == MappedType.Message) {
+ throw new ArgumentException("ExtensionRegistry.Add() must be provided a default instance "
+ + "when adding an embedded message extension.");
+ }
+ Add(new ExtensionInfo(type, null));
+ }
+
+ /// <summary>
+ /// Adds a message-type-extension to the registry by descriptor.
+ /// </summary>
+ /// <param name="type"></param>
+ /// <param name="defaultInstance"></param>
+ public void Add(FieldDescriptor type, IMessage defaultInstance) {
+ if (type.MappedType != MappedType.Message) {
+ throw new ArgumentException("ExtensionRegistry.Add() provided a default instance for a "
+ + "non-message extension.");
+ }
+ Add(new ExtensionInfo(type, defaultInstance));
+ }
+
+ private void Add(ExtensionInfo extension) {
+ if (readOnly) {
+ throw new InvalidOperationException("Cannot add entries to a read-only extension registry");
+ }
+ if (!extension.Descriptor.IsExtension) {
+ throw new ArgumentException("ExtensionRegistry.add() was given a FieldDescriptor for a "
+ + "regular (non-extension) field.");
+ }
+
+ extensionsByName[extension.Descriptor.FullName] = extension;
+ extensionsByNumber[new DescriptorIntPair(extension.Descriptor.ContainingType,
+ extension.Descriptor.FieldNumber)] = extension;
+
+ FieldDescriptor field = extension.Descriptor;
+ if (field.ContainingType.Options.IsMessageSetWireFormat
+ && field.FieldType == FieldType.Message
+ && field.IsOptional
+ && field.ExtensionScope == field.MessageType) {
+ // This is an extension of a MessageSet type defined within the extension
+ // type's own scope. For backwards-compatibility, allow it to be looked
+ // up by type name.
+ extensionsByName[field.MessageType.FullName] = extension;
+ }
+ }
+
+ /// <summary>
+ /// Nested type just used to represent a pair of MessageDescriptor and int, as
+ /// the key into the "by number" map.
+ /// </summary>
+ private struct DescriptorIntPair : IEquatable<DescriptorIntPair> {
+ readonly MessageDescriptor descriptor;
+ readonly int number;
+
+ internal DescriptorIntPair(MessageDescriptor descriptor, int number) {
+ this.descriptor = descriptor;
+ this.number = number;
+ }
+
+ public override int GetHashCode() {
+ return descriptor.GetHashCode() * ((1 << 16) - 1) + number;
+ }
+
+ public override bool Equals(object obj) {
+ if (!(obj is DescriptorIntPair)) {
+ return false;
+ }
+ return Equals((DescriptorIntPair)obj);
+ }
+
+ public bool Equals(DescriptorIntPair other) {
+ return descriptor == other.descriptor && number == other.number;
+ }
+ }
}
}
diff --git a/csharp/ProtocolBuffers/FieldAccess/Delegates.cs b/csharp/ProtocolBuffers/FieldAccess/Delegates.cs
new file mode 100644
index 00000000..3dc0445d
--- /dev/null
+++ b/csharp/ProtocolBuffers/FieldAccess/Delegates.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers.FieldAccess {
+ /// <summary>
+ /// Declarations of delegate types used for field access. Can't
+ /// use Func and Action (other than one parameter) as we can't guarantee .NET 3.5.
+ /// </summary>
+ delegate bool HasFunction<TMessage>(TMessage message);
+
+}
diff --git a/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs b/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
new file mode 100644
index 00000000..d7b239c1
--- /dev/null
+++ b/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.FieldAccess {
+ public class FieldAccessorTable<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage>
+ where TBuilder : IBuilder<TMessage> {
+
+ readonly MessageDescriptor descriptor;
+
+ public MessageDescriptor Descriptor {
+ get { return descriptor; }
+ }
+
+ public FieldAccessorTable(MessageDescriptor descriptor, String[] pascalCaseNames) {
+ this.descriptor = descriptor;
+ }
+
+ internal IFieldAccessor<TMessage, TBuilder> this[FieldDescriptor field] {
+ get { return null; }
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs
new file mode 100644
index 00000000..b667fd7f
--- /dev/null
+++ b/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers.FieldAccess {
+ internal interface IFieldAccessor<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage>
+ where TBuilder : IBuilder<TMessage> {
+
+ void AddRepeated(IBuilder<TMessage> builder, object value);
+ bool Has(IMessage<TMessage> message);
+ int GetRepeatedCount(IMessage<TMessage> message);
+ void Clear(TBuilder builder);
+ TBuilder CreateBuilder();
+
+ /// <summary>
+ /// Accessor for single fields
+ /// </summary>
+ object this[IMessage<TMessage> message] { get; }
+ /// <summary>
+ /// Mutator for single fields
+ /// </summary>
+ object this[IBuilder<TMessage> builder] { set; }
+
+ /// <summary>
+ /// Accessor for repeated fields
+ /// </summary>
+ object this[IMessage<TMessage> message, int index] { get; }
+ /// <summary>
+ /// Mutator for repeated fields
+ /// </summary>
+ object this[IBuilder<TMessage> builder, int index] { set; }
+ }
+}
diff --git a/csharp/ProtocolBuffers/FieldAccess/SingularFieldAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SingularFieldAccessor.cs
new file mode 100644
index 00000000..62b3c48d
--- /dev/null
+++ b/csharp/ProtocolBuffers/FieldAccess/SingularFieldAccessor.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.FieldAccess {
+ internal class SingularFieldAccessor<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage>
+ where TBuilder : IBuilder<TMessage> {
+
+ readonly HasFunction<TMessage> hasProxy;
+ readonly Action<TBuilder> clearProxy;
+
+ internal SingularFieldAccessor(FieldDescriptor descriptor, String pascalCaseName) {
+
+ /* Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+ type = getMethod.getReturnType();
+ setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+ hasMethod =
+ getMethodOrDie(messageClass, "has" + camelCaseName);
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName); */
+ }
+
+ public bool Has(IMessage<TMessage> message) {
+ return false;// hasProxy(message);
+ }
+
+ public void Clear(TBuilder builder) {
+// clearProxy(builder);
+ }
+
+ public TBuilder CreateBuilder() {
+// return createBuilderProxy(builder);
+ return default(TBuilder);
+ }
+
+ public object this[IMessage<TMessage> message] {
+ get { return null;/* getProxy(message);*/ }
+ }
+
+ public object this[IBuilder<TMessage> builder] {
+ set { /*setProxy(builder, value);*/ }
+ }
+
+ #region Repeated operations (which just throw an exception)
+ public object this[IMessage<TMessage> message, int index] {
+ get { throw new InvalidOperationException("Repeated operation called on singular field"); }
+ }
+
+ public object this[IBuilder<TMessage> builder, int index] {
+ set { throw new InvalidOperationException("Repeated operation called on singular field"); }
+ }
+
+ public int GetRepeatedCount(IMessage<TMessage> message) {
+ throw new InvalidOperationException("Repeated operation called on singular field");
+ }
+
+ public void AddRepeated(IBuilder<TMessage> builder, object value) {
+ throw new InvalidOperationException("Repeated operation called on singular field");
+ }
+ #endregion
+ }
+}
diff --git a/csharp/ProtocolBuffers/FieldSet.cs b/csharp/ProtocolBuffers/FieldSet.cs
new file mode 100644
index 00000000..0efde4b1
--- /dev/null
+++ b/csharp/ProtocolBuffers/FieldSet.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers {
+ public class FieldSet {
+ public static void MergeFrom(CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ IBuilder builder) {
+
+ while (true) {
+ uint tag = input.ReadTag();
+ if (tag == 0) {
+ break;
+ }
+ if (!MergeFieldFrom(input, unknownFields, extensionRegistry,
+ builder, tag)) {
+ // end group tag
+ break;
+ }
+ }
+ }
+
+ public static bool MergeFieldFrom(CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ IBuilder builder,
+ uint tag) {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/GeneratedExtension.cs b/csharp/ProtocolBuffers/GeneratedExtension.cs
new file mode 100644
index 00000000..52d3349b
--- /dev/null
+++ b/csharp/ProtocolBuffers/GeneratedExtension.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// Base class for all generated extensions.
+ /// </summary>
+ /// <remarks>
+ /// The protocol compiler generates a static singleton instance of this
+ /// class for each extension. For exmaple, imagine a .proto file with:
+ /// <code>
+ /// message Foo {
+ /// extensions 1000 to max
+ /// }
+ ///
+ /// extend Foo {
+ /// optional int32 bar;
+ /// }
+ /// </code>
+ /// Then MyProto.Foo.Bar has type GeneratedExtension&lt;MyProto.Foo,int&gt;.
+ /// <para />
+ /// In general, users should ignore the details of this type, and
+ /// simply use the static singletons as parmaeters to the extension accessors
+ /// in ExtendableMessage and ExtendableBuilder.
+ /// </remarks>
+ public class GeneratedExtension<TContainer, TExtension> where TContainer : IMessage<TContainer> {
+ public FieldDescriptor Descriptor;
+
+ public IMessage MessageDefaultInstance;
+ }
+}
diff --git a/csharp/ProtocolBuffers/GeneratedMessage.cs b/csharp/ProtocolBuffers/GeneratedMessage.cs
new file mode 100644
index 00000000..515eadc0
--- /dev/null
+++ b/csharp/ProtocolBuffers/GeneratedMessage.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+using Google.ProtocolBuffers.FieldAccess;
+
+namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// All generated protocol message classes extend this class. It implements
+ /// most of the IMessage and IBuilder interfaces using reflection. Users
+ /// can ignore this class as an implementation detail.
+ /// </summary>
+ public abstract class GeneratedMessage<TMessage, TBuilder> : AbstractMessage, IMessage<TMessage>
+ where TMessage : GeneratedMessage<TMessage, TBuilder> where TBuilder : IBuilder<TMessage> {
+
+ private readonly UnknownFieldSet unknownFields = UnknownFieldSet.DefaultInstance;
+
+ protected abstract FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors { get; }
+
+ public override MessageDescriptor DescriptorForType {
+ get { return InternalFieldAccessors.Descriptor; }
+ }
+
+ public IMessage<TMessage> DefaultInstanceForType {
+ get { throw new System.NotImplementedException(); }
+ }
+
+ public IBuilder<TMessage> CreateBuilderForType() {
+ throw new System.NotImplementedException();
+ }
+
+ private IDictionary<FieldDescriptor, Object> GetMutableFieldMap() {
+ var ret = new Dictionary<FieldDescriptor, object>();
+ MessageDescriptor descriptor = DescriptorForType;
+ foreach (FieldDescriptor field in descriptor.Fields) {
+ IFieldAccessor<TMessage, TBuilder> accessor = InternalFieldAccessors[field];
+ if ((field.IsRepeated && accessor.GetRepeatedCount(this) != 0)
+ || accessor.Has(this)) {
+ ret[field] = accessor[this];
+ }
+ }
+ return ret;
+ }
+
+ public override IDictionary<FieldDescriptor, object> AllFields {
+ // FIXME: Make it immutable
+ get { return GetMutableFieldMap(); }
+ }
+
+ public override bool HasField(FieldDescriptor field) {
+ return InternalFieldAccessors[field].Has(this);
+ }
+
+ public override int GetRepeatedFieldCount(FieldDescriptor field) {
+ return InternalFieldAccessors[field].GetRepeatedCount(this);
+ }
+
+ public override object this[FieldDescriptor field, int index] {
+ get { return InternalFieldAccessors[field][this, index]; }
+ }
+
+ public override object this[FieldDescriptor field] {
+ get { return InternalFieldAccessors[field][this]; }
+ }
+
+ public override UnknownFieldSet UnknownFields {
+ get { return unknownFields; }
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/IBuilder.cs b/csharp/ProtocolBuffers/IBuilder.cs
index 977001c7..50279039 100644
--- a/csharp/ProtocolBuffers/IBuilder.cs
+++ b/csharp/ProtocolBuffers/IBuilder.cs
@@ -29,7 +29,6 @@ namespace Google.ProtocolBuffers {
/// how IEnumerable and IEnumerable&lt;T&gt; work.
/// </summary>
public interface IBuilder {
- IBuilder MergeFrom(CodedInputStream codedInputStream, ExtensionRegistry extensionRegistry);
/// <summary>
/// Returns true iff all required fields in the message and all
/// embedded messages are set.
@@ -41,15 +40,15 @@ namespace Google.ProtocolBuffers {
/// The returned map may or may not reflect future changes to the builder.
/// Either way, the returned map is unmodifiable.
/// </summary>
- IDictionary<ProtocolBuffers.Descriptors.FieldDescriptor, object> AllFields { get; }
+ IDictionary<FieldDescriptor, object> AllFields { get; }
/// <summary>
/// Allows getting and setting of a field.
- /// <see cref="IMessage{T}.Item(Descriptors.FieldDescriptor)"/>
+ /// <see cref="IMessage{T}.Item(FieldDescriptor)"/>
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
- object this[Descriptors.FieldDescriptor field] { get; set; }
+ object this[FieldDescriptor field] { get; set; }
/// <summary>
/// Get the message's type's descriptor.
@@ -62,18 +61,44 @@ namespace Google.ProtocolBuffers {
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
- int GetRepeatedFieldCount(Descriptors.FieldDescriptor field);
+ int GetRepeatedFieldCount(FieldDescriptor field);
/// <summary>
/// Allows getting and setting of a repeated field value.
- /// <see cref="IMessage{T}.Item(Descriptors.FieldDescriptor, int)"/>
+ /// <see cref="IMessage{T}.Item(FieldDescriptor, int)"/>
/// </summary>
- object this[Descriptors.FieldDescriptor field, int index] { get; set; }
+ object this[FieldDescriptor field, int index] { get; set; }
/// <summary>
/// <see cref="IMessage{T}.HasField"/>
/// </summary>
- bool HasField(Descriptors.FieldDescriptor field);
+ bool HasField(FieldDescriptor field);
+
+ /// <summary>
+ /// <see cref="IMessage{T}.UnknownFields"/>
+ /// </summary>
+ UnknownFieldSet UnknownFields { get; set; }
+
+ #region Non-generic versions of generic methods in IBuilder<T>
+ IBuilder Clear();
+ IBuilder MergeFrom(IMessage other);
+ IMessage Build();
+ IMessage BuildPartial();
+ IBuilder Clone();
+ IBuilder MergeFrom(CodedInputStream input);
+ IBuilder MergeFrom(CodedInputStream codedInputStream, ExtensionRegistry extensionRegistry);
+ IMessage DefaultInstanceForType { get; }
+ IBuilder NewBuilderForField<TField>(FieldDescriptor field);
+ IBuilder ClearField(FieldDescriptor field);
+ IBuilder AddRepeatedField(FieldDescriptor field, object value);
+ IBuilder MergeUnknownFields(UnknownFieldSet unknownFields);
+ IBuilder MergeFrom(ByteString data);
+ IBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry);
+ IBuilder MergeFrom(byte[] data);
+ IBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry);
+ IBuilder MergeFrom(Stream input);
+ IBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry);
+ #endregion
}
/// <summary>
@@ -85,7 +110,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Resets all fields to their default values.
/// </summary>
- IBuilder<T> Clear();
+ new IBuilder<T> Clear();
/// <summary>
/// Merge the specified other message into the message being
@@ -111,20 +136,20 @@ namespace Google.ProtocolBuffers {
/// <exception cref="UninitializedMessageException">the message
/// is missing one or more required fields; use BuildPartial to bypass
/// this check</exception>
- IMessage<T> Build();
+ new IMessage<T> Build();
/// <summary>
/// Like Build(), but does not throw an exception if the message is missing
/// required fields. Instead, a partial message is returned.
/// </summary>
/// <returns></returns>
- IMessage<T> BuildPartial();
+ new IMessage<T> BuildPartial();
/// <summary>
/// Clones this builder.
/// TODO(jonskeet): Explain depth of clone.
/// </summary>
- IBuilder<T> Clone();
+ new IBuilder<T> Clone();
/// <summary>
/// Parses a message of this type from the input and merges it with this
@@ -145,7 +170,7 @@ namespace Google.ProtocolBuffers {
/// Use BuildPartial to build, which ignores missing required fields.
/// </list>
/// </remarks>
- IBuilder<T> MergeFrom(CodedInputStream input);
+ new IBuilder<T> MergeFrom(CodedInputStream input);
/// <summary>
/// Like MergeFrom(CodedInputStream), but also parses extensions.
@@ -159,17 +184,14 @@ namespace Google.ProtocolBuffers {
/// Get's the message's type's default instance.
/// <see cref="IMessage{T}.DefaultInstanceForType" />
/// </summary>
- IMessage<T> DefaultInstanceForType { get; }
+ new IMessage<T> DefaultInstanceForType { get; }
/// <summary>
/// Create a builder for messages of the appropriate type for the given field.
/// Messages built with this can then be passed to the various mutation properties
/// and methods.
/// </summary>
- /// <typeparam name="TField"></typeparam>
- /// <param name="field"></param>
- /// <returns></returns>
- IBuilder<TField> NewBuilderForField<TField>(Descriptors.FieldDescriptor field) where TField : IMessage<TField>;
+ new IBuilder<TField> NewBuilderForField<TField>(FieldDescriptor field) where TField : IMessage<TField>;
/// <summary>
/// Clears the field. This is exactly equivalent to calling the generated
@@ -177,7 +199,7 @@ namespace Google.ProtocolBuffers {
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
- IBuilder<T> ClearField(Descriptors.FieldDescriptor field);
+ new IBuilder<T> ClearField(FieldDescriptor field);
/// <summary>
/// Appends the given value as a new element for the specified repeated field.
@@ -186,51 +208,45 @@ namespace Google.ProtocolBuffers {
/// the field does not belong to this builder's type, or the value is
/// of the incorrect type
/// </exception>
- IBuilder<T> AddRepeatedField(Descriptors.FieldDescriptor field, object value);
-
- /// <summary>
- /// <see cref="IMessage{T}.UnknownFields"/>
- /// </summary>
- UnknownFieldSet UnknownFields { get; set; }
+ new IBuilder<T> AddRepeatedField(FieldDescriptor field, object value);
/// <summary>
/// Merge some unknown fields into the set for this message.
/// </summary>
- IBuilder<T> MergeUnknownFields(UnknownFieldSet unknownFields);
+ new IBuilder<T> MergeUnknownFields(UnknownFieldSet unknownFields);
#region Convenience methods
// TODO(jonskeet): Implement these as extension methods?
-
/// <summary>
/// Parse <paramref name="data"/> as a message of this type and merge
/// it with the message being built. This is just a small wrapper around
/// MergeFrom(CodedInputStream).
/// </summary>
- IBuilder<T> MergeFrom(ByteString data);
+ new IBuilder<T> MergeFrom(ByteString data);
/// <summary>
/// Parse <paramref name="data"/> as a message of this type and merge
/// it with the message being built. This is just a small wrapper around
/// MergeFrom(CodedInputStream, ExtensionRegistry).
/// </summary>
- IBuilder<T> MergeFrom(ByteString data, ExtensionRegistry extensionRegistry);
+ new IBuilder<T> MergeFrom(ByteString data, ExtensionRegistry extensionRegistry);
/// <summary>
/// Parse <paramref name="data"/> as a message of this type and merge
/// it with the message being built. This is just a small wrapper around
/// MergeFrom(CodedInputStream).
/// </summary>
- IBuilder<T> MergeFrom(byte[] data);
+ new IBuilder<T> MergeFrom(byte[] data);
/// <summary>
/// Parse <paramref name="data"/> as a message of this type and merge
/// it with the message being built. This is just a small wrapper around
/// MergeFrom(CodedInputStream, ExtensionRegistry).
/// </summary>
- IBuilder<T> MergeFrom(byte[] data, ExtensionRegistry extensionRegistry);
+ new IBuilder<T> MergeFrom(byte[] data, ExtensionRegistry extensionRegistry);
/// <summary>
- /// Parse <paramref name="data"/> as a message of this type and merge
+ /// Parse <paramref name="input"/> as a message of this type and merge
/// it with the message being built. This is just a small wrapper around
/// MergeFrom(CodedInputStream). Note that this method always reads
/// the entire input (unless it throws an exception). If you want it to
@@ -238,14 +254,14 @@ namespace Google.ProtocolBuffers {
/// stream which limits reading. Despite usually reading the entire
/// stream, this method never closes the stream.
/// </summary>
- IBuilder<T> MergeFrom(Stream input);
+ new IBuilder<T> MergeFrom(Stream input);
/// <summary>
- /// Parse <paramref name="data"/> as a message of this type and merge
+ /// Parse <paramref name="input"/> as a message of this type and merge
/// it with the message being built. This is just a small wrapper around
/// MergeFrom(CodedInputStream, ExtensionRegistry).
/// </summary>
- IBuilder<T> MergeFrom(Stream input, ExtensionRegistry extensionRegistry);
+ new IBuilder<T> MergeFrom(Stream input, ExtensionRegistry extensionRegistry);
#endregion
}
}
diff --git a/csharp/ProtocolBuffers/IMessage.cs b/csharp/ProtocolBuffers/IMessage.cs
index cb0e7623..9aea0ea7 100644
--- a/csharp/ProtocolBuffers/IMessage.cs
+++ b/csharp/ProtocolBuffers/IMessage.cs
@@ -41,11 +41,11 @@ namespace Google.ProtocolBuffers {
/// field is set iff HasField() returns true for that field. A "repeated"
/// field is set iff GetRepeatedFieldSize() is greater than zero. The
/// values are exactly what would be returned by calling
- /// GetField(Descriptors.FieldDescriptor) for each field. The map
+ /// GetField(FieldDescriptor) for each field. The map
/// is guaranteed to be a sorted map, so iterating over it will return fields
/// in order by field number.
/// </summary>
- IDictionary<Descriptors.FieldDescriptor, object> AllFields { get; }
+ IDictionary<FieldDescriptor, object> AllFields { get; }
/// <summary>
/// Returns true if the given field is set. This is exactly equivalent
@@ -53,7 +53,7 @@ namespace Google.ProtocolBuffers {
/// </summary>
/// <exception cref="ArgumentException">the field is a repeated field,
/// or it's not a field of this type</exception>
- bool HasField(Descriptors.FieldDescriptor field);
+ bool HasField(FieldDescriptor field);
/// <summary>
/// Obtains the value of the given field, or the default value if
@@ -61,7 +61,7 @@ namespace Google.ProtocolBuffers {
/// value is returned. For embedded message fields, the sub-message
/// is returned. For repeated fields, an IList&lt;T&gt; is returned.
/// </summary>
- object this[Descriptors.FieldDescriptor field] { get; }
+ object this[FieldDescriptor field] { get; }
/// <summary>
/// Returns the number of elements of a repeated field. This is
@@ -70,7 +70,7 @@ namespace Google.ProtocolBuffers {
/// </summary>
/// <exception cref="ArgumentException">the field is not a repeated field,
/// or it's not a field of this type</exception>
- int GetRepeatedFieldCount(Descriptors.FieldDescriptor field);
+ int GetRepeatedFieldCount(FieldDescriptor field);
/// <summary>
/// Gets an element of a repeated field. For value type fields
@@ -81,7 +81,7 @@ namespace Google.ProtocolBuffers {
/// or it's not a field of this type</exception>
/// <exception cref="ArgumentOutOfRangeException">the index is out of
/// range for the repeated field's value</exception>
- object this[Descriptors.FieldDescriptor field, int index] { get; }
+ object this[FieldDescriptor field, int index] { get; }
/// <summary>
/// Returns the unknown fields for this message.
diff --git a/csharp/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/ProtocolBuffers/ProtocolBuffers.csproj
index e3c22ac5..c22720f4 100644
--- a/csharp/ProtocolBuffers/ProtocolBuffers.csproj
+++ b/csharp/ProtocolBuffers/ProtocolBuffers.csproj
@@ -36,23 +36,34 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="AbstractBuilder.cs" />
<Compile Include="AbstractMessage.cs" />
<Compile Include="Autogenerated.cs" />
<Compile Include="ByteString.cs" />
<Compile Include="CodedInputStream.cs" />
<Compile Include="CodedOutputStream.cs" />
+ <Compile Include="Collections\Lists.cs" />
<Compile Include="Descriptors\EnumValueDescriptor.cs" />
<Compile Include="Descriptors\FieldDescriptor.cs" />
<Compile Include="Descriptors\FieldType.cs" />
<Compile Include="Descriptors\MappedType.cs" />
<Compile Include="Descriptors\MessageDescriptor.cs" />
+ <Compile Include="ExtensionInfo.cs" />
<Compile Include="ExtensionRegistry.cs" />
+ <Compile Include="FieldAccess\Delegates.cs" />
+ <Compile Include="FieldAccess\IFieldAccessor.cs" />
+ <Compile Include="FieldAccess\FieldAccessorTable.cs" />
+ <Compile Include="FieldAccess\SingularFieldAccessor.cs" />
+ <Compile Include="FieldSet.cs" />
+ <Compile Include="GeneratedExtension.cs" />
+ <Compile Include="GeneratedMessage.cs" />
<Compile Include="IBuilder.cs" />
<Compile Include="IMessage.cs" />
<Compile Include="InvalidProtocolBufferException.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TextFormat.cs" />
<Compile Include="UninitializedMessageException.cs" />
+ <Compile Include="UnknownField.cs" />
<Compile Include="UnknownFieldSet.cs" />
<Compile Include="WireFormat.cs" />
</ItemGroup>
diff --git a/csharp/ProtocolBuffers/TextFormat.cs b/csharp/ProtocolBuffers/TextFormat.cs
index b574c56d..e789d0d7 100644
--- a/csharp/ProtocolBuffers/TextFormat.cs
+++ b/csharp/ProtocolBuffers/TextFormat.cs
@@ -7,5 +7,9 @@ namespace Google.ProtocolBuffers {
public static string PrintToString(IMessage message) {
throw new NotImplementedException();
}
+
+ internal static string PrintToString(UnknownFieldSet unknownFieldSet) {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/csharp/ProtocolBuffers/UnknownField.cs b/csharp/ProtocolBuffers/UnknownField.cs
new file mode 100644
index 00000000..1866cbba
--- /dev/null
+++ b/csharp/ProtocolBuffers/UnknownField.cs
@@ -0,0 +1,306 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Google.ProtocolBuffers.Collections;
+
+namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Represents a single field in an UnknownFieldSet.
+ ///
+ /// An UnknownField consists of five lists of values. The lists correspond
+ /// to the five "wire types" used in the protocol buffer binary format.
+ /// The wire type of each field can be determined from the encoded form alone,
+ /// without knowing the field's declared type. So, we are able to parse
+ /// unknown values at least this far and separate them. Normally, only one
+ /// of the five lists will contain any values, since it is impossible to
+ /// define a valid message type that declares two different types for the
+ /// same field number. However, the code is designed to allow for the case
+ /// where the same unknown field number is encountered using multiple different
+ /// wire types.
+ ///
+ /// UnknownField is an immutable class. To construct one, you must use an
+ /// UnknownField.Builder.
+ /// </summary>
+ public sealed class UnknownField {
+
+ private static readonly UnknownField defaultInstance = CreateBuilder().Build();
+ private readonly ReadOnlyCollection<ulong> varintList;
+ private readonly ReadOnlyCollection<int> fixed32List;
+ private readonly ReadOnlyCollection<long> fixed64List;
+ private readonly ReadOnlyCollection<ByteString> lengthDelimitedList;
+ private readonly ReadOnlyCollection<UnknownFieldSet> groupList;
+
+ private UnknownField(ReadOnlyCollection<ulong> varintList,
+ ReadOnlyCollection<int> fixed32List,
+ ReadOnlyCollection<long> fixed64List,
+ ReadOnlyCollection<ByteString> lengthDelimitedList,
+ ReadOnlyCollection<UnknownFieldSet> groupList) {
+ this.varintList = varintList;
+ this.fixed32List = fixed32List;
+ this.fixed64List = fixed64List;
+ this.lengthDelimitedList = lengthDelimitedList;
+ this.groupList = groupList;
+ }
+
+ public static UnknownField DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ /// <summary>
+ /// The list of varint values for this field.
+ /// </summary>
+ public IList<ulong> VarintList {
+ get { return varintList; }
+ }
+
+ /// <summary>
+ /// The list of fixed32 values for this field.
+ /// </summary>
+ public IList<int> Fixed32List {
+ get { return fixed32List; }
+ }
+
+ /// <summary>
+ /// The list of fixed64 values for this field.
+ /// </summary>
+ public IList<long> Fixed64List {
+ get { return fixed64List; }
+ }
+
+ /// <summary>
+ /// The list of length-delimited values for this field.
+ /// </summary>
+ public IList<ByteString> LengthDelimitedList {
+ get { return lengthDelimitedList; }
+ }
+
+ /// <summary>
+ /// The list of embedded group values for this field. These
+ /// are represented using UnknownFieldSets rather than Messages
+ /// since the group's type is presumably unknown.
+ /// </summary>
+ public IList<UnknownFieldSet> GroupList {
+ get { return groupList; }
+ }
+
+ /// <summary>
+ /// Constructs a new Builder.
+ /// </summary>
+ public static Builder CreateBuilder() {
+ return new Builder();
+ }
+
+ /// <summary>
+ /// Constructs a new Builder and initializes it to a copy of <paramref name="copyFrom"/>.
+ /// </summary>
+ public static Builder CreateBuilder(UnknownField copyFrom) {
+ return new Builder().MergeFrom(copyFrom);
+ }
+
+ /// <summary>
+ /// Serializes the field, including the field number, and writes it to
+ /// <paramref name="output"/>.
+ /// </summary>
+ public void WriteTo(int fieldNumber, CodedOutputStream output) {
+ foreach (ulong value in varintList) {
+ output.WriteUInt64(fieldNumber, value);
+ }
+ foreach (int value in fixed32List) {
+ output.WriteFixed32(fieldNumber, value);
+ }
+ foreach (long value in fixed64List) {
+ output.WriteFixed64(fieldNumber, value);
+ }
+ foreach (ByteString value in lengthDelimitedList) {
+ output.WriteBytes(fieldNumber, value);
+ }
+ foreach (UnknownFieldSet value in groupList) {
+ output.WriteUnknownGroup(fieldNumber, value);
+ }
+ }
+
+ /// <summary>
+ /// Computes the number of bytes required to encode this field, including field
+ /// number.
+ /// </summary>
+ public int GetSerializedSize(int fieldNumber) {
+ int result = 0;
+ foreach (ulong value in varintList) {
+ result += CodedOutputStream.ComputeUInt64Size(fieldNumber, value);
+ }
+ foreach (int value in fixed32List) {
+ result += CodedOutputStream.ComputeFixed32Size(fieldNumber, value);
+ }
+ foreach (long value in fixed64List) {
+ result += CodedOutputStream.ComputeFixed64Size(fieldNumber, value);
+ }
+ foreach (ByteString value in lengthDelimitedList) {
+ result += CodedOutputStream.ComputeBytesSize(fieldNumber, value);
+ }
+ foreach (UnknownFieldSet value in groupList) {
+ result += CodedOutputStream.ComputeUnknownGroupSize(fieldNumber, value);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Serializes the length-delimited values of the field, including field
+ /// number, and writes them to <paramref name="output"/> using the MessageSet wire format.
+ /// </summary>
+ /// <param name="fieldNumber"></param>
+ /// <param name="output"></param>
+ public void WriteAsMessageSetExtensionTo(int fieldNumber, CodedOutputStream output) {
+ foreach (ByteString value in lengthDelimitedList) {
+ output.WriteRawMessageSetExtension(fieldNumber, value);
+ }
+ }
+
+ /// <summary>
+ /// Get the number of bytes required to encode this field, incuding field number,
+ /// using the MessageSet wire format.
+ /// </summary>
+ public int GetSerializedSizeAsMessageSetExtension(int fieldNumber) {
+ int result = 0;
+ foreach (ByteString value in lengthDelimitedList) {
+ result += CodedOutputStream.ComputeRawMessageSetExtensionSize(fieldNumber, value);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Used to build instances of UnknownField.
+ /// </summary>
+ public class Builder {
+
+ private List<ulong> varintList;
+ private List<int> fixed32List;
+ private List<long> fixed64List;
+ private List<ByteString> lengthDelimitedList;
+ private List<UnknownFieldSet> groupList;
+
+ /// <summary>
+ /// Builds the field. After building, the builder is reset to an empty
+ /// state. (This is actually easier than making it unusable.)
+ /// </summary>
+ public UnknownField Build() {
+ return new UnknownField(MakeReadOnly(ref varintList),
+ MakeReadOnly(ref fixed32List),
+ MakeReadOnly(ref fixed64List),
+ MakeReadOnly(ref lengthDelimitedList),
+ MakeReadOnly(ref groupList));
+ }
+
+ /// <summary>
+ /// Merge the values in <paramref name="other" /> into this field. For each list
+ /// of values, <paramref name="other"/>'s values are append to the ones in this
+ /// field.
+ /// </summary>
+ public Builder MergeFrom(UnknownField other) {
+ varintList = AddAll(varintList, other.VarintList);
+ fixed32List = AddAll(fixed32List, other.Fixed32List);
+ fixed64List = AddAll(fixed64List, other.Fixed64List);
+ lengthDelimitedList = AddAll(lengthDelimitedList, other.LengthDelimitedList);
+ groupList = AddAll(groupList, other.GroupList);
+ return this;
+ }
+
+ /// <summary>
+ /// Returns a new list containing all of the given specified values from
+ /// both the <paramref name="current"/> and <paramref name="extras"/> lists.
+ /// If <paramref name="current" /> is null and <paramref name="extras"/> is empty,
+ /// null is returned. Otherwise, either a new list is created (if <paramref name="current" />
+ /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />.
+ /// </summary>
+ private static List<T> AddAll<T>(List<T> current, IList<T> extras)
+ {
+ if (extras.Count == 0) {
+ return current;
+ }
+ if (current == null) {
+ current = new List<T>(extras);
+ } else {
+ current.AddRange(extras);
+ }
+ return current;
+ }
+
+ /// <summary>
+ /// Clears the contents of this builder.
+ /// </summary>
+ public Builder Clear() {
+ varintList = null;
+ fixed32List = null;
+ fixed64List = null;
+ lengthDelimitedList = null;
+ groupList = null;
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a varint value.
+ /// </summary>
+ public Builder AddVarint(ulong value) {
+ varintList = Add(varintList, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a fixed32 value.
+ /// </summary>
+ public Builder AddFixed32(int value) {
+ fixed32List = Add(fixed32List, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a fixed64 value.
+ /// </summary>
+ public Builder AddFixed64(long value) {
+ fixed64List = Add(fixed64List, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds a length-delimited value.
+ /// </summary>
+ public Builder AddLengthDelimited(ByteString value) {
+ lengthDelimitedList = Add(lengthDelimitedList, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds an embedded group.
+ /// </summary>
+ /// <param name="value"></param>
+ /// <returns></returns>
+ public Builder AddGroup(UnknownFieldSet value) {
+ groupList = Add(groupList, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating
+ /// a new list if <paramref name="list"/> is null. The list is returned - either
+ /// the original reference or the new list.
+ /// </summary>
+ private static List<T> Add<T>(List<T> list, T value) {
+ if (list == null) {
+ list = new List<T>();
+ }
+ list.Add(value);
+ return list;
+ }
+
+ /// <summary>
+ /// Returns a read-only version of the given IList, and clears
+ /// the field used for <paramref name="list"/>. If the value
+ /// is null, an empty list is produced using Lists.Empty.
+ /// </summary>
+ /// <returns></returns>
+ private static ReadOnlyCollection<T> MakeReadOnly<T>(ref List<T> list) {
+ ReadOnlyCollection<T> ret = list == null ? Lists<T>.Empty : new ReadOnlyCollection<T>(list);
+ list = null;
+ return ret;
+ }
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/UnknownFieldSet.cs b/csharp/ProtocolBuffers/UnknownFieldSet.cs
index 787126ad..a0d84d40 100644
--- a/csharp/ProtocolBuffers/UnknownFieldSet.cs
+++ b/csharp/ProtocolBuffers/UnknownFieldSet.cs
@@ -14,26 +14,404 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
+using System.Collections.Generic;
+using System.IO;
namespace Google.ProtocolBuffers {
public class UnknownFieldSet {
- public int SerializedSizeAsMessageSet;
+ private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
+
+ private readonly IDictionary<int, UnknownField> fields;
+
+ private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
+ this.fields = fields;
+ }
+
+ /// <summary>
+ /// Creates a new unknown field set builder.
+ /// </summary>
+ public static Builder CreateBuilder() {
+ return new Builder();
+ }
+
+ /// <summary>
+ /// Creates a new unknown field set builder
+ /// and initialize it from <paramref name="original"/>.
+ /// </summary>
+ public static Builder CreateBuilder(UnknownFieldSet original) {
+ return new Builder().MergeFrom(original);
+ }
+
+ public static UnknownFieldSet DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ /// <summary>
+ /// Creates and returns a copy of the mapping from field numbers to values.
+ /// </summary>
+ public IDictionary<int, UnknownField> FieldDictionary {
+ get { return new Dictionary<int, UnknownField>(fields); }
+ }
+
+ /// <summary>
+ /// Checks whether or not the given field number is present in the set.
+ /// </summary>
+ public bool HasField(int field) {
+ return fields.ContainsKey(field);
+ }
+
+ /// <summary>
+ /// Fetches a field by number, returning an empty field if not present.
+ /// Never returns null.
+ /// </summary>
+ public UnknownField this[int number] {
+ get {
+ UnknownField ret;
+ if (!fields.TryGetValue(number, out ret)) {
+ ret = UnknownField.DefaultInstance;
+ }
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Serializes the set and writes it to <paramref name="output"/>.
+ /// </summary>
public void WriteTo(CodedOutputStream output) {
- throw new NotImplementedException();
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ entry.Value.WriteTo(entry.Key, output);
+ }
}
- public int SerializedSize { get { return 0; } }
+ /// <summary>
+ /// Gets the number of bytes required to encode this set.
+ /// </summary>
+ public int SerializedSize {
+ get {
+ int result = 0;
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ result += entry.Value.GetSerializedSize(entry.Key);
+ }
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Converts the set to a string in protocol buffer text format. This
+ /// is just a trivial wrapper around TextFormat.PrintToString.
+ /// </summary>
+ public override String ToString() {
+ return TextFormat.PrintToString(this);
+ }
+
+ /// <summary>
+ /// Serializes the message to a ByteString and returns it. This is
+ /// just a trivial wrapper around WriteTo(CodedOutputStream).
+ /// </summary>
+ /// <returns></returns>
+ public ByteString ToByteString() {
+ ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
+ WriteTo(codedBuilder.CodedOutput);
+ return codedBuilder.Build();
+ }
+
+ /// <summary>
+ /// Serializes the message to a byte array and returns it. This is
+ /// just a trivial wrapper around WriteTo(CodedOutputStream).
+ /// </summary>
+ /// <returns></returns>
+ public byte[] ToByteArray() {
+ byte[] data = new byte[SerializedSize];
+ CodedOutputStream output = CodedOutputStream.CreateInstance(data);
+ WriteTo(output);
+ output.CheckNoSpaceLeft();
+ return data;
+ }
+
+ /// <summary>
+ /// Serializes the message and writes it to <paramref name="output"/>. This is
+ /// just a trivial wrapper around WriteTo(CodedOutputStream).
+ /// </summary>
+ /// <param name="output"></param>
+ public void WriteTo(Stream output) {
+ CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
+ WriteTo(codedOutput);
+ codedOutput.Flush();
+ }
+
+ /// <summary>
+ /// Serializes the set and writes it to <paramref name="output"/> using
+ /// the MessageSet wire format.
+ /// </summary>
+ public void WriteAsMessageSetTo(CodedOutputStream output) {
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of bytes required to encode this set using the MessageSet
+ /// wire format.
+ /// </summary>
+ public int SerializedSizeAsMessageSet {
+ get {
+ int result = 0;
+ foreach (KeyValuePair<int, UnknownField> entry in fields) {
+ result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
+ }
+ return result;
+ }
+ }
+
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given input.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(CodedInputStream input) {
+ return CreateBuilder().MergeFrom(input).Build();
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given data.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(ByteString data) {
+ return CreateBuilder().MergeFrom(data).Build();
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given data.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(byte[] data) {
+ return CreateBuilder().MergeFrom(data).Build();
+ }
+
+ /// <summary>
+ /// Parses an UnknownFieldSet from the given input.
+ /// </summary>
+ public static UnknownFieldSet ParseFrom(Stream input) {
+ return CreateBuilder().MergeFrom(input).Build();
+ }
public class Builder
{
- internal void MergeFrom(CodedInputStream codedInputStream) {
- throw new NotImplementedException();
+ private Dictionary<int, UnknownField> fields = new Dictionary<int, UnknownField>();
+
+ // Optimization: We keep around a builder for the last field that was
+ // modified so that we can efficiently add to it multiple times in a
+ // row (important when parsing an unknown repeated field).
+ int lastFieldNumber;
+ UnknownField.Builder lastField;
+
+ internal Builder() {
+ }
+
+ /// <summary>
+ /// Returns a field builder for the specified field number, including any values
+ /// which already exist.
+ /// </summary>
+ private UnknownField.Builder GetFieldBuilder(int number) {
+ if (lastField != null) {
+ if (number == lastFieldNumber) {
+ return lastField;
+ }
+ // Note: AddField() will reset lastField and lastFieldNumber.
+ AddField(lastFieldNumber, lastField.Build());
+ }
+ if (number == 0) {
+ return null;
+ }
+
+ lastField = UnknownField.CreateBuilder();
+ UnknownField existing;
+ if (fields.TryGetValue(number, out existing)) {
+ lastField.MergeFrom(existing);
+ }
+ lastFieldNumber = number;
+ return lastField;
+ }
+
+ /// <summary>
+ /// Build the UnknownFieldSet and return it. Once this method has been called,
+ /// this instance will no longer be usable. Calling any method after this
+ /// will throw a NullReferenceException.
+ /// </summary>
+ public UnknownFieldSet Build() {
+ GetFieldBuilder(0); // Force lastField to be built.
+ UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
+ fields = null;
+ return result;
+ }
+
+ /// <summary>
+ /// Adds a field to the set. If a field with the same number already exists, it
+ /// is replaced.
+ /// </summary>
+ public Builder AddField(int number, UnknownField field) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ if (lastField != null && lastFieldNumber == number) {
+ // Discard this.
+ lastField = null;
+ lastFieldNumber = 0;
+ }
+ fields[number] = field;
+ return this;
+ }
+
+ /// <summary>
+ /// Resets the builder to an empty set.
+ /// </summary>
+ public Builder Clear() {
+ fields.Clear();
+ lastFieldNumber = 0;
+ lastField = null;
+ return this;
+ }
+
+ /// <summary>
+ /// Parse an entire message from <paramref name="input"/> and merge
+ /// its fields into this set.
+ /// </summary>
+ public Builder MergeFrom(CodedInputStream input) {
+ while (true) {
+ uint tag = input.ReadTag();
+ if (tag == 0 || !MergeFieldFrom(tag, input)) {
+ break;
+ }
+ }
+ return this;
+ }
+
+ /// <summary>
+ /// Parse a single field from <paramref name="input"/> and merge it
+ /// into this set.
+ /// </summary>
+ /// <param name="tag">The field's tag number, which was already parsed.</param>
+ /// <param name="input">The coded input stream containing the field</param>
+ /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
+ public bool MergeFieldFrom(uint tag, CodedInputStream input) {
+ int number = WireFormat.GetTagFieldNumber(tag);
+ switch (WireFormat.GetTagWireType(tag)) {
+ case WireFormat.WireType.Varint:
+ // TODO(jonskeet): Check this is correct (different to Java)
+ GetFieldBuilder(number).AddVarint(input.ReadUInt64());
+ return true;
+ case WireFormat.WireType.Fixed64:
+ GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
+ return true;
+ case WireFormat.WireType.LengthDelimited:
+ GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
+ return true;
+ case WireFormat.WireType.StartGroup: {
+ Builder subBuilder = CreateBuilder();
+ input.ReadUnknownGroup(number, subBuilder);
+ GetFieldBuilder(number).AddGroup(subBuilder.Build());
+ return true;
+ }
+ case WireFormat.WireType.EndGroup:
+ return false;
+ case WireFormat.WireType.Fixed32:
+ GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
+ return true;
+ default:
+ throw InvalidProtocolBufferException.InvalidWireType();
+ }
+ }
+
+ /// <summary>
+ /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
+ /// with the set being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ public Builder MergeFrom(Stream input) {
+ CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
+ MergeFrom(codedInput);
+ codedInput.CheckLastTagWas(0);
+ return this;
+ }
+
+ /// <summary>
+ /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
+ /// with the set being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ public Builder MergeFrom(ByteString data) {
+ CodedInputStream input = data.CreateCodedInput();
+ MergeFrom(input);
+ input.CheckLastTagWas(0);
+ return this;
+ }
+
+ /// <summary>
+ /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
+ /// with the set being built. This is just a small wrapper around
+ /// MergeFrom(CodedInputStream).
+ /// </summary>
+ public Builder MergeFrom(byte[] data) {
+ CodedInputStream input = CodedInputStream.CreateInstance(data);
+ MergeFrom(input);
+ input.CheckLastTagWas(0);
+ return this;
+ }
+
+ /// <summary>
+ /// Convenience method for merging a new field containing a single varint
+ /// value. This is used in particular when an unknown enum value is
+ /// encountered.
+ /// </summary>
+ public Builder MergeVarintField(int number, ulong value) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ GetFieldBuilder(number).AddVarint(value);
+ return this;
+ }
+
+ /// <summary>
+ /// Merges the fields from <paramref name="other"/> into this set.
+ /// If a field number exists in both sets, the values in <paramref name="other"/>
+ /// will be appended to the values in this set.
+ /// </summary>
+ public Builder MergeFrom(UnknownFieldSet other) {
+ if (other != DefaultInstance) {
+ foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
+ MergeField(entry.Key, entry.Value);
+ }
+ }
+ return this;
+ }
+
+ /// <summary>
+ /// Checks if the given field number is present in the set.
+ /// </summary>
+ public bool HasField(int number) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ return number == lastFieldNumber || fields.ContainsKey(number);
+ }
+
+ /// <summary>
+ /// Adds a field to the unknown field set. If a field with the same
+ /// number already exists, the two are merged.
+ /// </summary>
+ public Builder MergeField(int number, UnknownField field) {
+ if (number == 0) {
+ throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
+ }
+ if (HasField(number)) {
+ GetFieldBuilder(number).MergeFrom(field);
+ } else {
+ // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
+ // in this case, but that would create a copy of the Field object.
+ // We'd rather reuse the one passed to us, so call AddField() instead.
+ AddField(number, field);
+ }
+ return this;
}
- }
- internal void WriteAsMessageSetTo(CodedOutputStream output) {
- throw new NotImplementedException();
}
}
}
diff --git a/csharp/ProtocolBuffers/WireFormat.cs b/csharp/ProtocolBuffers/WireFormat.cs
index ade1ebb1..0045e369 100644
--- a/csharp/ProtocolBuffers/WireFormat.cs
+++ b/csharp/ProtocolBuffers/WireFormat.cs
@@ -43,8 +43,8 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// Given a tag value, determines the field number (the upper 29 bits).
/// </summary>
- public static uint GetTagFieldNumber(uint tag) {
- return tag >> TagTypeBits;
+ public static int GetTagFieldNumber(uint tag) {
+ return (int) tag >> TagTypeBits;
}
/// <summary>