parent
57599ef16d
commit
c07571a79b
3 changed files with 798 additions and 0 deletions
@ -0,0 +1,245 @@ |
||||
#region Copyright notice and license |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// http://github.com/jskeet/dotnet-protobufs/ |
||||
// Original C++/Java/Python code: |
||||
// http://code.google.com/p/protobuf/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
#endregion |
||||
|
||||
using System.Collections.Generic; |
||||
using Google.ProtocolBuffers.Descriptors; |
||||
using System; |
||||
|
||||
namespace Google.ProtocolBuffers { |
||||
/// <summary> |
||||
/// A table of known extensions, searchable by name or field number. When |
||||
/// parsing a protocol message that might have extensions, you must provide |
||||
/// an <see cref="ExtensionRegistry"/> in which you have registered any extensions |
||||
/// that you want to be able to parse. Otherwise, those extensions will just |
||||
/// be treated like unknown fields. |
||||
/// </summary> |
||||
/// <example> |
||||
/// For example, if you had the <c>.proto</c> file: |
||||
/// <code> |
||||
/// option java_class = "MyProto"; |
||||
/// |
||||
/// message Foo { |
||||
/// extensions 1000 to max; |
||||
/// } |
||||
/// |
||||
/// extend Foo { |
||||
/// optional int32 bar; |
||||
/// } |
||||
/// </code> |
||||
/// |
||||
/// Then you might write code like: |
||||
/// |
||||
/// <code> |
||||
/// ExtensionRegistry registry = ExtensionRegistry.CreateInstance(); |
||||
/// registry.Add(MyProto.Bar); |
||||
/// MyProto.Foo message = MyProto.Foo.ParseFrom(input, registry); |
||||
/// </code> |
||||
/// </example> |
||||
/// |
||||
/// <remarks> |
||||
/// <para>You might wonder why this is necessary. Two alternatives might come to |
||||
/// mind. First, you might imagine a system where generated extensions are |
||||
/// automatically registered when their containing classes are loaded. This |
||||
/// is a popular technique, but is bad design; among other things, it creates a |
||||
/// situation where behavior can change depending on what classes happen to be |
||||
/// loaded. It also introduces a security vulnerability, because an |
||||
/// unprivileged class could cause its code to be called unexpectedly from a |
||||
/// privileged class by registering itself as an extension of the right type. |
||||
/// </para> |
||||
/// <para>Another option you might consider is lazy parsing: do not parse an |
||||
/// extension until it is first requested, at which point the caller must |
||||
/// provide a type to use. This introduces a different set of problems. First, |
||||
/// it would require a mutex lock any time an extension was accessed, which |
||||
/// would be slow. Second, corrupt data would not be detected until first |
||||
/// access, at which point it would be much harder to deal with it. Third, it |
||||
/// could violate the expectation that message objects are immutable, since the |
||||
/// type provided could be any arbitrary message class. An unprivileged user |
||||
/// could take advantage of this to inject a mutable object into a message |
||||
/// belonging to privileged code and create mischief.</para> |
||||
/// </remarks> |
||||
public sealed class ExtensionRegistry { |
||||
|
||||
private static readonly ExtensionRegistry empty = new ExtensionRegistry( |
||||
new Dictionary<string, ExtensionInfo>(), |
||||
new Dictionary<DescriptorIntPair, ExtensionInfo>(), |
||||
true); |
||||
|
||||
private readonly IDictionary<string, ExtensionInfo> extensionsByName; |
||||
private readonly IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber; |
||||
private readonly bool readOnly; |
||||
|
||||
private ExtensionRegistry(IDictionary<String, ExtensionInfo> extensionsByName, |
||||
IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber, |
||||
bool readOnly) { |
||||
this.extensionsByName = extensionsByName; |
||||
this.extensionsByNumber = extensionsByNumber; |
||||
this.readOnly = readOnly; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Construct a new, empty instance. |
||||
/// </summary> |
||||
public static ExtensionRegistry CreateInstance() { |
||||
return new ExtensionRegistry(new Dictionary<string, ExtensionInfo>(), |
||||
new Dictionary<DescriptorIntPair, ExtensionInfo>(), false); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Get the unmodifiable singleton empty instance. |
||||
/// </summary> |
||||
public static ExtensionRegistry Empty { |
||||
get { return empty; } |
||||
} |
||||
|
||||
public ExtensionRegistry AsReadOnly() { |
||||
return new ExtensionRegistry(extensionsByName, extensionsByNumber, true); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Finds an extension by fully-qualified field name, in the |
||||
/// proto namespace, i.e. result.Descriptor.FullName will match |
||||
/// <paramref name="fullName"/> if a match is found. A null |
||||
/// reference is returned if the extension can't be found. |
||||
/// </summary> |
||||
public ExtensionInfo this[string fullName] { |
||||
get { |
||||
ExtensionInfo ret; |
||||
extensionsByName.TryGetValue(fullName, out ret); |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Finds an extension by containing type and field number. |
||||
/// A null reference is returned if the extension can't be found. |
||||
/// </summary> |
||||
public ExtensionInfo this[MessageDescriptor containingType, int fieldNumber] { |
||||
get { |
||||
ExtensionInfo ret; |
||||
extensionsByNumber.TryGetValue(new DescriptorIntPair(containingType, fieldNumber), out ret); |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Add an extension from a generated file to the registry. |
||||
/// </summary> |
||||
public void Add<TExtension> (GeneratedExtensionBase<TExtension> extension) { |
||||
if (extension.Descriptor.MappedType == MappedType.Message) { |
||||
Add(new ExtensionInfo(extension.Descriptor, extension.MessageDefaultInstance)); |
||||
} else { |
||||
Add(new ExtensionInfo(extension.Descriptor, null)); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Adds a non-message-type extension to the registry by descriptor. |
||||
/// </summary> |
||||
/// <param name="type"></param> |
||||
public void Add(FieldDescriptor type) { |
||||
if (type.MappedType == MappedType.Message) { |
||||
throw new ArgumentException("ExtensionRegistry.Add() must be provided a default instance " |
||||
+ "when adding an embedded message extension."); |
||||
} |
||||
Add(new ExtensionInfo(type, null)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Adds a message-type-extension to the registry by descriptor. |
||||
/// </summary> |
||||
/// <param name="type"></param> |
||||
/// <param name="defaultInstance"></param> |
||||
public void Add(FieldDescriptor type, IMessage defaultInstance) { |
||||
if (type.MappedType != MappedType.Message) { |
||||
throw new ArgumentException("ExtensionRegistry.Add() provided a default instance for a " |
||||
+ "non-message extension."); |
||||
} |
||||
Add(new ExtensionInfo(type, defaultInstance)); |
||||
} |
||||
|
||||
private void Add(ExtensionInfo extension) { |
||||
if (readOnly) { |
||||
throw new InvalidOperationException("Cannot add entries to a read-only extension registry"); |
||||
} |
||||
if (!extension.Descriptor.IsExtension) { |
||||
throw new ArgumentException("ExtensionRegistry.add() was given a FieldDescriptor for a " |
||||
+ "regular (non-extension) field."); |
||||
} |
||||
|
||||
extensionsByName[extension.Descriptor.FullName] = extension; |
||||
extensionsByNumber[new DescriptorIntPair(extension.Descriptor.ContainingType, |
||||
extension.Descriptor.FieldNumber)] = extension; |
||||
|
||||
FieldDescriptor field = extension.Descriptor; |
||||
if (field.ContainingType.Options.MessageSetWireFormat |
||||
&& field.FieldType == FieldType.Message |
||||
&& field.IsOptional |
||||
&& field.ExtensionScope == field.MessageType) { |
||||
// This is an extension of a MessageSet type defined within the extension |
||||
// type's own scope. For backwards-compatibility, allow it to be looked |
||||
// up by type name. |
||||
extensionsByName[field.MessageType.FullName] = extension; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Nested type just used to represent a pair of MessageDescriptor and int, as |
||||
/// the key into the "by number" map. |
||||
/// </summary> |
||||
private struct DescriptorIntPair : IEquatable<DescriptorIntPair> { |
||||
readonly MessageDescriptor descriptor; |
||||
readonly int number; |
||||
|
||||
internal DescriptorIntPair(MessageDescriptor descriptor, int number) { |
||||
this.descriptor = descriptor; |
||||
this.number = number; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
return descriptor.GetHashCode() * ((1 << 16) - 1) + number; |
||||
} |
||||
|
||||
public override bool Equals(object obj) { |
||||
if (!(obj is DescriptorIntPair)) { |
||||
return false; |
||||
} |
||||
return Equals((DescriptorIntPair)obj); |
||||
} |
||||
|
||||
public bool Equals(DescriptorIntPair other) { |
||||
return descriptor == other.descriptor && number == other.number; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,317 @@ |
||||
#region Copyright notice and license |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// http://github.com/jskeet/dotnet-protobufs/ |
||||
// Original C++/Java/Python code: |
||||
// http://code.google.com/p/protobuf/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using Google.ProtocolBuffers.Descriptors; |
||||
|
||||
namespace Google.ProtocolBuffers { |
||||
|
||||
/// <summary> |
||||
/// Non-generic interface for all members whose signatures don't require knowledge of |
||||
/// the type being built. The generic interface extends this one. Some methods return |
||||
/// either an IBuilder or an IMessage; in these cases the generic interface redeclares |
||||
/// the same method with a type-specific signature. Implementations are encouraged to |
||||
/// use explicit interface implemenation for the non-generic form. This mirrors |
||||
/// how IEnumerable and IEnumerable<T> work. |
||||
/// </summary> |
||||
public interface IBuilder { |
||||
/// <summary> |
||||
/// Returns true iff all required fields in the message and all |
||||
/// embedded messages are set. |
||||
/// </summary> |
||||
bool IsInitialized { get; } |
||||
|
||||
/// <summary> |
||||
/// Only present in the nongeneric interface - useful for tests, but |
||||
/// not as much in real life. |
||||
/// </summary> |
||||
IBuilder SetField(FieldDescriptor field, object value); |
||||
|
||||
/// <summary> |
||||
/// Only present in the nongeneric interface - useful for tests, but |
||||
/// not as much in real life. |
||||
/// </summary> |
||||
IBuilder SetRepeatedField(FieldDescriptor field, int index, object value); |
||||
|
||||
/// <summary> |
||||
/// Behaves like the equivalent property in IMessage<T>. |
||||
/// The returned map may or may not reflect future changes to the builder. |
||||
/// Either way, the returned map is unmodifiable. |
||||
/// </summary> |
||||
IDictionary<FieldDescriptor, object> AllFields { get; } |
||||
|
||||
/// <summary> |
||||
/// Allows getting and setting of a field. |
||||
/// <see cref="IMessage{TMessage, TBuilder}.Item(FieldDescriptor)"/> |
||||
/// </summary> |
||||
/// <param name="field"></param> |
||||
/// <returns></returns> |
||||
object this[FieldDescriptor field] { get; set; } |
||||
|
||||
/// <summary> |
||||
/// Get the message's type descriptor. |
||||
/// <see cref="IMessage{TMessage, TBuilder}.DescriptorForType"/> |
||||
/// </summary> |
||||
MessageDescriptor DescriptorForType { get; } |
||||
|
||||
/// <summary> |
||||
/// <see cref="IMessage{TMessage, TBuilder}.GetRepeatedFieldCount"/> |
||||
/// </summary> |
||||
/// <param name="field"></param> |
||||
/// <returns></returns> |
||||
int GetRepeatedFieldCount(FieldDescriptor field); |
||||
|
||||
/// <summary> |
||||
/// Allows getting and setting of a repeated field value. |
||||
/// <see cref="IMessage{TMessage, TBuilder}.Item(FieldDescriptor, int)"/> |
||||
/// </summary> |
||||
object this[FieldDescriptor field, int index] { get; set; } |
||||
|
||||
/// <summary> |
||||
/// <see cref="IMessage{TMessage, TBuilder}.HasField"/> |
||||
/// </summary> |
||||
bool HasField(FieldDescriptor field); |
||||
|
||||
/// <summary> |
||||
/// <see cref="IMessage{TMessage, TBuilder}.UnknownFields"/> |
||||
/// </summary> |
||||
UnknownFieldSet UnknownFields { get; set; } |
||||
|
||||
/// <summary> |
||||
/// Create a builder for messages of the appropriate type for the given field. |
||||
/// Messages built with this can then be passed to the various mutation properties |
||||
/// and methods. |
||||
/// </summary> |
||||
IBuilder CreateBuilderForField(FieldDescriptor field); |
||||
|
||||
#region Methods which are like those of the generic form, but without any knowledge of the type parameters |
||||
IBuilder WeakAddRepeatedField(FieldDescriptor field, object value); |
||||
IBuilder WeakClear(); |
||||
IBuilder WeakClearField(FieldDescriptor field); |
||||
IBuilder WeakMergeFrom(IMessage message); |
||||
IBuilder WeakMergeFrom(ByteString data); |
||||
IBuilder WeakMergeFrom(ByteString data, ExtensionRegistry registry); |
||||
IBuilder WeakMergeFrom(CodedInputStream input); |
||||
IBuilder WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry); |
||||
IMessage WeakBuild(); |
||||
IMessage WeakBuildPartial(); |
||||
IBuilder WeakClone(); |
||||
IMessage WeakDefaultInstanceForType { get; } |
||||
#endregion |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Interface implemented by Protocol Message builders. |
||||
/// TODO(jonskeet): Consider "SetXXX" methods returning the builder, as well as the properties. |
||||
/// </summary> |
||||
/// <typeparam name="TMessage">Type of message</typeparam> |
||||
/// <typeparam name="TBuilder">Type of builder</typeparam> |
||||
public interface IBuilder<TMessage, TBuilder> : IBuilder |
||||
where TMessage : IMessage<TMessage, TBuilder> |
||||
where TBuilder : IBuilder<TMessage, TBuilder> { |
||||
|
||||
TBuilder SetUnknownFields(UnknownFieldSet unknownFields); |
||||
|
||||
/// <summary> |
||||
/// Resets all fields to their default values. |
||||
/// </summary> |
||||
TBuilder Clear(); |
||||
|
||||
/// <summary> |
||||
/// Merge the specified other message into the message being |
||||
/// built. Merging occurs as follows. For each field: |
||||
/// For singular primitive fields, if the field is set in <paramref name="other"/>, |
||||
/// then <paramref name="other"/>'s value overwrites the value in this message. |
||||
/// For singular message fields, if the field is set in <paramref name="other"/>, |
||||
/// it is merged into the corresponding sub-message of this message using the same |
||||
/// merging rules. |
||||
/// For repeated fields, the elements in <paramref name="other"/> are concatenated |
||||
/// with the elements in this message. |
||||
/// </summary> |
||||
/// <param name="other"></param> |
||||
/// <returns></returns> |
||||
TBuilder MergeFrom(TMessage other); |
||||
|
||||
/// <summary> |
||||
/// Merge the specified other message which may be a different implementation of |
||||
/// the same message descriptor. |
||||
/// </summary> |
||||
TBuilder MergeFrom(IMessage other); |
||||
|
||||
/// <summary> |
||||
/// Constructs the final message. Once this is called, this Builder instance |
||||
/// is no longer valid, and calling any other method may throw a |
||||
/// NullReferenceException. If you need to continue working with the builder |
||||
/// after calling Build, call Clone first. |
||||
/// </summary> |
||||
/// <exception cref="UninitializedMessageException">the message |
||||
/// is missing one or more required fields; use BuildPartial to bypass |
||||
/// this check</exception> |
||||
TMessage Build(); |
||||
|
||||
/// <summary> |
||||
/// Like Build(), but does not throw an exception if the message is missing |
||||
/// required fields. Instead, a partial message is returned. |
||||
/// </summary> |
||||
TMessage BuildPartial(); |
||||
|
||||
/// <summary> |
||||
/// Clones this builder. |
||||
/// TODO(jonskeet): Explain depth of clone. |
||||
/// </summary> |
||||
TBuilder Clone(); |
||||
|
||||
/// <summary> |
||||
/// Parses a message of this type from the input and merges it with this |
||||
/// message, as if using MergeFrom(IMessage<T>). |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// Warning: This does not verify that all required fields are present |
||||
/// in the input message. If you call Build() without setting all |
||||
/// required fields, it will throw an UninitializedMessageException. |
||||
/// There are a few good ways to deal with this: |
||||
/// <list> |
||||
/// <item>Call IsInitialized to verify to verify that all required fields are |
||||
/// set before building.</item> |
||||
/// <item>Parse the message separately using one of the static ParseFrom |
||||
/// methods, then use MergeFrom(IMessage<T>) to merge it with |
||||
/// this one. ParseFrom will throw an InvalidProtocolBufferException |
||||
/// (an IOException) if some required fields are missing. |
||||
/// Use BuildPartial to build, which ignores missing required fields. |
||||
/// </list> |
||||
/// </remarks> |
||||
TBuilder MergeFrom(CodedInputStream input); |
||||
|
||||
/// <summary> |
||||
/// Like MergeFrom(CodedInputStream), but also parses extensions. |
||||
/// The extensions that you want to be able to parse must be registered |
||||
/// in <paramref name="extensionRegistry"/>. Extensions not in the registry |
||||
/// will be treated as unknown fields. |
||||
/// </summary> |
||||
TBuilder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry); |
||||
|
||||
/// <summary> |
||||
/// Get's the message's type's default instance. |
||||
/// <see cref="IMessage{TMessage}.DefaultInstanceForType" /> |
||||
/// </summary> |
||||
TMessage DefaultInstanceForType { get; } |
||||
|
||||
/// <summary> |
||||
/// Clears the field. This is exactly equivalent to calling the generated |
||||
/// Clear method corresponding to the field. |
||||
/// </summary> |
||||
/// <param name="field"></param> |
||||
/// <returns></returns> |
||||
TBuilder ClearField(FieldDescriptor field); |
||||
|
||||
/// <summary> |
||||
/// Appends the given value as a new element for the specified repeated field. |
||||
/// </summary> |
||||
/// <exception cref="ArgumentException">the field is not a repeated field, |
||||
/// the field does not belong to this builder's type, or the value is |
||||
/// of the incorrect type |
||||
/// </exception> |
||||
TBuilder AddRepeatedField(FieldDescriptor field, object value); |
||||
|
||||
/// <summary> |
||||
/// Merge some unknown fields into the set for this message. |
||||
/// </summary> |
||||
TBuilder MergeUnknownFields(UnknownFieldSet unknownFields); |
||||
|
||||
/// <summary> |
||||
/// Like MergeFrom(Stream), but does not read until the end of the file. |
||||
/// Instead, the size of the message (encoded as a varint) is read first, |
||||
/// then the message data. Use Message.WriteDelimitedTo(Stream) to |
||||
/// write messages in this format. |
||||
/// </summary> |
||||
/// <param name="input"></param> |
||||
TBuilder MergeDelimitedFrom(Stream input); |
||||
|
||||
/// <summary> |
||||
/// Like MergeDelimitedFrom(Stream) but supporting extensions. |
||||
/// </summary> |
||||
TBuilder MergeDelimitedFrom(Stream input, ExtensionRegistry extensionRegistry); |
||||
|
||||
#region Convenience methods |
||||
/// <summary> |
||||
/// Parse <paramref name="data"/> as a message of this type and merge |
||||
/// it with the message being built. This is just a small wrapper around |
||||
/// MergeFrom(CodedInputStream). |
||||
/// </summary> |
||||
TBuilder MergeFrom(ByteString data); |
||||
|
||||
/// <summary> |
||||
/// Parse <paramref name="data"/> as a message of this type and merge |
||||
/// it with the message being built. This is just a small wrapper around |
||||
/// MergeFrom(CodedInputStream, ExtensionRegistry). |
||||
/// </summary> |
||||
TBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry); |
||||
|
||||
/// <summary> |
||||
/// Parse <paramref name="data"/> as a message of this type and merge |
||||
/// it with the message being built. This is just a small wrapper around |
||||
/// MergeFrom(CodedInputStream). |
||||
/// </summary> |
||||
TBuilder MergeFrom(byte[] data); |
||||
|
||||
/// <summary> |
||||
/// Parse <paramref name="data"/> as a message of this type and merge |
||||
/// it with the message being built. This is just a small wrapper around |
||||
/// MergeFrom(CodedInputStream, ExtensionRegistry). |
||||
/// </summary> |
||||
TBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry); |
||||
|
||||
/// <summary> |
||||
/// Parse <paramref name="input"/> as a message of this type and merge |
||||
/// it with the message being built. This is just a small wrapper around |
||||
/// MergeFrom(CodedInputStream). Note that this method always reads |
||||
/// the entire input (unless it throws an exception). If you want it to |
||||
/// stop earlier, you will need to wrap the input in a wrapper |
||||
/// stream which limits reading. Or, use IMessage.WriteDelimitedTo(Stream) |
||||
/// to write your message and MmergeDelimitedFrom(Stream) to read it. |
||||
/// Despite usually reading the entire stream, this method never closes the stream. |
||||
/// </summary> |
||||
TBuilder MergeFrom(Stream input); |
||||
|
||||
/// <summary> |
||||
/// Parse <paramref name="input"/> as a message of this type and merge |
||||
/// it with the message being built. This is just a small wrapper around |
||||
/// MergeFrom(CodedInputStream, ExtensionRegistry). |
||||
/// </summary> |
||||
TBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry); |
||||
#endregion |
||||
} |
||||
} |
@ -0,0 +1,236 @@ |
||||
#region Copyright notice and license |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// http://github.com/jskeet/dotnet-protobufs/ |
||||
// Original C++/Java/Python code: |
||||
// http://code.google.com/p/protobuf/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using Google.ProtocolBuffers.Descriptors; |
||||
|
||||
namespace Google.ProtocolBuffers { |
||||
|
||||
/// <summary> |
||||
/// Non-generic interface used for all parts of the API which don't require |
||||
/// any type knowledge. |
||||
/// </summary> |
||||
public interface IMessage { |
||||
/// <summary> |
||||
/// Returns the message's type's descriptor. This differs from the |
||||
/// Descriptor property of each generated message class in that this |
||||
/// method is an abstract method of IMessage whereas Descriptor is |
||||
/// a static property of a specific class. They return the same thing. |
||||
/// </summary> |
||||
MessageDescriptor DescriptorForType { get; } |
||||
/// <summary> |
||||
/// Returns a collection of all the fields in this message which are set |
||||
/// and their corresponding values. A singular ("required" or "optional") |
||||
/// field is set iff HasField() returns true for that field. A "repeated" |
||||
/// field is set iff GetRepeatedFieldSize() is greater than zero. The |
||||
/// values are exactly what would be returned by calling |
||||
/// GetField(FieldDescriptor) for each field. The map |
||||
/// is guaranteed to be a sorted map, so iterating over it will return fields |
||||
/// in order by field number. |
||||
/// </summary> |
||||
IDictionary<FieldDescriptor, object> AllFields { get; } |
||||
|
||||
/// <summary> |
||||
/// Returns true if the given field is set. This is exactly equivalent |
||||
/// to calling the generated "Has" property corresponding to the field. |
||||
/// </summary> |
||||
/// <exception cref="ArgumentException">the field is a repeated field, |
||||
/// or it's not a field of this type</exception> |
||||
bool HasField(FieldDescriptor field); |
||||
|
||||
/// <summary> |
||||
/// Obtains the value of the given field, or the default value if |
||||
/// it isn't set. For value type fields, the boxed value is returned. |
||||
/// For enum fields, the EnumValueDescriptor for the enum is returned. |
||||
/// For embedded message fields, the sub-message |
||||
/// is returned. For repeated fields, an IList<T> is returned. |
||||
/// </summary> |
||||
object this[FieldDescriptor field] { get; } |
||||
|
||||
/// <summary> |
||||
/// Returns the number of elements of a repeated field. This is |
||||
/// exactly equivalent to calling the generated "Count" property |
||||
/// corresponding to the field. |
||||
/// </summary> |
||||
/// <exception cref="ArgumentException">the field is not a repeated field, |
||||
/// or it's not a field of this type</exception> |
||||
int GetRepeatedFieldCount(FieldDescriptor field); |
||||
|
||||
/// <summary> |
||||
/// Gets an element of a repeated field. For value type fields |
||||
/// excluding enums, the boxed value is returned. For embedded |
||||
/// message fields, the sub-message is returned. For enums, the |
||||
/// relevant EnumValueDescriptor is returned. |
||||
/// </summary> |
||||
/// <exception cref="ArgumentException">the field is not a repeated field, |
||||
/// or it's not a field of this type</exception> |
||||
/// <exception cref="ArgumentOutOfRangeException">the index is out of |
||||
/// range for the repeated field's value</exception> |
||||
object this[FieldDescriptor field, int index] { get; } |
||||
|
||||
/// <summary> |
||||
/// Returns the unknown fields for this message. |
||||
/// </summary> |
||||
UnknownFieldSet UnknownFields { get; } |
||||
|
||||
/// <summary> |
||||
/// Returns true iff all required fields in the message and all embedded |
||||
/// messages are set. |
||||
/// </summary> |
||||
bool IsInitialized { get; } |
||||
|
||||
/// <summary> |
||||
/// Serializes the message and writes it to the given output stream. |
||||
/// This does not flush or close the stream. |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// Protocol Buffers are not self-delimiting. Therefore, if you write |
||||
/// any more data to the stream after the message, you must somehow ensure |
||||
/// that the parser on the receiving end does not interpret this as being |
||||
/// part of the protocol message. One way of doing this is by writing the size |
||||
/// of the message before the data, then making sure you limit the input to |
||||
/// that size when receiving the data. Alternatively, use WriteDelimitedTo(Stream). |
||||
/// </remarks> |
||||
void WriteTo(CodedOutputStream output); |
||||
|
||||
/// <summary> |
||||
/// Like WriteTo(Stream) but writes the size of the message as a varint before |
||||
/// writing the data. This allows more data to be written to the stream after the |
||||
/// message without the need to delimit the message data yourself. Use |
||||
/// IBuilder.MergeDelimitedFrom(Stream) or the static method |
||||
/// YourMessageType.ParseDelimitedFrom(Stream) to parse messages written by this method. |
||||
/// </summary> |
||||
/// <param name="output"></param> |
||||
void WriteDelimitedTo(Stream output); |
||||
|
||||
/// <summary> |
||||
/// Returns the number of bytes required to encode this message. |
||||
/// The result is only computed on the first call and memoized after that. |
||||
/// </summary> |
||||
int SerializedSize { get; } |
||||
|
||||
#region Comparison and hashing |
||||
/// <summary> |
||||
/// Compares the specified object with this message for equality. |
||||
/// Returns true iff the given object is a message of the same type |
||||
/// (as defined by DescriptorForType) and has identical values |
||||
/// for all its fields. |
||||
/// </summary> |
||||
bool Equals(object other); |
||||
|
||||
/// <summary> |
||||
/// Returns the hash code value for this message. |
||||
/// TODO(jonskeet): Specify the hash algorithm, but better than the Java one! |
||||
/// </summary> |
||||
int GetHashCode(); |
||||
#endregion |
||||
|
||||
#region Convenience methods |
||||
/// <summary> |
||||
/// Converts the message to a string in protocol buffer text format. |
||||
/// This is just a trivial wrapper around TextFormat.PrintToString. |
||||
/// </summary> |
||||
string ToString(); |
||||
|
||||
/// <summary> |
||||
/// Serializes the message to a ByteString. This is a trivial wrapper |
||||
/// around WriteTo(CodedOutputStream). |
||||
/// </summary> |
||||
ByteString ToByteString(); |
||||
|
||||
/// <summary> |
||||
/// Serializes the message to a byte array. This is a trivial wrapper |
||||
/// around WriteTo(CodedOutputStream). |
||||
/// </summary> |
||||
byte[] ToByteArray(); |
||||
|
||||
/// <summary> |
||||
/// Serializes the message and writes it to the given stream. |
||||
/// This is just a wrapper around WriteTo(CodedOutputStream). This |
||||
/// does not flush or close the stream. |
||||
/// </summary> |
||||
/// <param name="output"></param> |
||||
void WriteTo(Stream output); |
||||
#endregion |
||||
|
||||
/// <summary> |
||||
/// Creates a builder for the type, but in a weakly typed manner. This |
||||
/// is typically implemented by strongly typed messages by just returning |
||||
/// the result of CreateBuilderForType. |
||||
/// </summary> |
||||
IBuilder WeakCreateBuilderForType(); |
||||
|
||||
/// <summary> |
||||
/// Creates a builder with the same contents as this message. This |
||||
/// is typically implemented by strongly typed messages by just returning |
||||
/// the result of ToBuilder. |
||||
/// </summary> |
||||
IBuilder WeakToBuilder(); |
||||
|
||||
IMessage WeakDefaultInstanceForType { get; } |
||||
} |
||||
|
||||
public interface IMessage<TMessage> : IMessage { |
||||
/// <summary> |
||||
/// Returns an instance of this message type with all fields set to |
||||
/// their default values. This may or may not be a singleton. This differs |
||||
/// from the DefaultInstance property of each generated message class in that this |
||||
/// method is an abstract method of IMessage whereas DefaultInstance is |
||||
/// a static property of a specific class. They return the same thing. |
||||
/// </summary> |
||||
TMessage DefaultInstanceForType { get; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Type-safe interface for all generated messages to implement. |
||||
/// </summary> |
||||
public interface IMessage<TMessage, TBuilder> : IMessage<TMessage> |
||||
where TMessage : IMessage<TMessage, TBuilder> |
||||
where TBuilder : IBuilder<TMessage, TBuilder> { |
||||
#region Builders |
||||
/// <summary> |
||||
/// Constructs a new builder for a message of the same type as this message. |
||||
/// </summary> |
||||
TBuilder CreateBuilderForType(); |
||||
/// <summary> |
||||
/// Creates a builder with the same contents as this current instance. |
||||
/// This is typically implemented by strongly typed messages by just |
||||
/// returning the result of ToBuilder(). |
||||
/// </summary> |
||||
TBuilder ToBuilder(); |
||||
#endregion |
||||
} |
||||
} |
Loading…
Reference in new issue