aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/ProtocolBuffers/FieldAccess
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/FieldAccess
parent55df12194f5f0348c3ddf0636c63ba2b3978fab5 (diff)
downloadprotobuf-f7b417ddfe63cb4d39775e5fd4560894cc547d65.tar.gz
protobuf-f7b417ddfe63cb4d39775e5fd4560894cc547d65.tar.bz2
protobuf-f7b417ddfe63cb4d39775e5fd4560894cc547d65.zip
Add oneof support for C#
Diffstat (limited to 'csharp/src/ProtocolBuffers/FieldAccess')
-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
5 files changed, 155 insertions, 11 deletions
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
+}