diff options
author | csharptest <roger@csharptest.net> | 2010-11-04 14:25:56 -0500 |
---|---|---|
committer | unknown <rknapp@.svault.int> | 2010-11-04 14:25:56 -0500 |
commit | c07571a79b37a4be4551ff0cded0b160d4e8ee6c (patch) | |
tree | f237137ce6ffb0c8da008b9887198dd46bc4098d /src/ProtocolBuffers | |
parent | 57599ef16daeda48381711dae1600cf0c467689d (diff) | |
download | protobuf-c07571a79b37a4be4551ff0cded0b160d4e8ee6c.tar.gz protobuf-c07571a79b37a4be4551ff0cded0b160d4e8ee6c.tar.bz2 protobuf-c07571a79b37a4be4551ff0cded0b160d4e8ee6c.zip |
Added copy of existing classes that will be made Lite
Diffstat (limited to 'src/ProtocolBuffers')
-rw-r--r-- | src/ProtocolBuffers/ExtensionRegistryLite.cs | 245 | ||||
-rw-r--r-- | src/ProtocolBuffers/IBuilderLite.cs | 317 | ||||
-rw-r--r-- | src/ProtocolBuffers/IMessageLite.cs | 236 |
3 files changed, 798 insertions, 0 deletions
diff --git a/src/ProtocolBuffers/ExtensionRegistryLite.cs b/src/ProtocolBuffers/ExtensionRegistryLite.cs new file mode 100644 index 00000000..154b6902 --- /dev/null +++ b/src/ProtocolBuffers/ExtensionRegistryLite.cs @@ -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; + } + } + } +} diff --git a/src/ProtocolBuffers/IBuilderLite.cs b/src/ProtocolBuffers/IBuilderLite.cs new file mode 100644 index 00000000..b1aa4fb1 --- /dev/null +++ b/src/ProtocolBuffers/IBuilderLite.cs @@ -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 + } +} diff --git a/src/ProtocolBuffers/IMessageLite.cs b/src/ProtocolBuffers/IMessageLite.cs new file mode 100644 index 00000000..ec955c6d --- /dev/null +++ b/src/ProtocolBuffers/IMessageLite.cs @@ -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 + } +} |