|
@@ -170,7 +170,7 @@ namespace Google.Protobuf
|
|
|
continue;
|
|
|
}
|
|
|
// Omit awkward (single) values such as unknown enum values
|
|
|
- if (!field.IsRepeated && !field.IsMap && !CanWriteSingleValue(accessor.Descriptor, value))
|
|
|
+ if (!field.IsRepeated && !field.IsMap && !CanWriteSingleValue(value))
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
@@ -182,7 +182,7 @@ namespace Google.Protobuf
|
|
|
}
|
|
|
WriteString(builder, ToCamelCase(accessor.Descriptor.Name));
|
|
|
builder.Append(": ");
|
|
|
- WriteValue(builder, accessor, value);
|
|
|
+ WriteValue(builder, value);
|
|
|
first = false;
|
|
|
}
|
|
|
builder.Append(first ? "}" : " }");
|
|
@@ -291,93 +291,81 @@ namespace Google.Protobuf
|
|
|
throw new ArgumentException("Invalid field type");
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- private void WriteValue(StringBuilder builder, IFieldAccessor accessor, object value)
|
|
|
+
|
|
|
+ private void WriteValue(StringBuilder builder, object value)
|
|
|
{
|
|
|
- if (accessor.Descriptor.IsMap)
|
|
|
+ if (value == null)
|
|
|
{
|
|
|
- WriteDictionary(builder, accessor, (IDictionary) value);
|
|
|
+ WriteNull(builder);
|
|
|
}
|
|
|
- else if (accessor.Descriptor.IsRepeated)
|
|
|
+ else if (value is bool)
|
|
|
{
|
|
|
- WriteList(builder, accessor, (IList) value);
|
|
|
+ builder.Append((bool) value ? "true" : "false");
|
|
|
}
|
|
|
- else
|
|
|
+ else if (value is ByteString)
|
|
|
{
|
|
|
- WriteSingleValue(builder, accessor.Descriptor, value);
|
|
|
+ // Nothing in Base64 needs escaping
|
|
|
+ builder.Append('"');
|
|
|
+ builder.Append(((ByteString) value).ToBase64());
|
|
|
+ builder.Append('"');
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- private void WriteSingleValue(StringBuilder builder, FieldDescriptor descriptor, object value)
|
|
|
- {
|
|
|
- switch (descriptor.FieldType)
|
|
|
+ else if (value is string)
|
|
|
{
|
|
|
- case FieldType.Bool:
|
|
|
- builder.Append((bool) value ? "true" : "false");
|
|
|
- break;
|
|
|
- case FieldType.Bytes:
|
|
|
- // Nothing in Base64 needs escaping
|
|
|
+ WriteString(builder, (string) value);
|
|
|
+ }
|
|
|
+ else if (value is IDictionary)
|
|
|
+ {
|
|
|
+ WriteDictionary(builder, (IDictionary) value);
|
|
|
+ }
|
|
|
+ else if (value is IList)
|
|
|
+ {
|
|
|
+ WriteList(builder, (IList) value);
|
|
|
+ }
|
|
|
+ else if (value is int || value is uint)
|
|
|
+ {
|
|
|
+ IFormattable formattable = (IFormattable) value;
|
|
|
+ builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
|
|
|
+ }
|
|
|
+ else if (value is long || value is ulong)
|
|
|
+ {
|
|
|
+ builder.Append('"');
|
|
|
+ IFormattable formattable = (IFormattable) value;
|
|
|
+ builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
|
|
|
+ builder.Append('"');
|
|
|
+ }
|
|
|
+ else if (value is System.Enum)
|
|
|
+ {
|
|
|
+ WriteString(builder, value.ToString());
|
|
|
+ }
|
|
|
+ else if (value is float || value is double)
|
|
|
+ {
|
|
|
+ string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
|
|
|
+ if (text == "NaN" || text == "Infinity" || text == "-Infinity")
|
|
|
+ {
|
|
|
builder.Append('"');
|
|
|
- builder.Append(((ByteString) value).ToBase64());
|
|
|
+ builder.Append(text);
|
|
|
builder.Append('"');
|
|
|
- break;
|
|
|
- case FieldType.String:
|
|
|
- WriteString(builder, (string) value);
|
|
|
- break;
|
|
|
- case FieldType.Fixed32:
|
|
|
- case FieldType.UInt32:
|
|
|
- case FieldType.SInt32:
|
|
|
- case FieldType.Int32:
|
|
|
- case FieldType.SFixed32:
|
|
|
- {
|
|
|
- IFormattable formattable = (IFormattable) value;
|
|
|
- builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
|
|
|
- break;
|
|
|
- }
|
|
|
- case FieldType.Enum:
|
|
|
- EnumValueDescriptor enumValue = descriptor.EnumType.FindValueByNumber((int) value);
|
|
|
- // We will already have validated that this is a known value.
|
|
|
- WriteString(builder, enumValue.Name);
|
|
|
- break;
|
|
|
- case FieldType.Fixed64:
|
|
|
- case FieldType.UInt64:
|
|
|
- case FieldType.SFixed64:
|
|
|
- case FieldType.Int64:
|
|
|
- case FieldType.SInt64:
|
|
|
- {
|
|
|
- builder.Append('"');
|
|
|
- IFormattable formattable = (IFormattable) value;
|
|
|
- builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
|
|
|
- builder.Append('"');
|
|
|
- break;
|
|
|
- }
|
|
|
- case FieldType.Double:
|
|
|
- case FieldType.Float:
|
|
|
- string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
|
|
|
- if (text == "NaN" || text == "Infinity" || text == "-Infinity")
|
|
|
- {
|
|
|
- builder.Append('"');
|
|
|
- builder.Append(text);
|
|
|
- builder.Append('"');
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- builder.Append(text);
|
|
|
- }
|
|
|
- break;
|
|
|
- case FieldType.Message:
|
|
|
- case FieldType.Group: // Never expect to get this, but...
|
|
|
- if (descriptor.MessageType.IsWellKnownType)
|
|
|
- {
|
|
|
- WriteWellKnownTypeValue(builder, descriptor.MessageType, value, true);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- WriteMessage(builder, (IMessage) value);
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new ArgumentException("Invalid field type: " + descriptor.FieldType);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ builder.Append(text);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value is IMessage)
|
|
|
+ {
|
|
|
+ IMessage message = (IMessage) value;
|
|
|
+ if (message.Descriptor.IsWellKnownType)
|
|
|
+ {
|
|
|
+ WriteWellKnownTypeValue(builder, message.Descriptor, value, true);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ WriteMessage(builder, (IMessage) value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Unable to format value of type " + value.GetType());
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -398,7 +386,7 @@ namespace Google.Protobuf
|
|
|
// so we can write it as if we were unconditionally writing the Value field for the wrapper type.
|
|
|
if (descriptor.File == Int32Value.Descriptor.File)
|
|
|
{
|
|
|
- WriteSingleValue(builder, descriptor.FindFieldByNumber(1), value);
|
|
|
+ WriteValue(builder, value);
|
|
|
return;
|
|
|
}
|
|
|
if (descriptor.FullName == Timestamp.Descriptor.FullName)
|
|
@@ -424,7 +412,7 @@ namespace Google.Protobuf
|
|
|
if (descriptor.FullName == ListValue.Descriptor.FullName)
|
|
|
{
|
|
|
var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
|
|
|
- WriteList(builder, fieldAccessor, (IList) fieldAccessor.GetValue((IMessage) value));
|
|
|
+ WriteList(builder, (IList) fieldAccessor.GetValue((IMessage) value));
|
|
|
return;
|
|
|
}
|
|
|
if (descriptor.FullName == Value.Descriptor.FullName)
|
|
@@ -565,7 +553,7 @@ namespace Google.Protobuf
|
|
|
case Value.BoolValueFieldNumber:
|
|
|
case Value.StringValueFieldNumber:
|
|
|
case Value.NumberValueFieldNumber:
|
|
|
- WriteSingleValue(builder, specifiedField, value);
|
|
|
+ WriteValue(builder, value);
|
|
|
return;
|
|
|
case Value.StructValueFieldNumber:
|
|
|
case Value.ListValueFieldNumber:
|
|
@@ -581,13 +569,13 @@ namespace Google.Protobuf
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void WriteList(StringBuilder builder, IFieldAccessor accessor, IList list)
|
|
|
+ internal void WriteList(StringBuilder builder, IList list)
|
|
|
{
|
|
|
builder.Append("[ ");
|
|
|
bool first = true;
|
|
|
foreach (var value in list)
|
|
|
{
|
|
|
- if (!CanWriteSingleValue(accessor.Descriptor, value))
|
|
|
+ if (!CanWriteSingleValue(value))
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
@@ -595,22 +583,20 @@ namespace Google.Protobuf
|
|
|
{
|
|
|
builder.Append(", ");
|
|
|
}
|
|
|
- WriteSingleValue(builder, accessor.Descriptor, value);
|
|
|
+ WriteValue(builder, value);
|
|
|
first = false;
|
|
|
}
|
|
|
builder.Append(first ? "]" : " ]");
|
|
|
}
|
|
|
|
|
|
- private void WriteDictionary(StringBuilder builder, IFieldAccessor accessor, IDictionary dictionary)
|
|
|
+ internal void WriteDictionary(StringBuilder builder, IDictionary dictionary)
|
|
|
{
|
|
|
builder.Append("{ ");
|
|
|
bool first = true;
|
|
|
- FieldDescriptor keyType = accessor.Descriptor.MessageType.FindFieldByNumber(1);
|
|
|
- FieldDescriptor valueType = accessor.Descriptor.MessageType.FindFieldByNumber(2);
|
|
|
// This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
|
|
|
foreach (DictionaryEntry pair in dictionary)
|
|
|
{
|
|
|
- if (!CanWriteSingleValue(valueType, pair.Value))
|
|
|
+ if (!CanWriteSingleValue(pair.Value))
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
@@ -619,32 +605,29 @@ namespace Google.Protobuf
|
|
|
builder.Append(", ");
|
|
|
}
|
|
|
string keyText;
|
|
|
- switch (keyType.FieldType)
|
|
|
+ if (pair.Key is string)
|
|
|
{
|
|
|
- case FieldType.String:
|
|
|
- keyText = (string) pair.Key;
|
|
|
- break;
|
|
|
- case FieldType.Bool:
|
|
|
- keyText = (bool) pair.Key ? "true" : "false";
|
|
|
- break;
|
|
|
- case FieldType.Fixed32:
|
|
|
- case FieldType.Fixed64:
|
|
|
- case FieldType.SFixed32:
|
|
|
- case FieldType.SFixed64:
|
|
|
- case FieldType.Int32:
|
|
|
- case FieldType.Int64:
|
|
|
- case FieldType.SInt32:
|
|
|
- case FieldType.SInt64:
|
|
|
- case FieldType.UInt32:
|
|
|
- case FieldType.UInt64:
|
|
|
- keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new ArgumentException("Invalid key type: " + keyType.FieldType);
|
|
|
+ keyText = (string) pair.Key;
|
|
|
+ }
|
|
|
+ else if (pair.Key is bool)
|
|
|
+ {
|
|
|
+ keyText = (bool) pair.Key ? "true" : "false";
|
|
|
+ }
|
|
|
+ else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong)
|
|
|
+ {
|
|
|
+ keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (pair.Key == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Dictionary has entry with null key");
|
|
|
+ }
|
|
|
+ throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
|
|
|
}
|
|
|
WriteString(builder, keyText);
|
|
|
builder.Append(": ");
|
|
|
- WriteSingleValue(builder, valueType, pair.Value);
|
|
|
+ WriteValue(builder, pair.Value);
|
|
|
first = false;
|
|
|
}
|
|
|
builder.Append(first ? "}" : " }");
|
|
@@ -655,12 +638,11 @@ namespace Google.Protobuf
|
|
|
/// Currently only relevant for enums, where unknown values can't be represented.
|
|
|
/// For repeated/map fields, this always returns true.
|
|
|
/// </summary>
|
|
|
- private bool CanWriteSingleValue(FieldDescriptor descriptor, object value)
|
|
|
+ private bool CanWriteSingleValue(object value)
|
|
|
{
|
|
|
- if (descriptor.FieldType == FieldType.Enum)
|
|
|
+ if (value is System.Enum)
|
|
|
{
|
|
|
- EnumValueDescriptor enumValue = descriptor.EnumType.FindValueByNumber((int) value);
|
|
|
- return enumValue != null;
|
|
|
+ return System.Enum.IsDefined(value.GetType(), value);
|
|
|
}
|
|
|
return true;
|
|
|
}
|