aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/ProtocolBuffers
diff options
context:
space:
mode:
authorJie Luo <jieluo@google.com>2015-05-29 12:48:25 -0700
committerJie Luo <jieluo@google.com>2015-05-29 13:29:30 -0700
commitf7b417ddfe63cb4d39775e5fd4560894cc547d65 (patch)
tree2ffb9956310e6aeb46078e7ad58db94d517f1d86 /csharp/src/ProtocolBuffers
parent55df12194f5f0348c3ddf0636c63ba2b3978fab5 (diff)
downloadprotobuf-f7b417ddfe63cb4d39775e5fd4560894cc547d65.tar.gz
protobuf-f7b417ddfe63cb4d39775e5fd4560894cc547d65.tar.bz2
protobuf-f7b417ddfe63cb4d39775e5fd4560894cc547d65.zip
Add oneof support for C#
Diffstat (limited to 'csharp/src/ProtocolBuffers')
-rw-r--r--csharp/src/ProtocolBuffers/AbstractBuilder.cs8
-rw-r--r--csharp/src/ProtocolBuffers/AbstractMessage.cs2
-rw-r--r--csharp/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs18
-rw-r--r--csharp/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs28
-rw-r--r--csharp/src/ProtocolBuffers/Descriptors/OneofDescriptor.cs78
-rw-r--r--csharp/src/ProtocolBuffers/DynamicMessage.cs122
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs46
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/OneofAccessor.cs91
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs3
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs4
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs22
-rw-r--r--csharp/src/ProtocolBuffers/GeneratedBuilder.cs16
-rw-r--r--csharp/src/ProtocolBuffers/GeneratedMessage.cs10
-rw-r--r--csharp/src/ProtocolBuffers/IBuilder.cs14
-rw-r--r--csharp/src/ProtocolBuffers/IMessage.cs4
-rw-r--r--csharp/src/ProtocolBuffers/ProtocolBuffers.csproj4
16 files changed, 452 insertions, 18 deletions
diff --git a/csharp/src/ProtocolBuffers/AbstractBuilder.cs b/csharp/src/ProtocolBuffers/AbstractBuilder.cs
index e7a41fb3..8e33e931 100644
--- a/csharp/src/ProtocolBuffers/AbstractBuilder.cs
+++ b/csharp/src/ProtocolBuffers/AbstractBuilder.cs
@@ -58,8 +58,11 @@ namespace Google.ProtocolBuffers
public abstract int GetRepeatedFieldCount(FieldDescriptor field);
public abstract object this[FieldDescriptor field, int index] { get; set; }
public abstract bool HasField(FieldDescriptor field);
+ public abstract bool HasOneof(OneofDescriptor oneof);
+ public abstract FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof);
public abstract IBuilder CreateBuilderForField(FieldDescriptor field);
public abstract TBuilder ClearField(FieldDescriptor field);
+ public abstract TBuilder ClearOneof(OneofDescriptor oneof);
public abstract TBuilder AddRepeatedField(FieldDescriptor field, object value);
#endregion
@@ -248,6 +251,11 @@ namespace Google.ProtocolBuffers
return ClearField(field);
}
+ IBuilder IBuilder.WeakClearOneof(OneofDescriptor oneof)
+ {
+ return ClearOneof(oneof);
+ }
+
#endregion
/// <summary>
diff --git a/csharp/src/ProtocolBuffers/AbstractMessage.cs b/csharp/src/ProtocolBuffers/AbstractMessage.cs
index 16c8c786..ef057e6f 100644
--- a/csharp/src/ProtocolBuffers/AbstractMessage.cs
+++ b/csharp/src/ProtocolBuffers/AbstractMessage.cs
@@ -62,6 +62,8 @@ namespace Google.ProtocolBuffers
public abstract MessageDescriptor DescriptorForType { get; }
public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
public abstract bool HasField(FieldDescriptor field);
+ public abstract bool HasOneof(OneofDescriptor oneof);
+ public abstract FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof);
public abstract object this[FieldDescriptor field] { get; }
public abstract int GetRepeatedFieldCount(FieldDescriptor field);
public abstract object this[FieldDescriptor field, int index] { get; }
diff --git a/csharp/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs b/csharp/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
index 076dc852..e7f5a3c1 100644
--- a/csharp/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
+++ b/csharp/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
@@ -47,6 +47,7 @@ namespace Google.ProtocolBuffers.Descriptors
private EnumDescriptor enumType;
private MessageDescriptor messageType;
private MessageDescriptor containingType;
+ private OneofDescriptor containingOneof;
private object defaultValue;
private FieldType fieldType;
private MappedType mappedType;
@@ -94,6 +95,16 @@ namespace Google.ProtocolBuffers.Descriptors
"FieldDescriptorProto.Extendee set for non-extension field.");
}
containingType = parent;
+ if (proto.HasOneofIndex)
+ {
+ if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDeclCount)
+ {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.oneof_index is out of range for type " + parent.Name);
+ }
+ containingOneof = parent.Oneofs[proto.OneofIndex];
+ containingOneof.fieldCount ++;
+ }
extensionScope = null;
}
@@ -253,7 +264,12 @@ namespace Google.ProtocolBuffers.Descriptors
{
get { return containingType; }
}
-
+
+ public OneofDescriptor ContainingOneof
+ {
+ get { return containingOneof; }
+ }
+
/// <summary>
/// For extensions defined nested within message types, gets
/// the outer type. Not valid for non-extension fields.
diff --git a/csharp/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs b/csharp/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs
index 5b29849c..c00711b9 100644
--- a/csharp/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs
+++ b/csharp/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs
@@ -45,6 +45,7 @@ namespace Google.ProtocolBuffers.Descriptors
private readonly IList<EnumDescriptor> enumTypes;
private readonly IList<FieldDescriptor> fields;
private readonly IList<FieldDescriptor> extensions;
+ private readonly IList<OneofDescriptor> oneofs;
private bool hasRequiredFields;
internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
@@ -52,6 +53,10 @@ namespace Google.ProtocolBuffers.Descriptors
{
containingType = parent;
+ oneofs = DescriptorUtil.ConvertAndMakeReadOnly(proto.OneofDeclList,
+ (oneof, index) =>
+ new OneofDescriptor(oneof, file, this, index));
+
nestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.NestedTypeList,
(type, index) =>
new MessageDescriptor(type, file, this, index));
@@ -69,6 +74,19 @@ namespace Google.ProtocolBuffers.Descriptors
(field, index) =>
new FieldDescriptor(field, file, this, index, true));
+ for (int i = 0; i < proto.OneofDeclCount; i++)
+ {
+ oneofs[i].fields = new FieldDescriptor[oneofs[i].FieldCount];
+ oneofs[i].fieldCount = 0;
+ }
+ for (int i = 0; i< proto.FieldCount; i++)
+ {
+ OneofDescriptor oneofDescriptor = fields[i].ContainingOneof;
+ if (oneofDescriptor != null)
+ {
+ oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
+ }
+ }
file.DescriptorPool.AddSymbol(this);
}
@@ -112,6 +130,11 @@ namespace Google.ProtocolBuffers.Descriptors
get { return enumTypes; }
}
+ public IList<OneofDescriptor> Oneofs
+ {
+ get { return oneofs; }
+ }
+
/// <summary>
/// Returns a pre-computed result as to whether this message
/// has required fields. This includes optional fields which are
@@ -189,6 +212,11 @@ namespace Google.ProtocolBuffers.Descriptors
{
extension.CrossLink();
}
+
+ foreach (OneofDescriptor oneof in oneofs)
+ {
+ // oneof.C
+ }
}
internal void CheckRequiredFields()
diff --git a/csharp/src/ProtocolBuffers/Descriptors/OneofDescriptor.cs b/csharp/src/ProtocolBuffers/Descriptors/OneofDescriptor.cs
new file mode 100644
index 00000000..aa62853b
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/Descriptors/OneofDescriptor.cs
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// Author: jieluo@google.com (Jie Luo)
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Google.ProtocolBuffers.DescriptorProtos;
+
+namespace Google.ProtocolBuffers.Descriptors
+{
+ public sealed class OneofDescriptor
+ {
+ private int index;
+ private OneofDescriptorProto proto;
+ private FileDescriptor file;
+ private MessageDescriptor containingType;
+ internal int fieldCount;
+ internal IList<FieldDescriptor> fields;
+
+ internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file,
+ MessageDescriptor parent, int index)
+ {
+ this.proto = proto;
+ this.file = file;
+ this.index = index;
+
+ containingType = parent;
+ fieldCount = 0;
+ }
+
+ public int Index
+ {
+ get { return index; }
+ }
+
+ public MessageDescriptor ContainingType
+ {
+ get { return containingType; }
+ }
+
+ public int FieldCount
+ {
+ get { return fieldCount; }
+ }
+
+ public FieldDescriptor Field(int index)
+ {
+ return fields[index];
+ }
+ }
+}
diff --git a/csharp/src/ProtocolBuffers/DynamicMessage.cs b/csharp/src/ProtocolBuffers/DynamicMessage.cs
index e39efb12..0a8772ca 100644
--- a/csharp/src/ProtocolBuffers/DynamicMessage.cs
+++ b/csharp/src/ProtocolBuffers/DynamicMessage.cs
@@ -48,6 +48,7 @@ namespace Google.ProtocolBuffers
{
private readonly MessageDescriptor type;
private readonly FieldSet fields;
+ private readonly FieldDescriptor[] oneofCase;
private readonly UnknownFieldSet unknownFields;
private int memoizedSize = -1;
@@ -57,10 +58,12 @@ namespace Google.ProtocolBuffers
/// <param name="type"></param>
/// <param name="fields"></param>
/// <param name="unknownFields"></param>
- private DynamicMessage(MessageDescriptor type, FieldSet fields, UnknownFieldSet unknownFields)
+ private DynamicMessage(MessageDescriptor type, FieldSet fields,
+ FieldDescriptor[] oneofCase, UnknownFieldSet unknownFields)
{
this.type = type;
this.fields = fields;
+ this.oneofCase = oneofCase;
this.unknownFields = unknownFields;
}
@@ -71,7 +74,9 @@ namespace Google.ProtocolBuffers
/// <returns></returns>
public static DynamicMessage GetDefaultInstance(MessageDescriptor type)
{
- return new DynamicMessage(type, FieldSet.DefaultInstance, UnknownFieldSet.DefaultInstance);
+ int oneofDescriptorCount = type.Proto.OneofDeclCount;
+ FieldDescriptor[] oneofCase = new FieldDescriptor[oneofDescriptorCount];
+ return new DynamicMessage(type, FieldSet.DefaultInstance, oneofCase, UnknownFieldSet.DefaultInstance);
}
/// <summary>
@@ -201,6 +206,23 @@ namespace Google.ProtocolBuffers
get { return fields.AllFieldDescriptors; }
}
+ public override bool HasOneof(OneofDescriptor oneof)
+ {
+ VerifyContainingOneofType(oneof);
+ FieldDescriptor field = oneofCase[oneof.Index];
+ if (field == null)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public override FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof)
+ {
+ VerifyContainingOneofType(oneof);
+ return oneofCase[oneof.Index];
+ }
+
public override bool HasField(FieldDescriptor field)
{
VerifyContainingType(field);
@@ -306,12 +328,24 @@ namespace Google.ProtocolBuffers
}
/// <summary>
+ /// Verifies that the oneof is an oneof of this message.
+ /// </summary>
+ private void VerifyContainingOneofType(OneofDescriptor oneof)
+ {
+ if (oneof.ContainingType != type)
+ {
+ throw new ArgumentException("OneofDescritpor does not match message type");
+ }
+ }
+
+ /// <summary>
/// Builder for dynamic messages. Instances are created with DynamicMessage.CreateBuilder.
/// </summary>
public sealed partial class Builder : AbstractBuilder<DynamicMessage, Builder>
{
private readonly MessageDescriptor type;
private FieldSet fields;
+ private FieldDescriptor[] oneofCase;
private UnknownFieldSet unknownFields;
internal Builder(MessageDescriptor type)
@@ -319,6 +353,7 @@ namespace Google.ProtocolBuffers
this.type = type;
this.fields = FieldSet.CreateInstance();
this.unknownFields = UnknownFieldSet.DefaultInstance;
+ this.oneofCase = new FieldDescriptor[type.Proto.OneofDeclCount];
}
protected override Builder ThisBuilder
@@ -340,6 +375,23 @@ namespace Google.ProtocolBuffers
}
fields.MergeFrom(other);
MergeUnknownFields(other.UnknownFields);
+ for (int i = 0; i < oneofCase.Length; i++)
+ {
+ if (other.HasOneof(type.Oneofs[i]))
+ {
+ if (oneofCase[i] == null)
+ {
+ oneofCase[i] = other.OneofFieldDescriptor(type.Oneofs[i]);
+ } else
+ {
+ if (oneofCase[i] != other.OneofFieldDescriptor(type.Oneofs[i]))
+ {
+ fields.ClearField(oneofCase[i]);
+ oneofCase[i] = other.OneofFieldDescriptor(type.Oneofs[i]);
+ }
+ }
+ }
+ }
return this;
}
@@ -353,7 +405,7 @@ namespace Google.ProtocolBuffers
{
if (fields != null && !IsInitialized)
{
- throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields));
+ throw new UninitializedMessageException(new DynamicMessage(type, fields, oneofCase, unknownFields));
}
return BuildPartial();
}
@@ -367,7 +419,7 @@ namespace Google.ProtocolBuffers
{
if (!IsInitialized)
{
- throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).
+ throw new UninitializedMessageException(new DynamicMessage(type, fields, oneofCase, unknownFields)).
AsInvalidProtocolBufferException();
}
return BuildPartial();
@@ -380,7 +432,7 @@ namespace Google.ProtocolBuffers
throw new InvalidOperationException("Build() has already been called on this Builder.");
}
fields.MakeImmutable();
- DynamicMessage result = new DynamicMessage(type, fields, unknownFields);
+ DynamicMessage result = new DynamicMessage(type, fields, oneofCase, unknownFields);
fields = null;
unknownFields = null;
return result;
@@ -390,6 +442,7 @@ namespace Google.ProtocolBuffers
{
Builder result = new Builder(type);
result.fields.MergeFrom(fields);
+ result.oneofCase = oneofCase;
return result;
}
@@ -431,6 +484,23 @@ namespace Google.ProtocolBuffers
return new Builder(field.MessageType);
}
+ public override bool HasOneof(OneofDescriptor oneof)
+ {
+ VerifyContainingOneofType(oneof);
+ FieldDescriptor field = oneofCase[oneof.Index];
+ if (field == null)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public override FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof)
+ {
+ VerifyContainingOneofType(oneof);
+ return oneofCase[oneof.Index];
+ }
+
public override bool HasField(FieldDescriptor field)
{
VerifyContainingType(field);
@@ -466,6 +536,17 @@ namespace Google.ProtocolBuffers
set
{
VerifyContainingType(field);
+ OneofDescriptor oneof = field.ContainingOneof;
+ if (oneof != null)
+ {
+ int index = oneof.Index;
+ FieldDescriptor oldField = oneofCase[index];
+ if ((oldField != null) && (oldField != field))
+ {
+ fields.ClearField(oldField);
+ }
+ oneofCase[index] = field;
+ }
fields[field] = value;
}
}
@@ -473,10 +554,30 @@ namespace Google.ProtocolBuffers
public override Builder ClearField(FieldDescriptor field)
{
VerifyContainingType(field);
+ OneofDescriptor oneof = field.ContainingOneof;
+ if (oneof != null)
+ {
+ int index = oneof.Index;
+ if (oneofCase[index] == field)
+ {
+ oneofCase[index] = null;
+ }
+ }
fields.ClearField(field);
return this;
}
+ public override Builder ClearOneof(OneofDescriptor oneof)
+ {
+ VerifyContainingOneofType(oneof);
+ FieldDescriptor field = oneofCase[oneof.Index];
+ if (field != null)
+ {
+ ClearField(field);
+ }
+ return this;
+ }
+
public override int GetRepeatedFieldCount(FieldDescriptor field)
{
VerifyContainingType(field);
@@ -507,6 +608,17 @@ namespace Google.ProtocolBuffers
throw new ArgumentException("FieldDescriptor does not match message type.");
}
}
+
+ /// <summary>
+ /// Verifies that the oneof is an oneof of this message.
+ /// </summary>
+ private void VerifyContainingOneofType(OneofDescriptor oneof)
+ {
+ if (oneof.ContainingType != type)
+ {
+ throw new ArgumentException("OneofDescriptor does not match message type");
+ }
+ }
}
}
} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs b/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
index 6e20b14e..ad1a4382 100644
--- a/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
+++ b/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
@@ -45,6 +45,7 @@ namespace Google.ProtocolBuffers.FieldAccess
where TBuilder : IBuilder<TMessage, TBuilder>
{
private readonly IFieldAccessor<TMessage, TBuilder>[] accessors;
+ private readonly OneofAccessor<TMessage, TBuilder>[] oneofs;
private readonly MessageDescriptor descriptor;
@@ -68,17 +69,28 @@ namespace Google.ProtocolBuffers.FieldAccess
{
this.descriptor = descriptor;
accessors = new IFieldAccessor<TMessage, TBuilder>[descriptor.Fields.Count];
+ oneofs = new OneofAccessor<TMessage, TBuilder>[descriptor.Oneofs.Count];
bool supportFieldPresence = descriptor.File.Syntax == FileDescriptor.ProtoSyntax.Proto2;
- for (int i = 0; i < accessors.Length; i++)
+ int fieldSize = accessors.Length;
+ for (int i = 0; i < fieldSize; i++)
{
- accessors[i] = CreateAccessor(descriptor.Fields[i], propertyNames[i], supportFieldPresence);
+ FieldDescriptor field = descriptor.Fields[i];
+ string containingOneofName = (field.ContainingOneof != null) ?
+ propertyNames[fieldSize +field.ContainingOneof.Index] : null;
+ accessors[i] = CreateAccessor(
+ field, propertyNames[i], containingOneofName, supportFieldPresence);
+ }
+ for (int i = 0; i < oneofs.Length; i++)
+ {
+ oneofs[i] = new OneofAccessor<TMessage, TBuilder>(descriptor, propertyNames[i + accessors.Length]);
}
}
/// <summary>
/// Creates an accessor for a single field
/// </summary>
- private static IFieldAccessor<TMessage, TBuilder> CreateAccessor(FieldDescriptor field, string name, bool supportFieldPresence)
+ private static IFieldAccessor<TMessage, TBuilder> CreateAccessor(
+ FieldDescriptor field, string name, string containingOneofName, bool supportFieldPresence)
{
if (field.IsRepeated)
{
@@ -97,11 +109,24 @@ namespace Google.ProtocolBuffers.FieldAccess
switch (field.MappedType)
{
case MappedType.Message:
- return new SingleMessageAccessor<TMessage, TBuilder>(name);
+ {
+ if (field.ContainingOneof != null)
+ {
+ return new SingleMessageAccessor<TMessage, TBuilder>(
+ field, name, containingOneofName, supportFieldPresence);
+ }
+ else
+ {
+ return new SingleMessageAccessor<TMessage, TBuilder>(
+ field, name, containingOneofName, true);
+ }
+ }
case MappedType.Enum:
- return new SingleEnumAccessor<TMessage, TBuilder>(field, name, supportFieldPresence);
+ return new SingleEnumAccessor<TMessage, TBuilder>(
+ field, name, containingOneofName, supportFieldPresence);
default:
- return new SinglePrimitiveAccessor<TMessage, TBuilder>(field, name, supportFieldPresence);
+ return new SinglePrimitiveAccessor<TMessage, TBuilder>(
+ field, name, containingOneofName, supportFieldPresence);
}
}
}
@@ -123,5 +148,14 @@ namespace Google.ProtocolBuffers.FieldAccess
return accessors[field.Index];
}
}
+
+ internal OneofAccessor<TMessage, TBuilder> Oneof(OneofDescriptor oneof)
+ {
+ if (oneof.ContainingType != descriptor)
+ {
+ throw new ArgumentException("OneofDescriptor does not match message type");
+ }
+ return oneofs[oneof.Index];
+ }
}
} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/OneofAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/OneofAccessor.cs
new file mode 100644
index 00000000..1a4bda76
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/OneofAccessor.cs
@@ -0,0 +1,91 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// Author: jieluo@google.com (Jie Luo)
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Reflection;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Access for an oneof
+ /// </summary>
+ internal class OneofAccessor<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage, TBuilder>
+ where TBuilder : IBuilder<TMessage, TBuilder>
+ {
+ private readonly Func<TMessage, object> caseDelegate;
+ private readonly Func<TBuilder, IBuilder> clearDelegate;
+ private MessageDescriptor descriptor;
+
+ internal OneofAccessor(MessageDescriptor descriptor, string name)
+ {
+ this.descriptor = descriptor;
+ MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
+ PropertyInfo caseProperty = typeof(TMessage).GetProperty(name + "Case");
+ if (clearMethod == null || caseProperty == null)
+ {
+ throw new ArgumentException("Not all required properties/methods available for oneof");
+ }
+
+
+ clearDelegate = ReflectionUtil.CreateDelegateFunc<TBuilder, IBuilder>(clearMethod);
+ caseDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(caseProperty.GetGetMethod());
+ }
+
+ /// <summary>
+ /// Indicates whether the specified message has set any field in the oneof.
+ /// </summary>
+ public bool Has(TMessage message)
+ {
+ return ((int) caseDelegate(message) != 0);
+ }
+
+ /// <summary>
+ /// Clears the oneof in the specified builder.
+ /// </summary>
+ public void Clear(TBuilder builder)
+ {
+ clearDelegate(builder);
+ }
+
+ /// <summary>
+ /// Indicates which field in the oneof is set for specified message
+ /// </summary>
+ public virtual FieldDescriptor GetOneofFieldDescriptor(TMessage message)
+ {
+ int fieldNumber = (int) caseDelegate(message);
+ if (fieldNumber > 0)
+ {
+ return descriptor.FindFieldByNumber(fieldNumber);
+ }
+ return null;
+ }
+ }
+}
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs
index e63f717c..89e10179 100644
--- a/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs
+++ b/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs
@@ -42,7 +42,8 @@ namespace Google.ProtocolBuffers.FieldAccess
{
private readonly EnumDescriptor enumDescriptor;
- internal SingleEnumAccessor(FieldDescriptor field, string name, bool supportFieldPresence) : base(field, name, supportFieldPresence)
+ internal SingleEnumAccessor(FieldDescriptor field, string name, string containingOneofName, bool supportFieldPresence)
+ : base(field, name, containingOneofName, supportFieldPresence)
{
enumDescriptor = field.EnumType;
}
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs
index 0ec2b0b7..9068d40a 100644
--- a/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs
+++ b/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs
@@ -31,6 +31,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Reflection;
+using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.FieldAccess
{
@@ -48,7 +49,8 @@ namespace Google.ProtocolBuffers.FieldAccess
/// </summary>
private readonly Func<IBuilder> createBuilderDelegate;
- internal SingleMessageAccessor(string name) : base(null, name, true)
+ internal SingleMessageAccessor(FieldDescriptor field, string name, string containingOneofName, bool supportFieldPresence)
+ : base(field, name, containingOneofName, supportFieldPresence)
{
MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", ReflectionUtil.EmptyTypes);
if (createBuilderMethod == null)
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs
index b9ab7293..035fcf3c 100644
--- a/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs
+++ b/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs
@@ -47,6 +47,7 @@ namespace Google.ProtocolBuffers.FieldAccess
private readonly Action<TBuilder, object> setValueDelegate;
private readonly Func<TMessage, bool> hasDelegate;
private readonly Func<TBuilder, IBuilder> clearDelegate;
+ private readonly Func<TMessage, object> caseDelegate;
/// <summary>
/// The CLR type of the field (int, the enum type, ByteString, the message etc).
@@ -57,7 +58,8 @@ namespace Google.ProtocolBuffers.FieldAccess
get { return clrType; }
}
- internal SinglePrimitiveAccessor(FieldDescriptor fieldDescriptor, string name, bool supportFieldPresence)
+ internal SinglePrimitiveAccessor(
+ FieldDescriptor fieldDescriptor, string name, string containingOneofName, bool supportFieldPresence)
{
PropertyInfo messageProperty = typeof(TMessage).GetProperty(name, null, ReflectionUtil.EmptyTypes);
PropertyInfo builderProperty = typeof(TBuilder).GetProperty(name, null, ReflectionUtil.EmptyTypes);
@@ -77,7 +79,16 @@ namespace Google.ProtocolBuffers.FieldAccess
hasDelegate = ReflectionUtil.CreateDelegateFunc<TMessage, bool>(hasProperty.GetGetMethod());
} else
{
- hasDelegate = message => !GetValue(message).Equals(fieldDescriptor.DefaultValue);
+ if (fieldDescriptor.ContainingOneof != null)
+ {
+ PropertyInfo caseProperty = typeof(TMessage).GetProperty(containingOneofName + "Case");
+ caseDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(caseProperty.GetGetMethod());
+ hasDelegate = message => OneofFieldNumber(message).Equals(fieldDescriptor.FieldNumber);
+ }
+ else
+ {
+ hasDelegate = message => !GetValue(message).Equals(fieldDescriptor.DefaultValue);
+ }
}
clrType = messageProperty.PropertyType;
@@ -86,6 +97,11 @@ namespace Google.ProtocolBuffers.FieldAccess
setValueDelegate = ReflectionUtil.CreateDowncastDelegate<TBuilder>(builderProperty.GetSetMethod());
}
+ private int OneofFieldNumber(TMessage message)
+ {
+ return (int) caseDelegate(message);
+ }
+
public bool Has(TMessage message)
{
return hasDelegate(message);
@@ -143,4 +159,4 @@ namespace Google.ProtocolBuffers.FieldAccess
#endregion
}
-} \ No newline at end of file
+}
diff --git a/csharp/src/ProtocolBuffers/GeneratedBuilder.cs b/csharp/src/ProtocolBuffers/GeneratedBuilder.cs
index e60a4201..0f121ae8 100644
--- a/csharp/src/ProtocolBuffers/GeneratedBuilder.cs
+++ b/csharp/src/ProtocolBuffers/GeneratedBuilder.cs
@@ -105,6 +105,16 @@ namespace Google.ProtocolBuffers
set { InternalFieldAccessors[field].SetRepeated(ThisBuilder, index, value); }
}
+ public override bool HasOneof(OneofDescriptor oneof)
+ {
+ return MessageBeingBuilt.HasOneof(oneof);
+ }
+
+ public override FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof)
+ {
+ return MessageBeingBuilt.OneofFieldDescriptor(oneof);
+ }
+
public override bool HasField(FieldDescriptor field)
{
return MessageBeingBuilt.HasField(field);
@@ -121,6 +131,12 @@ namespace Google.ProtocolBuffers
return ThisBuilder;
}
+ public override TBuilder ClearOneof(OneofDescriptor oneof)
+ {
+ InternalFieldAccessors.Oneof(oneof).Clear(ThisBuilder);
+ return ThisBuilder;
+ }
+
public override TBuilder MergeFrom(TMessage other)
{
if (other.DescriptorForType != InternalFieldAccessors.Descriptor)
diff --git a/csharp/src/ProtocolBuffers/GeneratedMessage.cs b/csharp/src/ProtocolBuffers/GeneratedMessage.cs
index c17c15cf..ff3a0c2a 100644
--- a/csharp/src/ProtocolBuffers/GeneratedMessage.cs
+++ b/csharp/src/ProtocolBuffers/GeneratedMessage.cs
@@ -142,6 +142,16 @@ namespace Google.ProtocolBuffers
get { return Dictionaries.AsReadOnly(GetMutableFieldMap()); }
}
+ public override bool HasOneof(OneofDescriptor oneof)
+ {
+ return InternalFieldAccessors.Oneof(oneof).Has(ThisMessage);
+ }
+
+ public override FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof)
+ {
+ return InternalFieldAccessors.Oneof(oneof).GetOneofFieldDescriptor(ThisMessage);
+ }
+
public override bool HasField(FieldDescriptor field)
{
return InternalFieldAccessors[field].Has(ThisMessage);
diff --git a/csharp/src/ProtocolBuffers/IBuilder.cs b/csharp/src/ProtocolBuffers/IBuilder.cs
index f9c0df61..e765464a 100644
--- a/csharp/src/ProtocolBuffers/IBuilder.cs
+++ b/csharp/src/ProtocolBuffers/IBuilder.cs
@@ -103,6 +103,11 @@ namespace Google.ProtocolBuffers
/// </summary>
object this[FieldDescriptor field, int index] { get; set; }
+
+ bool HasOneof(OneofDescriptor oneof);
+
+ FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof);
+
/// <summary>
/// <see cref="IMessage{TMessage, TBuilder}.HasField"/>
/// </summary>
@@ -125,6 +130,7 @@ namespace Google.ProtocolBuffers
IBuilder WeakAddRepeatedField(FieldDescriptor field, object value);
new IBuilder WeakClear();
IBuilder WeakClearField(FieldDescriptor field);
+ IBuilder WeakClearOneof(OneofDescriptor oneof);
IBuilder WeakMergeFrom(IMessage message);
new IBuilder WeakMergeFrom(ByteString data);
new IBuilder WeakMergeFrom(ByteString data, ExtensionRegistry registry);
@@ -228,6 +234,14 @@ namespace Google.ProtocolBuffers
TBuilder ClearField(FieldDescriptor field);
/// <summary>
+ /// Clears the oneof. This is exactly equivalent to calling the generated
+ /// Clear method corresponding to the oneof.
+ /// </summary>
+ /// <param name="oneof"></param>
+ /// <returns></returns>
+ TBuilder ClearOneof(OneofDescriptor oneof);
+
+ /// <summary>
/// Appends the given value as a new element for the specified repeated field.
/// </summary>
/// <exception cref="ArgumentException">the field is not a repeated field,
diff --git a/csharp/src/ProtocolBuffers/IMessage.cs b/csharp/src/ProtocolBuffers/IMessage.cs
index c23bc3f7..dd309d4e 100644
--- a/csharp/src/ProtocolBuffers/IMessage.cs
+++ b/csharp/src/ProtocolBuffers/IMessage.cs
@@ -67,6 +67,10 @@ namespace Google.ProtocolBuffers
/// </summary>
IDictionary<FieldDescriptor, object> AllFields { get; }
+ bool HasOneof(OneofDescriptor oneof);
+
+ FieldDescriptor OneofFieldDescriptor(OneofDescriptor oneof);
+
/// <summary>
/// Returns true if the given field is set. This is exactly equivalent
/// to calling the generated "Has" property corresponding to the field.
diff --git a/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj
index 32a343ad..7dc8f665 100644
--- a/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj
+++ b/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj
@@ -81,6 +81,7 @@
<Compile Include="Descriptors\FieldMappingAttribute.cs" />
<Compile Include="Descriptors\FieldType.cs" />
<Compile Include="Descriptors\FileDescriptor.cs" />
+ <Compile Include="Descriptors\OneofDescriptor.cs" />
<Compile Include="Descriptors\IDescriptor.cs" />
<Compile Include="Descriptors\IndexedDescriptorBase.cs" />
<Compile Include="Descriptors\MappedType.cs" />
@@ -106,6 +107,7 @@
<Compile Include="FieldAccess\IFieldAccessor.cs" />
<Compile Include="FieldAccess\FieldAccessorTable.cs" />
<Compile Include="FieldAccess\RepeatedMessageAccessor.cs" />
+ <Compile Include="FieldAccess\OneofAccessor.cs" />
<Compile Include="FieldSet.cs" />
<Compile Include="FrameworkPortability.cs" />
<Compile Include="GeneratedBuilder.cs" />
@@ -146,4 +148,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>