Added initial DictionaryReader/Writer implementations

pull/288/head
csharptest 14 years ago committed by rogerk
parent ddb74eb6a4
commit 4dc0dfb154
  1. 6
      src/ProtoBench/Program.cs
  2. 13
      src/ProtocolBuffers.Test/CompatTests/CompatibilityTests.cs
  3. 37
      src/ProtocolBuffers.Test/CompatTests/DictionaryCompatibilityTests.cs
  4. 1
      src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
  5. 2
      src/ProtocolBuffers/ProtocolBuffers.csproj
  6. 7
      src/ProtocolBuffers/Serialization/AbstractWriter.cs
  7. 227
      src/ProtocolBuffers/Serialization/DictionaryReader.cs
  8. 172
      src/ProtocolBuffers/Serialization/DictionaryWriter.cs
  9. 10
      src/ProtocolBuffers/Serialization/JsonFormatWriter.cs
  10. 2
      src/ProtocolBuffers/Serialization/XmlFormatWriter.cs

@ -137,6 +137,10 @@ namespace Google.ProtocolBuffers.ProtoBench
new JsonFormatWriter(temp).WriteMessage(sampleMessage); new JsonFormatWriter(temp).WriteMessage(sampleMessage);
string jsonMessageText = temp.ToString(); string jsonMessageText = temp.ToString();
IDictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
new DictionaryWriter(dictionary).WriteMessage(sampleMessage);
//Serializers //Serializers
if(!FastTest) RunBenchmark("Serialize to byte string", inputData.Length, () => sampleMessage.ToByteString()); if(!FastTest) RunBenchmark("Serialize to byte string", inputData.Length, () => sampleMessage.ToByteString());
RunBenchmark("Serialize to byte array", inputData.Length, () => sampleMessage.ToByteArray()); RunBenchmark("Serialize to byte array", inputData.Length, () => sampleMessage.ToByteArray());
@ -145,6 +149,7 @@ namespace Google.ProtocolBuffers.ProtoBench
RunBenchmark("Serialize to xml", xmlMessageText.Length, () => new XmlFormatWriter(new StringWriter()).WriteMessage(sampleMessage)); RunBenchmark("Serialize to xml", xmlMessageText.Length, () => new XmlFormatWriter(new StringWriter()).WriteMessage(sampleMessage));
RunBenchmark("Serialize to json", jsonMessageText.Length, () => new JsonFormatWriter(new StringWriter()).WriteMessage(sampleMessage)); RunBenchmark("Serialize to json", jsonMessageText.Length, () => new JsonFormatWriter(new StringWriter()).WriteMessage(sampleMessage));
RunBenchmark("Serialize to dictionary", sampleMessage.SerializedSize, () => new DictionaryWriter().WriteMessage(sampleMessage));
//Deserializers //Deserializers
if (!FastTest) RunBenchmark("Deserialize from byte string", inputData.Length, if (!FastTest) RunBenchmark("Deserialize from byte string", inputData.Length,
@ -168,6 +173,7 @@ namespace Google.ProtocolBuffers.ProtoBench
RunBenchmark("Deserialize from xml", xmlMessageText.Length, () => new XmlFormatReader(xmlMessageText).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild()); RunBenchmark("Deserialize from xml", xmlMessageText.Length, () => new XmlFormatReader(xmlMessageText).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
RunBenchmark("Deserialize from json", jsonMessageText.Length, () => new JsonFormatReader(jsonMessageText).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild()); RunBenchmark("Deserialize from json", jsonMessageText.Length, () => new JsonFormatReader(jsonMessageText).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
RunBenchmark("Deserialize from dictionary", sampleMessage.SerializedSize, () => new DictionaryReader(dictionary).Merge(defaultMessage.WeakCreateBuilderForType()).WeakBuild());
Console.WriteLine(); Console.WriteLine();
return true; return true;

@ -14,6 +14,11 @@ namespace Google.ProtocolBuffers.CompatTests
where TMessage : IMessageLite<TMessage, TBuilder> where TMessage : IMessageLite<TMessage, TBuilder>
where TBuilder : IBuilderLite<TMessage, TBuilder>; where TBuilder : IBuilderLite<TMessage, TBuilder>;
protected virtual void AssertOutputEquals(object lhs, object rhs)
{
Assert.AreEqual(lhs, rhs);
}
[Test] [Test]
public virtual void RoundTripMessage1OptimizeSize() public virtual void RoundTripMessage1OptimizeSize()
{ {
@ -23,7 +28,7 @@ namespace Google.ProtocolBuffers.CompatTests
SizeMessage1 copy = DeerializeMessage<SizeMessage1, SizeMessage1.Builder>(content, SizeMessage1.CreateBuilder(), ExtensionRegistry.Empty).Build(); SizeMessage1 copy = DeerializeMessage<SizeMessage1, SizeMessage1.Builder>(content, SizeMessage1.CreateBuilder(), ExtensionRegistry.Empty).Build();
Assert.AreEqual(msg, copy); Assert.AreEqual(msg, copy);
Assert.AreEqual(content, SerializeMessage<SizeMessage1,SizeMessage1.Builder>(copy)); AssertOutputEquals(content, SerializeMessage<SizeMessage1, SizeMessage1.Builder>(copy));
Assert.AreEqual(TestResources.google_message1, copy.ToByteArray()); Assert.AreEqual(TestResources.google_message1, copy.ToByteArray());
} }
@ -36,7 +41,7 @@ namespace Google.ProtocolBuffers.CompatTests
SizeMessage2 copy = DeerializeMessage<SizeMessage2, SizeMessage2.Builder>(content, SizeMessage2.CreateBuilder(), ExtensionRegistry.Empty).Build(); SizeMessage2 copy = DeerializeMessage<SizeMessage2, SizeMessage2.Builder>(content, SizeMessage2.CreateBuilder(), ExtensionRegistry.Empty).Build();
Assert.AreEqual(msg, copy); Assert.AreEqual(msg, copy);
Assert.AreEqual(content, SerializeMessage<SizeMessage2, SizeMessage2.Builder>(copy)); AssertOutputEquals(content, SerializeMessage<SizeMessage2, SizeMessage2.Builder>(copy));
Assert.AreEqual(TestResources.google_message2, copy.ToByteArray()); Assert.AreEqual(TestResources.google_message2, copy.ToByteArray());
} }
@ -49,7 +54,7 @@ namespace Google.ProtocolBuffers.CompatTests
SpeedMessage1 copy = DeerializeMessage<SpeedMessage1, SpeedMessage1.Builder>(content, SpeedMessage1.CreateBuilder(), ExtensionRegistry.Empty).Build(); SpeedMessage1 copy = DeerializeMessage<SpeedMessage1, SpeedMessage1.Builder>(content, SpeedMessage1.CreateBuilder(), ExtensionRegistry.Empty).Build();
Assert.AreEqual(msg, copy); Assert.AreEqual(msg, copy);
Assert.AreEqual(content, SerializeMessage<SpeedMessage1, SpeedMessage1.Builder>(copy)); AssertOutputEquals(content, SerializeMessage<SpeedMessage1, SpeedMessage1.Builder>(copy));
Assert.AreEqual(TestResources.google_message1, copy.ToByteArray()); Assert.AreEqual(TestResources.google_message1, copy.ToByteArray());
} }
@ -62,7 +67,7 @@ namespace Google.ProtocolBuffers.CompatTests
SpeedMessage2 copy = DeerializeMessage<SpeedMessage2, SpeedMessage2.Builder>(content, SpeedMessage2.CreateBuilder(), ExtensionRegistry.Empty).Build(); SpeedMessage2 copy = DeerializeMessage<SpeedMessage2, SpeedMessage2.Builder>(content, SpeedMessage2.CreateBuilder(), ExtensionRegistry.Empty).Build();
Assert.AreEqual(msg, copy); Assert.AreEqual(msg, copy);
Assert.AreEqual(content, SerializeMessage<SpeedMessage2, SpeedMessage2.Builder>(copy)); AssertOutputEquals(content, SerializeMessage<SpeedMessage2, SpeedMessage2.Builder>(copy));
Assert.AreEqual(TestResources.google_message2, copy.ToByteArray()); Assert.AreEqual(TestResources.google_message2, copy.ToByteArray());
} }

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Google.ProtocolBuffers.Serialization;
using NUnit.Framework;
namespace Google.ProtocolBuffers.CompatTests
{
[TestFixture]
public class DictionaryCompatibilityTests : CompatibilityTests
{
protected override object SerializeMessage<TMessage, TBuilder>(TMessage message)
{
DictionaryWriter writer = new DictionaryWriter();
writer.WriteMessage(message);
return writer.ToDictionary();
}
protected override TBuilder DeerializeMessage<TMessage, TBuilder>(object message, TBuilder builder, ExtensionRegistry registry)
{
new DictionaryReader((IDictionary<string, object>)message).Merge(builder);
return builder;
}
protected override void AssertOutputEquals(object lhs, object rhs)
{
IDictionary<string, object> left = (IDictionary<string, object>)lhs;
IDictionary<string, object> right = (IDictionary<string, object>)rhs;
Assert.AreEqual(
String.Join(",", new List<string>(left.Keys).ToArray()),
String.Join(",", new List<string>(right.Keys).ToArray())
);
}
}
}

