Commit cdeda4b8 authored by Jon Skeet's avatar Jon Skeet

Minor cleanup.

- Make some members internal
- Remove a lot of FrameworkPortability that isn't required
- Start adding documentation comments
- Remove some more group-based members
- Not passing in "the last tag read" into Read*Array, g
parent d7dda2fe
...@@ -214,7 +214,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook { ...@@ -214,7 +214,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
break; break;
} }
case 34: { case 34: {
input.ReadMessageArray(tag, phone_, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.Parser); input.ReadMessageArray(phone_, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.Parser);
break; break;
} }
} }
...@@ -432,7 +432,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook { ...@@ -432,7 +432,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
} }
break; break;
case 10: { case 10: {
input.ReadMessageArray(tag, person_, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Parser); input.ReadMessageArray(person_, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Parser);
break; break;
} }
} }
......
...@@ -489,7 +489,7 @@ namespace Google.Protobuf ...@@ -489,7 +489,7 @@ namespace Google.Protobuf
Assert.IsTrue(input.ReadTag(out tag)); Assert.IsTrue(input.ReadTag(out tag));
RepeatedField<TestNegEnum> values = new RepeatedField<TestNegEnum>(); RepeatedField<TestNegEnum> values = new RepeatedField<TestNegEnum>();
input.ReadEnumArray(tag, values); input.ReadEnumArray(values);
Assert.AreEqual(6, values.Count); Assert.AreEqual(6, values.Count);
Assert.AreEqual(TestNegEnum.None, values[0]); Assert.AreEqual(TestNegEnum.None, values[0]);
...@@ -513,7 +513,7 @@ namespace Google.Protobuf ...@@ -513,7 +513,7 @@ namespace Google.Protobuf
Assert.IsTrue(input.ReadTag(out tag)); Assert.IsTrue(input.ReadTag(out tag));
RepeatedField<TestNegEnum> values = new RepeatedField<TestNegEnum>(); RepeatedField<TestNegEnum> values = new RepeatedField<TestNegEnum>();
input.ReadEnumArray(tag, values); input.ReadEnumArray(values);
Assert.AreEqual(6, values.Count); Assert.AreEqual(6, values.Count);
Assert.AreEqual(TestNegEnum.None, values[0]); Assert.AreEqual(TestNegEnum.None, values[0]);
......
...@@ -326,7 +326,7 @@ namespace Google.Protobuf ...@@ -326,7 +326,7 @@ namespace Google.Protobuf
Assert.IsTrue(input.ReadTag(out tag)); Assert.IsTrue(input.ReadTag(out tag));
List<int> values = new List<int>(); List<int> values = new List<int>();
input.ReadInt32Array(tag, values); input.ReadInt32Array(values);
Assert.AreEqual(6, values.Count); Assert.AreEqual(6, values.Count);
for (int i = 0; i > -6; i--) for (int i = 0; i > -6; i--)
...@@ -349,7 +349,7 @@ namespace Google.Protobuf ...@@ -349,7 +349,7 @@ namespace Google.Protobuf
Assert.IsTrue(input.ReadTag(out tag)); Assert.IsTrue(input.ReadTag(out tag));
List<int> values = new List<int>(); List<int> values = new List<int>();
input.ReadInt32Array(tag, values); input.ReadInt32Array(values);
Assert.AreEqual(6, values.Count); Assert.AreEqual(6, values.Count);
for (int i = 0; i > -6; i--) for (int i = 0; i > -6; i--)
......
...@@ -218,12 +218,12 @@ namespace UnitTest.Issues.TestProtos { ...@@ -218,12 +218,12 @@ namespace UnitTest.Issues.TestProtos {
} }
case 18: case 18:
case 16: { case 16: {
input.ReadEnumArray<global::UnitTest.Issues.TestProtos.NegativeEnum>(tag, values_); input.ReadEnumArray<global::UnitTest.Issues.TestProtos.NegativeEnum>(values_);
break; break;
} }
case 26: case 26:
case 24: { case 24: {
input.ReadEnumArray<global::UnitTest.Issues.TestProtos.NegativeEnum>(tag, packedValues_); input.ReadEnumArray<global::UnitTest.Issues.TestProtos.NegativeEnum>(packedValues_);
break; break;
} }
} }
...@@ -495,7 +495,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -495,7 +495,7 @@ namespace UnitTest.Issues.TestProtos {
} }
case 18: case 18:
case 16: { case 16: {
input.ReadInt32Array(tag, primitiveArray_); input.ReadInt32Array(primitiveArray_);
break; break;
} }
case 26: { case 26: {
...@@ -506,7 +506,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -506,7 +506,7 @@ namespace UnitTest.Issues.TestProtos {
break; break;
} }
case 34: { case 34: {
input.ReadMessageArray(tag, messageArray_, global::UnitTest.Issues.TestProtos.DeprecatedChild.Parser); input.ReadMessageArray(messageArray_, global::UnitTest.Issues.TestProtos.DeprecatedChild.Parser);
break; break;
} }
case 40: { case 40: {
...@@ -515,7 +515,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -515,7 +515,7 @@ namespace UnitTest.Issues.TestProtos {
} }
case 50: case 50:
case 48: { case 48: {
input.ReadEnumArray<global::UnitTest.Issues.TestProtos.DeprecatedEnum>(tag, enumArray_); input.ReadEnumArray<global::UnitTest.Issues.TestProtos.DeprecatedEnum>(enumArray_);
break; break;
} }
} }
......
...@@ -51,7 +51,7 @@ namespace Google.Protobuf ...@@ -51,7 +51,7 @@ namespace Google.Protobuf
/// <summary> /// <summary>
/// Determines which copy routine to use based on the number of bytes to be copied. /// Determines which copy routine to use based on the number of bytes to be copied.
/// </summary> /// </summary>
public static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
{ {
if (count > CopyThreshold) if (count > CopyThreshold)
{ {
...@@ -66,7 +66,7 @@ namespace Google.Protobuf ...@@ -66,7 +66,7 @@ namespace Google.Protobuf
/// <summary> /// <summary>
/// Copy the bytes provided with a for loop, faster when there are only a few bytes to copy /// Copy the bytes provided with a for loop, faster when there are only a few bytes to copy
/// </summary> /// </summary>
public static void ByteCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) internal static void ByteCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
{ {
int stop = srcOffset + count; int stop = srcOffset + count;
for (int i = srcOffset; i < stop; i++) for (int i = srcOffset; i < stop; i++)
...@@ -78,12 +78,11 @@ namespace Google.Protobuf ...@@ -78,12 +78,11 @@ namespace Google.Protobuf
/// <summary> /// <summary>
/// Reverses the order of bytes in the array /// Reverses the order of bytes in the array
/// </summary> /// </summary>
public static void Reverse(byte[] bytes) internal static void Reverse(byte[] bytes)
{ {
byte temp;
for (int first = 0, last = bytes.Length - 1; first < last; first++, last--) for (int first = 0, last = bytes.Length - 1; first < last; first++, last--)
{ {
temp = bytes[first]; byte temp = bytes[first];
bytes[first] = bytes[last]; bytes[first] = bytes[last];
bytes[last] = temp; bytes[last] = temp;
} }
......
...@@ -37,9 +37,7 @@ ...@@ -37,9 +37,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
using Google.Protobuf.Collections; using Google.Protobuf.Collections;
using Google.Protobuf.Descriptors;
namespace Google.Protobuf namespace Google.Protobuf
{ {
...@@ -183,7 +181,7 @@ namespace Google.Protobuf ...@@ -183,7 +181,7 @@ namespace Google.Protobuf
/// </summary> /// </summary>
/// <exception cref="InvalidProtocolBufferException">The last /// <exception cref="InvalidProtocolBufferException">The last
/// tag read was not the one specified</exception> /// tag read was not the one specified</exception>
public void CheckLastTagWas(uint value) internal void CheckLastTagWas(uint value)
{ {
if (lastTag != value) if (lastTag != value)
{ {
...@@ -251,7 +249,7 @@ namespace Google.Protobuf ...@@ -251,7 +249,7 @@ namespace Google.Protobuf
/// </summary> /// </summary>
public double ReadDouble() public double ReadDouble()
{ {
return FrameworkPortability.Int64ToDouble((long) ReadRawLittleEndian64()); return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
} }
/// <summary> /// <summary>
...@@ -347,21 +345,6 @@ namespace Google.Protobuf ...@@ -347,21 +345,6 @@ namespace Google.Protobuf
return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(size), 0, size); return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(size), 0, size);
} }
/// <summary>
/// Reads a group field value from the stream.
/// </summary>
public void ReadGroup(int fieldNumber, IMessage message)
{
if (recursionDepth >= recursionLimit)
{
throw InvalidProtocolBufferException.RecursionLimitExceeded();
}
++recursionDepth;
message.MergeFrom(this);
CheckLastTagWas(WireFormat.MakeTag(fieldNumber, WireFormat.WireType.EndGroup));
--recursionDepth;
}
/// <summary> /// <summary>
/// Reads an embedded message field value from the stream. /// Reads an embedded message field value from the stream.
/// </summary> /// </summary>
...@@ -516,24 +499,34 @@ namespace Google.Protobuf ...@@ -516,24 +499,34 @@ namespace Google.Protobuf
return false; return false;
} }
public void ReadStringArray(uint fieldTag, ICollection<string> list) /// <summary>
/// Reads a string array.
/// </summary>
/// <remarks>The stream is assumed to be positioned after a tag indicating the field
/// repeated string value. A string is read, and then if the next tag is the same,
/// the process is repeated, until the next tag is a different one.</remarks>
/// <param name="list"></param>
public void ReadStringArray(ICollection<string> list)
{ {
uint fieldTag = lastTag;
do do
{ {
list.Add(ReadString()); list.Add(ReadString());
} while (ContinueArray(fieldTag)); } while (ContinueArray(fieldTag));
} }
public void ReadBytesArray(uint fieldTag, ICollection<ByteString> list) public void ReadBytesArray(ICollection<ByteString> list)
{ {
uint fieldTag = lastTag;
do do
{ {
list.Add(ReadBytes()); list.Add(ReadBytes());
} while (ContinueArray(fieldTag)); } while (ContinueArray(fieldTag));
} }
public void ReadBoolArray(uint fieldTag, ICollection<bool> list) public void ReadBoolArray(ICollection<bool> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -545,8 +538,9 @@ namespace Google.Protobuf ...@@ -545,8 +538,9 @@ namespace Google.Protobuf
} }
} }
public void ReadInt32Array(uint fieldTag, ICollection<int> list) public void ReadInt32Array(ICollection<int> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -558,8 +552,9 @@ namespace Google.Protobuf ...@@ -558,8 +552,9 @@ namespace Google.Protobuf
} }
} }
public void ReadSInt32Array(uint fieldTag, ICollection<int> list) public void ReadSInt32Array(ICollection<int> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -571,8 +566,9 @@ namespace Google.Protobuf ...@@ -571,8 +566,9 @@ namespace Google.Protobuf
} }
} }
public void ReadUInt32Array(uint fieldTag, ICollection<uint> list) public void ReadUInt32Array(ICollection<uint> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -584,8 +580,9 @@ namespace Google.Protobuf ...@@ -584,8 +580,9 @@ namespace Google.Protobuf
} }
} }
public void ReadFixed32Array(uint fieldTag, ICollection<uint> list) public void ReadFixed32Array(ICollection<uint> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -597,8 +594,9 @@ namespace Google.Protobuf ...@@ -597,8 +594,9 @@ namespace Google.Protobuf
} }
} }
public void ReadSFixed32Array(uint fieldTag, ICollection<int> list) public void ReadSFixed32Array(ICollection<int> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -610,8 +608,9 @@ namespace Google.Protobuf ...@@ -610,8 +608,9 @@ namespace Google.Protobuf
} }
} }
public void ReadInt64Array(uint fieldTag, ICollection<long> list) public void ReadInt64Array(ICollection<long> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -623,8 +622,9 @@ namespace Google.Protobuf ...@@ -623,8 +622,9 @@ namespace Google.Protobuf
} }
} }
public void ReadSInt64Array(uint fieldTag, ICollection<long> list) public void ReadSInt64Array(ICollection<long> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -636,8 +636,9 @@ namespace Google.Protobuf ...@@ -636,8 +636,9 @@ namespace Google.Protobuf
} }
} }
public void ReadUInt64Array(uint fieldTag, ICollection<ulong> list) public void ReadUInt64Array(ICollection<ulong> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -649,8 +650,9 @@ namespace Google.Protobuf ...@@ -649,8 +650,9 @@ namespace Google.Protobuf
} }
} }
public void ReadFixed64Array(uint fieldTag, ICollection<ulong> list) public void ReadFixed64Array(ICollection<ulong> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -662,8 +664,9 @@ namespace Google.Protobuf ...@@ -662,8 +664,9 @@ namespace Google.Protobuf
} }
} }
public void ReadSFixed64Array(uint fieldTag, ICollection<long> list) public void ReadSFixed64Array(ICollection<long> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -675,8 +678,9 @@ namespace Google.Protobuf ...@@ -675,8 +678,9 @@ namespace Google.Protobuf
} }
} }
public void ReadDoubleArray(uint fieldTag, ICollection<double> list) public void ReadDoubleArray(ICollection<double> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -688,8 +692,9 @@ namespace Google.Protobuf ...@@ -688,8 +692,9 @@ namespace Google.Protobuf
} }
} }
public void ReadFloatArray(uint fieldTag, ICollection<float> list) public void ReadFloatArray(ICollection<float> list)
{ {
uint fieldTag = lastTag;
bool isPacked; bool isPacked;
int holdLimit; int holdLimit;
if (BeginArray(fieldTag, out isPacked, out holdLimit)) if (BeginArray(fieldTag, out isPacked, out holdLimit))
...@@ -701,9 +706,10 @@ namespace Google.Protobuf ...@@ -701,9 +706,10 @@ namespace Google.Protobuf
} }
} }
public void ReadEnumArray<T>(uint fieldTag, RepeatedField<T> list) public void ReadEnumArray<T>(RepeatedField<T> list)
where T : struct, IComparable, IFormattable where T : struct, IComparable, IFormattable
{ {
uint fieldTag = lastTag;
WireFormat.WireType wformat = WireFormat.GetTagWireType(fieldTag); WireFormat.WireType wformat = WireFormat.GetTagWireType(fieldTag);
// 2.3 allows packed form even if the field is not declared packed. // 2.3 allows packed form even if the field is not declared packed.
...@@ -727,9 +733,10 @@ namespace Google.Protobuf ...@@ -727,9 +733,10 @@ namespace Google.Protobuf
} }
} }
public void ReadMessageArray<T>(uint fieldTag, ICollection<T> list, MessageParser<T> messageParser) public void ReadMessageArray<T>(ICollection<T> list, MessageParser<T> messageParser)
where T : IMessage<T> where T : IMessage<T>
{ {
uint fieldTag = lastTag;
do do
{ {
T message = messageParser.CreateTemplate(); T message = messageParser.CreateTemplate();
...@@ -737,17 +744,6 @@ namespace Google.Protobuf ...@@ -737,17 +744,6 @@ namespace Google.Protobuf
list.Add(message); list.Add(message);
} while (ContinueArray(fieldTag)); } while (ContinueArray(fieldTag));
} }
public void ReadGroupArray<T>(uint fieldTag, ICollection<T> list, MessageParser<T> messageParser)
where T : IMessage<T>
{
do
{
T message = messageParser.CreateTemplate();
ReadGroup(WireFormat.GetTagFieldNumber(fieldTag), message);
list.Add(message);
} while (ContinueArray(fieldTag));
}
#endregion #endregion
#region Underlying reading primitives #region Underlying reading primitives
......
...@@ -35,12 +35,9 @@ ...@@ -35,12 +35,9 @@
#endregion #endregion
using System; using System;
using System.Collections;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using Google.Protobuf.Collections; using Google.Protobuf.Collections;
using Google.Protobuf.Descriptors;
namespace Google.Protobuf namespace Google.Protobuf
{ {
...@@ -151,7 +148,7 @@ namespace Google.Protobuf ...@@ -151,7 +148,7 @@ namespace Google.Protobuf
/// </summary> /// </summary>
public void WriteDouble(double value) public void WriteDouble(double value)
{ {
WriteRawLittleEndian64((ulong)FrameworkPortability.DoubleToInt64(value)); WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
} }
/// <summary> /// <summary>
......
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
#endregion #endregion
using System; using System;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace Google.Protobuf namespace Google.Protobuf
...@@ -46,66 +44,10 @@ namespace Google.Protobuf ...@@ -46,66 +44,10 @@ namespace Google.Protobuf
/// </summary> /// </summary>
internal static class FrameworkPortability internal static class FrameworkPortability
{ {
#if COMPACT_FRAMEWORK // The value of RegexOptions.Compiled is 8. We can test for the presence at
internal const string NewLine = "\n"; // execution time using Enum.IsDefined, so a single build will do the right thing
#else // on each platform.
internal static readonly string NewLine = System.Environment.NewLine; internal static readonly RegexOptions CompiledRegexWhereAvailable =
#endif Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None;
#if CLIENTPROFILE
internal const RegexOptions CompiledRegexWhereAvailable = RegexOptions.Compiled;
#else
internal const RegexOptions CompiledRegexWhereAvailable = RegexOptions.None;
#endif
internal static CultureInfo InvariantCulture
{
get { return CultureInfo.InvariantCulture; }
}
internal static double Int64ToDouble(long value)
{
#if CLIENTPROFILE
return BitConverter.Int64BitsToDouble(value);
#else
double[] arresult = new double[1];
Buffer.BlockCopy(new[] { value }, 0, arresult, 0, 8);
return arresult[0];
#endif
}
internal static long DoubleToInt64(double value)
{
#if CLIENTPROFILE
return BitConverter.DoubleToInt64Bits(value);
#else
long[] arresult = new long[1];
Buffer.BlockCopy(new[] { value }, 0, arresult, 0, 8);
return arresult[0];
#endif
}
internal static bool TryParseInt32(string text, out int number)
{
return TryParseInt32(text, NumberStyles.Any, InvariantCulture, out number);
}
internal static bool TryParseInt32(string text, NumberStyles style, IFormatProvider format, out int number)
{
#if COMPACT_FRAMEWORK
try
{
number = int.Parse(text, style, format);
return true;
}
catch
{
number = 0;
return false;
}
#else
return int.TryParse(text, style, format, out number);
#endif
}
} }
} }
\ No newline at end of file
...@@ -34,30 +34,63 @@ ...@@ -34,30 +34,63 @@
#endregion #endregion
using System;
using System.Collections.Generic;
using System.IO;
using Google.Protobuf.Descriptors;
using Google.Protobuf.FieldAccess; using Google.Protobuf.FieldAccess;
namespace Google.Protobuf namespace Google.Protobuf
{ {
// TODO(jonskeet): Do we want a "weak" version of IReflectedMessage? // TODO(jonskeet): Do we want a "weak" (non-generic) version of IReflectedMessage?
/// <summary>
/// Reflection support for a specific message type. message
/// </summary>
/// <typeparam name="T">The message type being reflected.</typeparam>
public interface IReflectedMessage<T> where T : IMessage<T> public interface IReflectedMessage<T> where T : IMessage<T>
{ {
FieldAccessorTable<T> Fields { get; } FieldAccessorTable<T> Fields { get; }
// TODO(jonskeet): Descriptor? Or a single property which has "all you need for reflection"?
} }
/// <summary>
/// Interface for a Protocol Buffers message, supporting
/// basic operations required for serialization.
/// </summary>
public interface IMessage public interface IMessage
{ {
/// <summary>
/// Merges the data from the specified coded input stream with the current message.
/// </summary>
/// <remarks>See the user guide for precise merge semantics.</remarks>
/// <param name="input"></param>
void MergeFrom(CodedInputStream input); void MergeFrom(CodedInputStream input);
/// <summary>
/// Writes the data to the given coded output stream.
/// </summary>
/// <param name="output">Coded output stream to write the data to. Must not be null.</param>
void WriteTo(CodedOutputStream output); void WriteTo(CodedOutputStream output);
/// <summary>
/// Calculates the size of this message in Protocol Buffer wire format, in bytes.
/// </summary>
/// <returns>The number of bytes required to write this message
/// to a coded output stream.</returns>
int CalculateSize(); int CalculateSize();
} }
/// <summary>
/// Generic interface for a Protocol Buffers message,
/// where the type parameter is expected to be the same type as
/// the implementation class.
/// </summary>
/// <typeparam name="T">The message type.</typeparam>
public interface IMessage<T> : IMessage where T : IMessage<T> public interface IMessage<T> : IMessage where T : IMessage<T>
{ {
/// <summary>
/// Merges the given message into this one.
/// </summary>
/// <remarks>See the user guide for precise merge semantics.</remarks>
/// <param name="message">The message to merge with this one. Must not be null.</param>
void MergeFrom(T message); void MergeFrom(T message);
} }
} }
\ No newline at end of file
...@@ -2,11 +2,15 @@ ...@@ -2,11 +2,15 @@
namespace Google.Protobuf namespace Google.Protobuf
{ {
// TODO: MessageExtensions? /// <summary>
public static class Extensions /// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>.
/// </summary>
public static class MessageExtensions
{ {
public static void MergeFrom(this IMessage message, byte[] data) public static void MergeFrom(this IMessage message, byte[] data)
{ {
ThrowHelper.ThrowIfNull(message, "message");
ThrowHelper.ThrowIfNull(data, "data");
CodedInputStream input = CodedInputStream.CreateInstance(data); CodedInputStream input = CodedInputStream.CreateInstance(data);
message.MergeFrom(input); message.MergeFrom(input);
input.CheckLastTagWas(0); input.CheckLastTagWas(0);
...@@ -14,6 +18,8 @@ namespace Google.Protobuf ...@@ -14,6 +18,8 @@ namespace Google.Protobuf
public static void MergeFrom(this IMessage message, ByteString data) public static void MergeFrom(this IMessage message, ByteString data)
{ {
ThrowHelper.ThrowIfNull(message, "message");
ThrowHelper.ThrowIfNull(data, "data");
CodedInputStream input = data.CreateCodedInput(); CodedInputStream input = data.CreateCodedInput();
message.MergeFrom(input); message.MergeFrom(input);
input.CheckLastTagWas(0); input.CheckLastTagWas(0);
...@@ -21,6 +27,8 @@ namespace Google.Protobuf ...@@ -21,6 +27,8 @@ namespace Google.Protobuf
public static void MergeFrom(this IMessage message, Stream input) public static void MergeFrom(this IMessage message, Stream input)
{ {
ThrowHelper.ThrowIfNull(message, "message");
ThrowHelper.ThrowIfNull(input, "input");
CodedInputStream codedInput = CodedInputStream.CreateInstance(input); CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
message.MergeFrom(codedInput); message.MergeFrom(codedInput);
codedInput.CheckLastTagWas(0); codedInput.CheckLastTagWas(0);
...@@ -28,6 +36,8 @@ namespace Google.Protobuf ...@@ -28,6 +36,8 @@ namespace Google.Protobuf
public static void MergeDelimitedFrom(this IMessage message, Stream input) public static void MergeDelimitedFrom(this IMessage message, Stream input)
{ {
ThrowHelper.ThrowIfNull(message, "message");
ThrowHelper.ThrowIfNull(input, "input");
int size = (int)CodedInputStream.ReadRawVarint32(input); int size = (int)CodedInputStream.ReadRawVarint32(input);
Stream limitedStream = new LimitedInputStream(input, size); Stream limitedStream = new LimitedInputStream(input, size);
message.MergeFrom(limitedStream); message.MergeFrom(limitedStream);
...@@ -35,6 +45,7 @@ namespace Google.Protobuf ...@@ -35,6 +45,7 @@ namespace Google.Protobuf
public static byte[] ToByteArray(this IMessage message) public static byte[] ToByteArray(this IMessage message)
{ {
ThrowHelper.ThrowIfNull(message, "message");
byte[] result = new byte[message.CalculateSize()]; byte[] result = new byte[message.CalculateSize()];
CodedOutputStream output = CodedOutputStream.CreateInstance(result); CodedOutputStream output = CodedOutputStream.CreateInstance(result);
message.WriteTo(output); message.WriteTo(output);
...@@ -44,18 +55,17 @@ namespace Google.Protobuf ...@@ -44,18 +55,17 @@ namespace Google.Protobuf
public static void WriteTo(this IMessage message, Stream output) public static void WriteTo(this IMessage message, Stream output)
{ {
ThrowHelper.ThrowIfNull(message, "message");
ThrowHelper.ThrowIfNull(output, "output");
CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output); CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
message.WriteTo(codedOutput); message.WriteTo(codedOutput);
codedOutput.Flush(); codedOutput.Flush();
} }
public static void WriteTo(this IMessage message, CodedOutputStream output)
{
message.WriteTo(output);
}
public static void WriteDelimitedTo(this IMessage message, Stream output) public static void WriteDelimitedTo(this IMessage message, Stream output)
{ {
ThrowHelper.ThrowIfNull(message, "message");
ThrowHelper.ThrowIfNull(output, "output");
CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output); CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
codedOutput.WriteRawVarint32((uint)message.CalculateSize()); codedOutput.WriteRawVarint32((uint)message.CalculateSize());
message.WriteTo(codedOutput); message.WriteTo(codedOutput);
...@@ -64,6 +74,7 @@ namespace Google.Protobuf ...@@ -64,6 +74,7 @@ namespace Google.Protobuf
public static ByteString ToByteString(this IMessage message) public static ByteString ToByteString(this IMessage message)
{ {
ThrowHelper.ThrowIfNull(message, "message");
return ByteString.AttachBytes(message.ToByteArray()); return ByteString.AttachBytes(message.ToByteArray());
} }
} }
......
using System; using System;
using System.IO; using System.IO;
using Google.Protobuf;
namespace Google.Protobuf namespace Google.Protobuf
{ {
/// <summary>
/// A parser for a specific message type.
/// </summary>
/// <remarks>
/// <p>
/// This delegates most behavior to the
/// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
/// provides convenient overloads to parse from a variety of sources.
/// </p>
/// <p>
/// Most applications will never need to create their own instances of this type;
/// instead, use the static <c>Parser</c> property of a generated message type to obtain a
/// parser for that type.
/// </p>
/// </remarks>
/// <typeparam name="T">The type of message to be parsed.</typeparam>
public sealed class MessageParser<T> where T : IMessage<T> public sealed class MessageParser<T> where T : IMessage<T>
{ {
private readonly Func<T> factory; private readonly Func<T> factory;
/// <summary>
/// Creates a new parser.
/// </summary>
/// <remarks>
/// The factory method is effectively an optimization over using a generic constraint
/// to require a parameterless constructor: delegates are significantly faster to execute.
/// </remarks>
/// <param name="factory">Function to invoke when a new, empty message is required.</param>
public MessageParser(Func<T> factory) public MessageParser(Func<T> factory)
{ {
this.factory = factory; this.factory = factory;
} }
// Creates a template instance ready for population. /// <summary>
/// Creates a template instance ready for population.
/// </summary>
/// <returns>An empty message.</returns>
internal T CreateTemplate() internal T CreateTemplate()
{ {
return factory(); return factory();
} }
/// <summary>
/// Parses a message from a byte array.
/// </summary>
/// <param name="data">The byte array containing the message. Must not be null.</param>
/// <returns>The newly parsed message.</returns>
public T ParseFrom(byte[] data) public T ParseFrom(byte[] data)
{ {
ThrowHelper.ThrowIfNull(data, "data");
T message = factory(); T message = factory();
message.MergeFrom(data); message.MergeFrom(data);
return message; return message;
...@@ -28,6 +60,7 @@ namespace Google.Protobuf ...@@ -28,6 +60,7 @@ namespace Google.Protobuf
public T ParseFrom(ByteString data) public T ParseFrom(ByteString data)
{ {
ThrowHelper.ThrowIfNull(data, "data");
T message = factory(); T message = factory();
message.MergeFrom(data); message.MergeFrom(data);
return message; return message;
......
...@@ -84,7 +84,8 @@ ...@@ -84,7 +84,8 @@
<Compile Include="Descriptors\MethodDescriptor.cs" /> <Compile Include="Descriptors\MethodDescriptor.cs" />
<Compile Include="Descriptors\PackageDescriptor.cs" /> <Compile Include="Descriptors\PackageDescriptor.cs" />
<Compile Include="Descriptors\ServiceDescriptor.cs" /> <Compile Include="Descriptors\ServiceDescriptor.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="FrameworkPortability.cs" />
<Compile Include="MessageExtensions.cs" />
<Compile Include="FieldAccess\FieldAccessorBase.cs" /> <Compile Include="FieldAccess\FieldAccessorBase.cs" />
<Compile Include="FieldAccess\ReflectionUtil.cs" /> <Compile Include="FieldAccess\ReflectionUtil.cs" />
<Compile Include="FieldAccess\RepeatedFieldAccessor.cs" /> <Compile Include="FieldAccess\RepeatedFieldAccessor.cs" />
...@@ -92,7 +93,6 @@ ...@@ -92,7 +93,6 @@
<Compile Include="FieldAccess\IFieldAccessor.cs" /> <Compile Include="FieldAccess\IFieldAccessor.cs" />
<Compile Include="FieldAccess\FieldAccessorTable.cs" /> <Compile Include="FieldAccess\FieldAccessorTable.cs" />
<Compile Include="FieldAccess\OneofAccessor.cs" /> <Compile Include="FieldAccess\OneofAccessor.cs" />
<Compile Include="FrameworkPortability.cs" />
<Compile Include="IMessage.cs" /> <Compile Include="IMessage.cs" />
<Compile Include="InvalidProtocolBufferException.cs" /> <Compile Include="InvalidProtocolBufferException.cs" />
<Compile Include="LimitedInputStream.cs" /> <Compile Include="LimitedInputStream.cs" />
......
...@@ -42,12 +42,12 @@ namespace Google.Protobuf ...@@ -42,12 +42,12 @@ namespace Google.Protobuf
/// <summary> /// <summary>
/// Helper methods for throwing exceptions /// Helper methods for throwing exceptions
/// </summary> /// </summary>
public static class ThrowHelper internal static class ThrowHelper
{ {
/// <summary> /// <summary>
/// Throws an ArgumentNullException if the given value is null. /// Throws an ArgumentNullException if the given value is null.
/// </summary> /// </summary>
public static void ThrowIfNull(object value, string name) internal static void ThrowIfNull(object value, string name)
{ {
if (value == null) if (value == null)
{ {
...@@ -58,7 +58,7 @@ namespace Google.Protobuf ...@@ -58,7 +58,7 @@ namespace Google.Protobuf
/// <summary> /// <summary>
/// Throws an ArgumentNullException if the given value is null. /// Throws an ArgumentNullException if the given value is null.
/// </summary> /// </summary>
public static void ThrowIfNull(object value) internal static void ThrowIfNull(object value)
{ {
if (value == null) if (value == null)
{ {
...@@ -69,7 +69,7 @@ namespace Google.Protobuf ...@@ -69,7 +69,7 @@ namespace Google.Protobuf
/// <summary> /// <summary>
/// Throws an ArgumentNullException if the given value or any element within it is null. /// Throws an ArgumentNullException if the given value or any element within it is null.
/// </summary> /// </summary>
public static void ThrowIfAnyNull<T>(IEnumerable<T> sequence) internal static void ThrowIfAnyNull<T>(IEnumerable<T> sequence)
{ {
foreach (T t in sequence) foreach (T t in sequence)
{ {
...@@ -79,14 +79,5 @@ namespace Google.Protobuf ...@@ -79,14 +79,5 @@ namespace Google.Protobuf
} }
} }
} }
public static Exception CreateMissingMethod(Type type, string methodName)
{
#if CLIENTPROFILE
return new System.MissingMethodException(type.FullName, methodName);
#else
return new System.ArgumentException(String.Format("The method '{0}' was not found on type {1}.", methodName, type));
#endif
}
} }
} }
\ No newline at end of file
...@@ -76,7 +76,7 @@ void RepeatedEnumFieldGenerator::GenerateMergingCode(io::Printer* printer) { ...@@ -76,7 +76,7 @@ void RepeatedEnumFieldGenerator::GenerateMergingCode(io::Printer* printer) {
void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer) { void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print( printer->Print(
variables_, variables_,
"input.ReadEnumArray<$type_name$>(tag, $name$_);\n"); "input.ReadEnumArray<$type_name$>($name$_);\n");
} }
void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) { void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
......
...@@ -75,7 +75,7 @@ void RepeatedMessageFieldGenerator::GenerateMergingCode(io::Printer* printer) { ...@@ -75,7 +75,7 @@ void RepeatedMessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer) { void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print( printer->Print(
variables_, variables_,
"input.ReadMessageArray(tag, $name$_, $type_name$.Parser);\n"); "input.ReadMessageArray($name$_, $type_name$.Parser);\n");
} }
void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) { void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
......
...@@ -75,7 +75,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) ...@@ -75,7 +75,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer)
void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) { void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(variables_, printer->Print(variables_,
"input.Read$capitalized_type_name$Array(tag, $name$_);\n"); "input.Read$capitalized_type_name$Array($name$_);\n");
} }
void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode( void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment