aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/ProtocolBuffers
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2015-06-11 21:15:36 +0100
committerJon Skeet <skeet@pobox.com>2015-06-11 21:15:36 +0100
commit39aaf21d5194fdc07c296847def8e7795279e041 (patch)
tree174c362717574e13047c4d590b5f9609405aed84 /csharp/src/ProtocolBuffers
parentce0e348ded9cb7e180588476ebb5a8f3e0460f4e (diff)
downloadprotobuf-39aaf21d5194fdc07c296847def8e7795279e041.tar.gz
protobuf-39aaf21d5194fdc07c296847def8e7795279e041.tar.bz2
protobuf-39aaf21d5194fdc07c296847def8e7795279e041.zip
Reimplement enums as int values, and get rid of EnumHelper.
This makes repeated fields really awkward at the moment - but when we reimplement RepeatedField<T> to be backed by an array, we can cast the array directly...
Diffstat (limited to 'csharp/src/ProtocolBuffers')
-rw-r--r--csharp/src/ProtocolBuffers/CodedInputStream.cs17
-rw-r--r--csharp/src/ProtocolBuffers/CodedOutputStream.ComputeSize.cs12
-rw-r--r--csharp/src/ProtocolBuffers/CodedOutputStream.cs24
-rw-r--r--csharp/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs55
-rw-r--r--csharp/src/ProtocolBuffers/EnumHelper.cs93
-rw-r--r--csharp/src/ProtocolBuffers/ICodedInputStream.cs11
-rw-r--r--csharp/src/ProtocolBuffers/ICodedOutputStream.cs2
-rw-r--r--csharp/src/ProtocolBuffers/ProtocolBuffers.csproj1
8 files changed, 67 insertions, 148 deletions
diff --git a/csharp/src/ProtocolBuffers/CodedInputStream.cs b/csharp/src/ProtocolBuffers/CodedInputStream.cs
index 685d7702..d5cab6fd 100644
--- a/csharp/src/ProtocolBuffers/CodedInputStream.cs
+++ b/csharp/src/ProtocolBuffers/CodedInputStream.cs
@@ -434,11 +434,10 @@ namespace Google.Protobuf
/// then the ref value is set and it returns true. Otherwise the unknown output
/// value is set and this method returns false.
/// </summary>
- public bool ReadEnum<T>(ref T value)
- where T : struct, IComparable, IFormattable
+ public bool ReadEnum(ref int value)
{
- int number = (int) ReadRawVarint32();
- value = EnumHelper<T>.FromInt32(number);
+ // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
+ value = (int) ReadRawVarint32();
return true;
}
@@ -796,7 +795,7 @@ namespace Google.Protobuf
public void ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list)
where T : struct, IComparable, IFormattable
{
- T value = default(T);
+ int value = 0;
WireFormat.WireType wformat = WireFormat.GetTagWireType(fieldTag);
// 2.3 allows packed form even if the field is not declared packed.
@@ -806,8 +805,9 @@ namespace Google.Protobuf
int limit = PushLimit(length);
while (!ReachedLimit)
{
- ReadEnum<T>(ref value);
- list.Add(value);
+ ReadEnum(ref value);
+ // TODO(jonskeet): Avoid this horrible boxing!
+ list.Add((T)(object)value);
}
PopLimit(limit);
}
@@ -816,7 +816,8 @@ namespace Google.Protobuf
do
{
ReadEnum(ref value);
- list.Add(value);
+ // TODO(jonskeet): Avoid this horrible boxing!
+ list.Add((T)(object) value);
} while (ContinueArray(fieldTag));
}
}
diff --git a/csharp/src/ProtocolBuffers/CodedOutputStream.ComputeSize.cs b/csharp/src/ProtocolBuffers/CodedOutputStream.ComputeSize.cs
index 58475ff7..96be9db5 100644
--- a/csharp/src/ProtocolBuffers/CodedOutputStream.ComputeSize.cs
+++ b/csharp/src/ProtocolBuffers/CodedOutputStream.ComputeSize.cs
@@ -196,7 +196,7 @@ namespace Google.Protobuf
/// enum field, including the tag. The caller is responsible for
/// converting the enum value to its numeric value.
/// </summary>
- public static int ComputeEnumSize<T>(int fieldNumber, T value) where T : struct, IComparable, IFormattable
+ public static int ComputeEnumSize(int fieldNumber, int value)
{
return ComputeTagSize(fieldNumber) + ComputeEnumSizeNoTag(value);
}
@@ -371,10 +371,10 @@ namespace Google.Protobuf
/// enum field, including the tag. The caller is responsible for
/// converting the enum value to its numeric value.
/// </summary>
- public static int ComputeEnumSizeNoTag<T>(T value) where T : struct, IComparable, IFormattable
+ public static int ComputeEnumSizeNoTag(int value)
{
- int serializedValue = EnumHelper<T>.ToInt32(value);
- return ComputeInt32SizeNoTag(serializedValue);
+ // Currently just a pass-through, but it's nice to separate it logically.
+ return ComputeInt32SizeNoTag(value);
}
/// <summary>
@@ -555,7 +555,7 @@ namespace Google.Protobuf
case FieldType.SInt64:
return ComputeSInt64Size(fieldNumber, (long) value);
case FieldType.Enum:
- return ComputeEnumSize(fieldNumber, Convert.ToInt64(value));
+ return ComputeEnumSize(fieldNumber, (int) value);
default:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
}
@@ -605,7 +605,7 @@ namespace Google.Protobuf
case FieldType.SInt64:
return ComputeSInt64SizeNoTag((long) value);
case FieldType.Enum:
- return ComputeEnumSizeNoTag(Convert.ToInt64(value));
+ return ComputeEnumSizeNoTag((int) value);
default:
throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
}
diff --git a/csharp/src/ProtocolBuffers/CodedOutputStream.cs b/csharp/src/ProtocolBuffers/CodedOutputStream.cs
index f55f8ca2..e3f0c700 100644
--- a/csharp/src/ProtocolBuffers/CodedOutputStream.cs
+++ b/csharp/src/ProtocolBuffers/CodedOutputStream.cs
@@ -37,6 +37,7 @@
using System;
using System.Collections;
using System.IO;
+using System.Linq;
using System.Text;
using Google.Protobuf.Collections;
using Google.Protobuf.Descriptors;
@@ -350,10 +351,11 @@ namespace Google.Protobuf
WriteRawVarint32(value);
}
- public void WriteEnum<T>(int fieldNumber, string fieldName, T value) where T : struct, IComparable, IFormattable
+ public void WriteEnum(int fieldNumber, string fieldName, int value)
{
+ // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
WriteTag(fieldNumber, WireFormat.WireType.Varint);
- WriteInt32NoTag(EnumHelper<T>.ToInt32(value));
+ WriteInt32NoTag(value);
}
public void WriteSFixed32(int fieldNumber, string fieldName, int value)
@@ -595,9 +597,9 @@ namespace Google.Protobuf
WriteRawVarint32(value);
}
- public void WriteEnumNoTag<T>(T value) where T : struct, IComparable, IFormattable
+ public void WriteEnumNoTag(int value)
{
- WriteInt32NoTag(EnumHelper<T>.ToInt32(value));
+ WriteInt32NoTag(value);
}
public void WriteSFixed32NoTag(int value)
@@ -774,7 +776,12 @@ namespace Google.Protobuf
public void WriteEnumArray<T>(int fieldNumber, string fieldName, RepeatedField<T> list)
where T : struct, IComparable, IFormattable
{
- foreach (T value in list)
+ if (list.Count == 0)
+ {
+ return;
+ }
+ // TODO(jonskeet): Avoid the Cast call here. Work out a better mass "T to int" conversion.
+ foreach (int value in list.Cast<int>())
{
WriteEnum(fieldNumber, fieldName, value);
}
@@ -1005,10 +1012,13 @@ namespace Google.Protobuf
{
return;
}
- uint size = list.CalculateSize(ComputeEnumSizeNoTag);
+ // Obviously, we'll want to get rid of this hack...
+ var temporaryHack = new RepeatedField<int>();
+ temporaryHack.Add(list.Cast<int>());
+ uint size = temporaryHack.CalculateSize(ComputeEnumSizeNoTag);
WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
WriteRawVarint32(size);
- foreach (T value in list)
+ foreach (int value in temporaryHack)
{
WriteEnumNoTag(value);
}
diff --git a/csharp/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs b/csharp/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
index b18b63bf..eb96dfcf 100644
--- a/csharp/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
+++ b/csharp/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
@@ -1360,10 +1360,10 @@ namespace Google.Protobuf.DescriptorProtos {
output.WriteInt32(3, fieldNames[4], Number);
}
if (Label != global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
- output.WriteEnum(4, fieldNames[2], Label);
+ output.WriteEnum(4, fieldNames[2], (int) Label);
}
if (Type != global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
- output.WriteEnum(5, fieldNames[7], Type);
+ output.WriteEnum(5, fieldNames[7], (int) Type);
}
if (TypeName != "") {
output.WriteString(6, fieldNames[8], TypeName);
@@ -1388,10 +1388,10 @@ namespace Google.Protobuf.DescriptorProtos {
size += pb::CodedOutputStream.ComputeInt32Size(3, Number);
}
if (Label != global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
- size += pb::CodedOutputStream.ComputeEnumSize(4, Label);
+ size += pb::CodedOutputStream.ComputeEnumSize(4, (int) Label);
}
if (Type != global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
- size += pb::CodedOutputStream.ComputeEnumSize(5, Type);
+ size += pb::CodedOutputStream.ComputeEnumSize(5, (int) Type);
}
if (TypeName != "") {
size += pb::CodedOutputStream.ComputeStringSize(6, TypeName);
@@ -1477,12 +1477,14 @@ namespace Google.Protobuf.DescriptorProtos {
break;
}
case 32: {
- input.ReadEnum(ref label_);
- break;
+ int tmp = 0;
+ input.ReadEnum(ref tmp);
+ label_ = (global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Label) tmp;break;
}
case 40: {
- input.ReadEnum(ref type_);
- break;
+ int tmp = 0;
+ input.ReadEnum(ref tmp);
+ type_ = (global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Type) tmp;break;
}
case 50: {
input.ReadString(ref typeName_);
@@ -1510,7 +1512,7 @@ namespace Google.Protobuf.DescriptorProtos {
#region Nested types
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Types {
- public enum Type : long {
+ public enum Type {
TYPE_DOUBLE = 1,
TYPE_FLOAT = 2,
TYPE_INT64 = 3,
@@ -1531,7 +1533,7 @@ namespace Google.Protobuf.DescriptorProtos {
TYPE_SINT64 = 18,
}
- public enum Label : long {
+ public enum Label {
LABEL_OPTIONAL = 1,
LABEL_REQUIRED = 2,
LABEL_REPEATED = 3,
@@ -2489,7 +2491,7 @@ namespace Google.Protobuf.DescriptorProtos {
output.WriteString(8, fieldNames[8], JavaOuterClassname);
}
if (OptimizeFor != global::Google.Protobuf.DescriptorProtos.FileOptions.Types.OptimizeMode.SPEED) {
- output.WriteEnum(9, fieldNames[12], OptimizeFor);
+ output.WriteEnum(9, fieldNames[12], (int) OptimizeFor);
}
if (JavaMultipleFiles != false) {
output.WriteBool(10, fieldNames[7], JavaMultipleFiles);
@@ -2545,7 +2547,7 @@ namespace Google.Protobuf.DescriptorProtos {
size += pb::CodedOutputStream.ComputeBoolSize(27, JavaStringCheckUtf8);
}
if (OptimizeFor != global::Google.Protobuf.DescriptorProtos.FileOptions.Types.OptimizeMode.SPEED) {
- size += pb::CodedOutputStream.ComputeEnumSize(9, OptimizeFor);
+ size += pb::CodedOutputStream.ComputeEnumSize(9, (int) OptimizeFor);
}
if (GoPackage != "") {
size += pb::CodedOutputStream.ComputeStringSize(11, GoPackage);
@@ -2652,8 +2654,9 @@ namespace Google.Protobuf.DescriptorProtos {
break;
}
case 72: {
- input.ReadEnum(ref optimizeFor_);
- break;
+ int tmp = 0;
+ input.ReadEnum(ref tmp);
+ optimizeFor_ = (global::Google.Protobuf.DescriptorProtos.FileOptions.Types.OptimizeMode) tmp;break;
}
case 80: {
input.ReadBool(ref javaMultipleFiles_);
@@ -2710,7 +2713,7 @@ namespace Google.Protobuf.DescriptorProtos {
#region Nested types
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Types {
- public enum OptimizeMode : long {
+ public enum OptimizeMode {
SPEED = 1,
CODE_SIZE = 2,
LITE_RUNTIME = 3,
@@ -3015,7 +3018,7 @@ namespace Google.Protobuf.DescriptorProtos {
public void WriteTo(pb::ICodedOutputStream output) {
string[] fieldNames = _fieldNames;
if (Ctype != global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.CType.STRING) {
- output.WriteEnum(1, fieldNames[0], Ctype);
+ output.WriteEnum(1, fieldNames[0], (int) Ctype);
}
if (Packed != false) {
output.WriteBool(2, fieldNames[4], Packed);
@@ -3027,7 +3030,7 @@ namespace Google.Protobuf.DescriptorProtos {
output.WriteBool(5, fieldNames[3], Lazy);
}
if (Jstype != global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.JSType.JS_NORMAL) {
- output.WriteEnum(6, fieldNames[2], Jstype);
+ output.WriteEnum(6, fieldNames[2], (int) Jstype);
}
if (Weak != false) {
output.WriteBool(10, fieldNames[6], Weak);
@@ -3038,13 +3041,13 @@ namespace Google.Protobuf.DescriptorProtos {
public int CalculateSize() {
int size = 0;
if (Ctype != global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.CType.STRING) {
- size += pb::CodedOutputStream.ComputeEnumSize(1, Ctype);
+ size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Ctype);
}
if (Packed != false) {
size += pb::CodedOutputStream.ComputeBoolSize(2, Packed);
}
if (Jstype != global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.JSType.JS_NORMAL) {
- size += pb::CodedOutputStream.ComputeEnumSize(6, Jstype);
+ size += pb::CodedOutputStream.ComputeEnumSize(6, (int) Jstype);
}
if (Lazy != false) {
size += pb::CodedOutputStream.ComputeBoolSize(5, Lazy);
@@ -3104,8 +3107,9 @@ namespace Google.Protobuf.DescriptorProtos {
}
break;
case 8: {
- input.ReadEnum(ref ctype_);
- break;
+ int tmp = 0;
+ input.ReadEnum(ref tmp);
+ ctype_ = (global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.CType) tmp;break;
}
case 16: {
input.ReadBool(ref packed_);
@@ -3120,8 +3124,9 @@ namespace Google.Protobuf.DescriptorProtos {
break;
}
case 48: {
- input.ReadEnum(ref jstype_);
- break;
+ int tmp = 0;
+ input.ReadEnum(ref tmp);
+ jstype_ = (global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.JSType) tmp;break;
}
case 80: {
input.ReadBool(ref weak_);
@@ -3138,13 +3143,13 @@ namespace Google.Protobuf.DescriptorProtos {
#region Nested types
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Types {
- public enum CType : long {
+ public enum CType {
STRING = 0,
CORD = 1,
STRING_PIECE = 2,
}
- public enum JSType : long {
+ public enum JSType {
JS_NORMAL = 0,
JS_STRING = 1,
JS_NUMBER = 2,
diff --git a/csharp/src/ProtocolBuffers/EnumHelper.cs b/csharp/src/ProtocolBuffers/EnumHelper.cs
deleted file mode 100644
index 1cf18985..00000000
--- a/csharp/src/ProtocolBuffers/EnumHelper.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Text;
-
-namespace Google.Protobuf
-{
- public class EnumHelper<T> where T : struct, IComparable, IFormattable
- {
- // TODO(jonskeet): For snmall enums, use something lighter-weight than a dictionary?
- private static readonly Dictionary<int, T> _byNumber;
- private static readonly Dictionary<string, T> _byName;
- private static readonly Func<T, long> toRawValue;
- private static readonly Func<long, T> fromRawValue;
-
- private const long UnknownValueBase = 0x100000000L;
-
- static EnumHelper()
- {
- if (!typeof(T).IsEnum)
- {
- throw new InvalidOperationException(string.Format("{0} is not an enum type", typeof(T).FullName));
- }
- if (Enum.GetUnderlyingType(typeof(T)) != typeof(long))
- {
- throw new InvalidOperationException(string.Format("{0} does not have long as an underlying type", typeof(T).FullName));
- }
- // It will actually be a T[], but the CLR will let us convert.
- long[] array = (long[])Enum.GetValues(typeof(T));
- _byNumber = new Dictionary<int, T>(array.Length);
- foreach (long i in array)
- {
- _byNumber[(int) i] = (T)(object)i;
- }
- string[] names = (string[])Enum.GetNames(typeof(T));
- _byName = new Dictionary<string, T>();
- foreach (var name in names)
- {
- _byName[name] = (T) Enum.Parse(typeof(T), name, false);
- }
-
- ParameterExpression param1 = Expression.Parameter(typeof(T), "x");
- ParameterExpression param2 = Expression.Parameter(typeof(long), "x");
- Expression convertedParam1 = Expression.Convert(param1, typeof(long));
- Expression convertedParam2 = Expression.Convert(param2, typeof(T));
- toRawValue = Expression.Lambda<Func<T, long>>(convertedParam1, param1).Compile();
- fromRawValue = Expression.Lambda<Func<long, T>>(convertedParam2, param2).Compile();
- }
-
- /// <summary>
- /// Converts the given 32-bit integer into a value of the enum type.
- /// If the integer is a known, named value, that is returned; otherwise,
- /// a value which is outside the range of 32-bit integers but which preserves
- /// the original integer is returned.
- /// </summary>
- public static T FromInt32(int value)
- {
- T validValue;
- return _byNumber.TryGetValue(value, out validValue) ? validValue : FromRawValue((long) value | UnknownValueBase);
- }
-
- /// <summary>
- /// Converts a value of the enum type to a 32-bit integer. This reverses
- /// <see cref="Int32"/>.
- /// </summary>
- public static int ToInt32(T value)
- {
- return (int)GetRawValue(value);
- }
-
- public static bool IsKnownValue(T value)
- {
- long raw = GetRawValue(value);
- if (raw >= int.MinValue && raw <= int.MaxValue)
- {
- return _byNumber.ContainsKey((int)raw);
- }
- return false;
- }
-
- private static long GetRawValue(T value)
- {
- return toRawValue(value);
- }
-
- private static T FromRawValue(long value)
- {
- return fromRawValue(value);
- }
-
- }
-}
diff --git a/csharp/src/ProtocolBuffers/ICodedInputStream.cs b/csharp/src/ProtocolBuffers/ICodedInputStream.cs
index 748589a0..d962e62b 100644
--- a/csharp/src/ProtocolBuffers/ICodedInputStream.cs
+++ b/csharp/src/ProtocolBuffers/ICodedInputStream.cs
@@ -146,14 +146,11 @@ namespace Google.Protobuf
bool ReadUInt32(ref uint value);
/// <summary>
- /// Reads an enum field value from the stream. If the enum is valid for type T,
- /// then the ref value is set and it returns true. Otherwise, if a value is present
- /// but invalid for the proto enum, it is still set in the field as a "preserved
- /// but invalid" value, and the method returns true. If no value can be read, the
- /// method does not affect the parameter and returns false.
+ /// Reads an enum field value from the stream. This performs no checking
+ /// as to whether the enum value is known to the enum type as it was present
+ /// when the code was generated.
/// </summary>
- bool ReadEnum<T>(ref T value)
- where T : struct, IComparable, IFormattable;
+ bool ReadEnum(ref int value);
/// <summary>
/// Reads an sfixed32 field value from the stream.
diff --git a/csharp/src/ProtocolBuffers/ICodedOutputStream.cs b/csharp/src/ProtocolBuffers/ICodedOutputStream.cs
index e51c10a4..921400ac 100644
--- a/csharp/src/ProtocolBuffers/ICodedOutputStream.cs
+++ b/csharp/src/ProtocolBuffers/ICodedOutputStream.cs
@@ -148,7 +148,7 @@ namespace Google.Protobuf
/// <summary>
/// Writes an enum field value, including tag, to the stream.
/// </summary>
- void WriteEnum<T>(int fieldNumber, string fieldName, T value) where T : struct, IComparable, IFormattable;
+ void WriteEnum(int fieldNumber, string fieldName, int value);
/// <summary>
/// Writes a fixed 32-bit field value, including tag, to the stream.
diff --git a/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj
index d15f1306..efd387a2 100644
--- a/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj
+++ b/csharp/src/ProtocolBuffers/ProtocolBuffers.csproj
@@ -84,7 +84,6 @@
<Compile Include="Descriptors\MethodDescriptor.cs" />
<Compile Include="Descriptors\PackageDescriptor.cs" />
<Compile Include="Descriptors\ServiceDescriptor.cs" />
- <Compile Include="EnumHelper.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="FieldAccess\FieldAccessorBase.cs" />
<Compile Include="FieldAccess\ReflectionUtil.cs" />