@ -77,6 +77,7 @@
<Compile Include="Collections\PopsicleListTest.cs" /> <Compile Include="Collections\PopsicleListTest.cs" />
<Compile Include="CompatTests\BinaryCompatibilityTests.cs" /> <Compile Include="CompatTests\BinaryCompatibilityTests.cs" />
<Compile Include="CompatTests\CompatibilityTests.cs" /> <Compile Include="CompatTests\CompatibilityTests.cs" />
<Compile Include="CompatTests\DictionaryCompatibilityTests.cs" />
<Compile Include="CompatTests\JsonCompatibilityTests.cs" /> <Compile Include="CompatTests\JsonCompatibilityTests.cs" />
<Compile Include="CompatTests\TestResources.Designer.cs"> <Compile Include="CompatTests\TestResources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>

@ -184,6 +184,8 @@
<Compile Include="Serialization\AbstractTextReader.cs" /> <Compile Include="Serialization\AbstractTextReader.cs" />
<Compile Include="Serialization\AbstractTextWriter.cs" /> <Compile Include="Serialization\AbstractTextWriter.cs" />
<Compile Include="Serialization\AbstractWriter.cs" /> <Compile Include="Serialization\AbstractWriter.cs" />
<Compile Include="Serialization\DictionaryReader.cs" />
<Compile Include="Serialization\DictionaryWriter.cs" />
<Compile Include="Serialization\JsonFormatReader.cs" /> <Compile Include="Serialization\JsonFormatReader.cs" />
<Compile Include="Serialization\JsonFormatWriter.cs" /> <Compile Include="Serialization\JsonFormatWriter.cs" />
<Compile Include="Serialization\JsonTextCursor.cs" /> <Compile Include="Serialization\JsonTextCursor.cs" />

