diff options
Diffstat (limited to 'csharp/ProtocolBuffers')
8 files changed, 193 insertions, 20 deletions
diff --git a/csharp/ProtocolBuffers/Delegates.cs b/csharp/ProtocolBuffers/Delegates.cs new file mode 100644 index 00000000..2aa440b1 --- /dev/null +++ b/csharp/ProtocolBuffers/Delegates.cs @@ -0,0 +1,8 @@ +using System.IO; +namespace Google.ProtocolBuffers { + + /// <summary> + /// Delegate to return a stream when asked, used by MessageStreamIterator. + /// </summary> + public delegate Stream StreamProvider(); +} diff --git a/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs b/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs index c103cb19..e42c36f3 100644 --- a/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs +++ b/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs @@ -363,7 +363,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorSet.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorSet result = new global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorSet(); @@ -726,7 +726,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto(); @@ -1326,7 +1326,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto.Types.ExtensionRange.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto.Types.ExtensionRange result = new global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto.Types.ExtensionRange(); @@ -1646,7 +1646,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto(); @@ -2337,7 +2337,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.FieldDescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.FieldDescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.FieldDescriptorProto(); @@ -2791,7 +2791,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.EnumDescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.EnumDescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.EnumDescriptorProto(); @@ -3136,7 +3136,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.EnumValueDescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.EnumValueDescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.EnumValueDescriptorProto(); @@ -3450,7 +3450,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.ServiceDescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.ServiceDescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.ServiceDescriptorProto(); @@ -3811,7 +3811,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.MethodDescriptorProto.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.MethodDescriptorProto result = new global::Google.ProtocolBuffers.DescriptorProtos.MethodDescriptorProto(); @@ -4254,7 +4254,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.FileOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.FileOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.FileOptions(); @@ -4674,7 +4674,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.MessageOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.MessageOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.MessageOptions(); @@ -4906,7 +4906,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions(); @@ -5128,7 +5128,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions(); @@ -5293,7 +5293,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.EnumValueOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.EnumValueOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.EnumValueOptions(); @@ -5458,7 +5458,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.ServiceOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.ServiceOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.ServiceOptions(); @@ -5623,7 +5623,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } // Construct using global::Google.ProtocolBuffers.DescriptorProtos.MethodOptions.CreateBuilder() - internal Builder() {} + public Builder() {} global::Google.ProtocolBuffers.DescriptorProtos.MethodOptions result = new global::Google.ProtocolBuffers.DescriptorProtos.MethodOptions(); diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs index fe801182..35d7b1a8 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs @@ -36,7 +36,7 @@ namespace Google.ProtocolBuffers.FieldAccess { private readonly Func<IBuilder> createBuilderDelegate; internal RepeatedMessageAccessor(string name) : base(name) { - MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); + MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", Type.EmptyTypes); if (createBuilderMethod == null) { throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name); } diff --git a/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs index 931848b5..5aa9f777 100644 --- a/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs @@ -31,8 +31,8 @@ namespace Google.ProtocolBuffers.FieldAccess { /// </summary> private readonly Func<IBuilder> createBuilderDelegate; - internal SingleMessageAccessor(string name) : base(name) { - MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); + internal SingleMessageAccessor(string name) : base(name) { + MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", Type.EmptyTypes); if (createBuilderMethod == null) { throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name); } diff --git a/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs b/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs index 10257542..4f1b1a92 100644 --- a/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs +++ b/csharp/ProtocolBuffers/InvalidProtocolBufferException.cs @@ -71,5 +71,10 @@ namespace Google.ProtocolBuffers { "Protocol message was too large. May be malicious. " + "Use CodedInputStream.SetSizeLimit() to increase the size limit."); } + + internal static InvalidProtocolBufferException InvalidMessageStreamTag() { + return new InvalidProtocolBufferException( + "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1."); + } } } diff --git a/csharp/ProtocolBuffers/MessageStreamIterator.cs b/csharp/ProtocolBuffers/MessageStreamIterator.cs new file mode 100644 index 00000000..4944e5ce --- /dev/null +++ b/csharp/ProtocolBuffers/MessageStreamIterator.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; +using System.IO; +using System.Reflection; + +namespace Google.ProtocolBuffers { + + /// <summary> + /// Helper class to create MessageStreamIterators without explicitly specifying + /// the builder type. The concrete builder type is determined by reflection, based + /// on the message type. The reflection step looks for a <c>CreateBuilder</c> method + /// in the message type which is public and static, and uses the return type of that + /// method as the builder type. This will work for all generated messages, whether + /// optimised for size or speed. It won't work for dynamic messages. + /// + /// TODO(jonskeet): This also won't work for non-public protos :( + /// Pass in delegate to create a builder? + /// </summary> + public static class MessageStreamIterator { + + public static IEnumerable<TMessage> FromFile<TMessage>(string file) + where TMessage : IMessage<TMessage> { + return FromStreamProvider<TMessage>(() => File.OpenRead(file)); + } + + public static IEnumerable<TMessage> FromStreamProvider<TMessage>(StreamProvider streamProvider) + where TMessage : IMessage<TMessage> { + MethodInfo createBuilderMethod = typeof(TMessage).GetMethod("CreateBuilder", Type.EmptyTypes); + if (createBuilderMethod == null) { + throw new ArgumentException("Message type " + typeof(TMessage).FullName + " has no CreateBuilder method."); + } + if (createBuilderMethod.ReturnType == typeof(void)) { + throw new ArgumentException("CreateBuilder method in " + typeof(TMessage).FullName + " has void return type"); + } + Type builderType = createBuilderMethod.ReturnType; + if (builderType.GetConstructor(Type.EmptyTypes) == null) { + throw new ArgumentException("Builder type " + builderType.FullName + " has no public parameterless constructor."); + } + Type messageInterface = typeof(IMessage<,>).MakeGenericType(typeof(TMessage), builderType); + Type builderInterface = typeof(IBuilder<,>).MakeGenericType(typeof(TMessage), builderType); + if (Array.IndexOf(typeof (TMessage).GetInterfaces(), messageInterface) == -1) { + throw new ArgumentException("Message type " + typeof(TMessage) + " doesn't implement " + messageInterface.FullName); + } + if (Array.IndexOf(builderType.GetInterfaces(), builderInterface) == -1) { + throw new ArgumentException("Builder type " + typeof(TMessage) + " doesn't implement " + builderInterface.FullName); + } + Type iteratorType = typeof(MessageStreamIterator<,>).MakeGenericType(typeof(TMessage), builderType); + MethodInfo factoryMethod = iteratorType.GetMethod("FromStreamProvider", new Type[] { typeof(StreamProvider) }); + return (IEnumerable<TMessage>) factoryMethod.Invoke(null, new object[] { streamProvider }); + } + } + + /// <summary> + /// Iterates over data created using a <see cref="MessageStreamWriter{T}" />. + /// Unlike MessageStreamWriter, this class is not usually constructed directly with + /// a stream; instead it is provided with a way of opening a stream when iteration + /// is started. The stream is closed when the iteration is completed or the enumerator + /// is disposed. (This occurs naturally when using <c>foreach</c>.) + /// This type is generic in both the message type and the builder type; if only the + /// iteration is required (i.e. just <see cref="IEnumerable{T}" />) then the static + /// generic methods in the nongeneric class are more appropriate. + /// </summary> + public sealed class MessageStreamIterator<TMessage, TBuilder> : IEnumerable<TMessage> + where TMessage : IMessage<TMessage, TBuilder> + where TBuilder : IBuilder<TMessage, TBuilder>, new() { + + private readonly StreamProvider streamProvider; + private readonly ExtensionRegistry extensionRegistry; + private static readonly uint ExpectedTag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + + private MessageStreamIterator(StreamProvider streamProvider, ExtensionRegistry extensionRegistry) { + this.streamProvider = streamProvider; + this.extensionRegistry = extensionRegistry; + } + + /// <summary> + /// Creates an instance which opens the specified file when it begins + /// iterating. No extension registry is used when reading messages. + /// </summary> + public static MessageStreamIterator<TMessage, TBuilder> FromFile(string file) { + return new MessageStreamIterator<TMessage, TBuilder>(() => File.OpenRead(file), ExtensionRegistry.Empty); + } + + /// <summary> + /// Creates an instance which calls the given delegate when it begins + /// iterating. No extension registry is used when reading messages. + /// </summary> + public static MessageStreamIterator<TMessage, TBuilder> FromStreamProvider(StreamProvider streamProvider) { + return new MessageStreamIterator<TMessage, TBuilder>(streamProvider, ExtensionRegistry.Empty); + } + + /// <summary> + /// Creates a new instance which uses the same stream provider as this one, + /// but the specified extension registry. + /// </summary> + public MessageStreamIterator<TMessage, TBuilder> WithExtensionRegistry(ExtensionRegistry newRegistry) { + return new MessageStreamIterator<TMessage, TBuilder>(streamProvider, newRegistry); + } + + public IEnumerator<TMessage> GetEnumerator() { + using (Stream stream = streamProvider()) { + CodedInputStream input = CodedInputStream.CreateInstance(stream); + uint tag; + while ((tag = input.ReadTag()) != 0) { + if (tag != ExpectedTag) { + throw InvalidProtocolBufferException.InvalidMessageStreamTag(); + } + TBuilder builder = new TBuilder(); + input.ReadMessage(builder, extensionRegistry); + yield return builder.Build(); + } + } + } + + /// <summary> + /// Explicit implementation of nongeneric IEnumerable interface. + /// </summary> + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + } +} diff --git a/csharp/ProtocolBuffers/MessageStreamWriter.cs b/csharp/ProtocolBuffers/MessageStreamWriter.cs new file mode 100644 index 00000000..9ff33b05 --- /dev/null +++ b/csharp/ProtocolBuffers/MessageStreamWriter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace Google.ProtocolBuffers { + /// <summary> + /// Writes multiple messages to the same stream. Each message is written + /// as if it were an element of a repeated field 1 in a larger protocol buffer. + /// This class takes no ownership of the stream it is given; it never closes the + /// stream. + /// </summary> + public sealed class MessageStreamWriter<T> where T : IMessage<T> { + + private readonly CodedOutputStream codedOutput; + + /// <summary> + /// Creates an instance which writes to the given stream. + /// </summary> + /// <param name="output">Stream to write messages to.</param> + public MessageStreamWriter(Stream output) { + codedOutput = CodedOutputStream.CreateInstance(output); + } + + public void Write(T message) { + codedOutput.WriteMessage(1, message); + } + + public void Flush() { + codedOutput.Flush(); + } + } +} diff --git a/csharp/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/ProtocolBuffers/ProtocolBuffers.csproj index 88a21226..25f7cdbb 100644 --- a/csharp/ProtocolBuffers/ProtocolBuffers.csproj +++ b/csharp/ProtocolBuffers/ProtocolBuffers.csproj @@ -3,7 +3,7 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.21022</ProductVersion> + <ProductVersion>9.0.30729</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</ProjectGuid> <OutputType>Library</OutputType> @@ -41,6 +41,7 @@ <Compile Include="AbstractBuilder.cs" /> <Compile Include="AbstractMessage.cs" /> <Compile Include="ByteString.cs" /> + <Compile Include="Delegates.cs" /> <Compile Include="CodedInputStream.cs" /> <Compile Include="CodedOutputStream.cs" /> <Compile Include="Collections\Dictionaries.cs" /> @@ -93,6 +94,8 @@ <Compile Include="IRpcChannel.cs" /> <Compile Include="IRpcController.cs" /> <Compile Include="IService.cs" /> + <Compile Include="MessageStreamIterator.cs" /> + <Compile Include="MessageStreamWriter.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="RpcUtil.cs" /> <Compile Include="TextFormat.cs" /> |