@ -41,13 +41,6 @@ namespace Google.ProtocolBuffers.Serialization
/// </summary> /// </summary>
public abstract void WriteMessage(IMessageLite message); public abstract void WriteMessage(IMessageLite message);
/// <summary>
/// Writes a message
/// </summary>
public abstract void WriteMessage(string field, IMessageLite message);
/// <summary> /// <summary>
/// Writes a Boolean value /// Writes a Boolean value
/// </summary> /// </summary>

@ -0,0 +1,227 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Allows reading messages from a name/value dictionary
/// </summary>
public class DictionaryReader : AbstractReader
{
private readonly IEnumerator<KeyValuePair<string, object>> _input;
private bool _ready;
/// <summary>
/// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary
/// </summary>
public DictionaryReader(IEnumerable<KeyValuePair<string, object>> input)
{
_input = input.GetEnumerator();
_ready = _input.MoveNext();
}
/// <summary>
/// Merges the contents of stream into the provided message builder
/// </summary>
public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
{
builder.WeakMergeFrom(this, registry);
return builder;
}
/// <summary>
/// Peeks at the next field in the input stream and returns what information is available.
/// </summary>
/// <remarks>
/// This may be called multiple times without actually reading the field. Only after the field
/// is either read, or skipped, should PeekNext return a different value.
/// </remarks>
protected override bool PeekNext(out string field)
{
field = _ready ? _input.Current.Key : null;
return _ready;
}
/// <summary>
/// Causes the reader to skip past this field
/// </summary>
protected override void Skip()
{
_ready = _input.MoveNext();
}
private bool GetValue<T>(ref T value)
{
if (!_ready) return false;
object obj = _input.Current.Value;
if (obj is T)
value = (T)obj;
else
{
try
{
if (obj is IConvertible)
value = (T)Convert.ChangeType(obj, typeof(T));
else
value = (T)obj;
}
catch
{
_ready = _input.MoveNext();
return false;
}
}
_ready = _input.MoveNext();
return true;
}
/// <summary>
/// Returns true if it was able to read a Boolean from the input
/// </summary>
protected override bool Read(ref bool value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Int32 from the input
/// </summary>
protected override bool Read(ref int value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a UInt32 from the input
/// </summary>
[CLSCompliant(false)]
protected override bool Read(ref uint value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Int64 from the input
/// </summary>
protected override bool Read(ref long value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a UInt64 from the input
/// </summary>
[CLSCompliant(false)]
protected override bool Read(ref ulong value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Single from the input
/// </summary>
protected override bool Read(ref float value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a Double from the input
/// </summary>
protected override bool Read(ref double value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a String from the input
/// </summary>
protected override bool Read(ref string value)
{
return GetValue(ref value);
}
/// <summary>
/// Returns true if it was able to read a ByteString from the input
/// </summary>
protected override bool Read(ref ByteString value)
{
byte[] rawbytes = null;
if (GetValue(ref rawbytes))
{
value = ByteString.AttachBytes(rawbytes);
return true;
}
return false;
}
/// <summary>
/// returns true if it was able to read a single value into the value reference. The value
/// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.
/// </summary>
protected override bool ReadEnum(ref object value)
{
return GetValue(ref value);
}
/// <summary>
/// Merges the input stream into the provided IBuilderLite
/// </summary>
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
{
IDictionary<string, object> values = null;
if (GetValue(ref values))
{
new DictionaryReader(values).Merge(builder, registry);
return true;
}
return false;
}
public override bool ReadArray<T>(FieldType type, string field, ICollection<T> items)
{
object[] array = null;
if (GetValue(ref array))
{
foreach (T item in array)
items.Add(item);
return true;
}
return false;
}
public override bool ReadEnumArray(string field, ICollection<object> items)
{
object[] array = null;
if (GetValue(ref array))
{
foreach (object item in array)
items.Add(item);
return true;
}
return false;
}
public override bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType, ExtensionRegistry registry)
{
object[] array = null;
if (GetValue(ref array))
{
foreach (IDictionary<string, object> item in array)
{
IBuilderLite builder = messageType.WeakCreateBuilderForType();
new DictionaryReader(item).Merge(builder);
items.Add((T)builder.WeakBuild());
}
return true;
}
return false;
}
public override bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType, ExtensionRegistry registry)
{ return ReadMessageArray(field, items, messageType, registry); }
}
}

@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.Serialization
{
/// <summary>
/// Allows writing messages to a name/value dictionary
/// </summary>
public class DictionaryWriter : AbstractWriter
{
private readonly IDictionary<string, object> _output;
/// <summary>
/// Constructs a writer using a new dictionary
/// </summary>
public DictionaryWriter()
: this(new Dictionary<string,object>())
{ }
/// <summary>
/// Constructs a writer using an existing dictionary
/// </summary>
public DictionaryWriter(IDictionary<string, object> output)
{
ThrowHelper.ThrowIfNull(output, "output");
_output = output;
}
/// <summary>
/// Accesses the dictionary that is backing this writer
/// </summary>
public IDictionary<string, object> ToDictionary() { return _output; }
/// <summary>
/// Writes the message to the the formatted stream.
/// </summary>
public override void WriteMessage(IMessageLite message)
{
message.WriteTo(this);
}
/// <summary>
/// Writes a Boolean value
/// </summary>
protected override void Write(string field, bool value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Int32 value
/// </summary>
protected override void Write(string field, int value)
{
_output[field] = value;
}
/// <summary>
/// Writes a UInt32 value
/// </summary>
[CLSCompliant(false)]
protected override void Write(string field, uint value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Int64 value
/// </summary>
protected override void Write(string field, long value)
{
_output[field] = value;
}
/// <summary>
/// Writes a UInt64 value
/// </summary>
[CLSCompliant(false)]
protected override void Write(string field, ulong value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Single value
/// </summary>
protected override void Write(string field, float value)
{
_output[field] = value;
}
/// <summary>
/// Writes a Double value
/// </summary>
protected override void Write(string field, double value)
{
_output[field] = value;
}
/// <summary>
/// Writes a String value
/// </summary>
protected override void Write(string field, string value)
{
_output[field] = value;
}
/// <summary>
/// Writes a set of bytes
/// </summary>
protected override void Write(string field, ByteString value)
{
_output[field] = value.ToByteArray();
}
/// <summary>
/// Writes a message or group as a field
/// </summary>
protected override void WriteMessageOrGroup(string field, IMessageLite message)
{
DictionaryWriter writer = new DictionaryWriter();
writer.WriteMessage(message);
_output[field] = writer.ToDictionary();
}
/// <summary>
/// Writes a System.Enum by the numeric and textual value
/// </summary>
protected override void WriteEnum(string field, int number, string name)
{
_output[field] = number;
}
/// <summary>
/// Writes an array of field values
/// </summary>
protected override void WriteArray(FieldType fieldType, string field, System.Collections.IEnumerable items)
{
List<object> objects = new List<object>();
foreach (object o in items)
{
switch (fieldType)
{
case FieldType.Group:
case FieldType.Message:
{
DictionaryWriter writer = new DictionaryWriter();
writer.WriteMessage((IMessageLite)o);
objects.Add(writer.ToDictionary());
}
break;
case FieldType.Bytes:
objects.Add(((ByteString)o).ToByteArray());
break;
case FieldType.Enum:
if (o is IEnumLite)
objects.Add(((IEnumLite)o).Number);
else
objects.Add((int)o);
break;
default:
objects.Add(o);
break;
}
}
_output[field] = objects.ToArray();
}
}
}

@ -263,16 +263,6 @@ namespace Google.ProtocolBuffers.Serialization
Flush(); Flush();
} }
/// <summary>
/// Writes a message
/// </summary>
[System.ComponentModel.Browsable(false)]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public override void WriteMessage(string field, IMessageLite message)
{
WriteMessage(message);
}
/// <summary> /// <summary>
/// Used in streaming arrays of objects to the writer /// Used in streaming arrays of objects to the writer
/// </summary> /// </summary>

@ -73,7 +73,7 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary> /// <summary>
/// Writes a message as an element with the given name /// Writes a message as an element with the given name
/// </summary> /// </summary>
public override void WriteMessage(string elementName, IMessageLite message) public void WriteMessage(string elementName, IMessageLite message)
{ {
if (TestOption(XmlWriterOptions.OutputJsonTypes)) if (TestOption(XmlWriterOptions.OutputJsonTypes))
{ {

Loading…
Cancel
Save