// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. // http://code.google.com/p/protobuf/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.IO; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers { /// /// 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. /// public interface IBuilder { /// /// Returns true iff all required fields in the message and all /// embedded messages are set. /// bool IsInitialized { get; } /// /// Only present in the nongeneric interface - useful for tests, but /// not as much in real life. /// IBuilder SetField(FieldDescriptor field, object value); /// /// Only present in the nongeneric interface - useful for tests, but /// not as much in real life. /// IBuilder SetRepeatedField(FieldDescriptor field, int index, object value); /// /// 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. /// IDictionary AllFields { get; } /// /// Allows getting and setting of a field. /// /// /// /// object this[FieldDescriptor field] { get; set; } /// /// Get the message's type's descriptor. /// /// MessageDescriptor DescriptorForType { get; } /// /// /// /// /// int GetRepeatedFieldCount(FieldDescriptor field); /// /// Allows getting and setting of a repeated field value. /// /// object this[FieldDescriptor field, int index] { get; set; } /// /// /// bool HasField(FieldDescriptor field); /// /// /// UnknownFieldSet UnknownFields { get; set; } /// /// 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. /// 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 } /// /// Interface implemented by Protocol Message builders. /// TODO(jonskeet): Consider "SetXXX" methods returning the builder, as well as the properties. /// /// Type of message /// Type of builder public interface IBuilder : IBuilder where TMessage : IMessage where TBuilder : IBuilder { TBuilder SetUnknownFields(UnknownFieldSet unknownFields); /// /// Resets all fields to their default values. /// TBuilder Clear(); /// /// 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 , /// then 's value overwrites the value in this message. /// For singular message fields, if the field is set in , /// it is merged into the corresponding sub-message of this message using the same /// merging rules. /// For repeated fields, the elements in are concatenated /// with the elements in this message. /// /// /// TBuilder MergeFrom(TMessage other); /// /// Merge the specified other message which may be a different implementation of /// the same message descriptor. /// TBuilder MergeFrom(IMessage other); /// /// 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. /// /// the message /// is missing one or more required fields; use BuildPartial to bypass /// this check TMessage Build(); /// /// Like Build(), but does not throw an exception if the message is missing /// required fields. Instead, a partial message is returned. /// TMessage BuildPartial(); /// /// Clones this builder. /// TODO(jonskeet): Explain depth of clone. /// TBuilder Clone(); /// /// Parses a message of this type from the input and merges it with this /// message, as if using MergeFrom(IMessage<T>). /// /// /// 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: /// /// Call IsInitialized to verify to verify that all required fields are /// set before building. /// 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. /// /// TBuilder MergeFrom(CodedInputStream input); /// /// Like MergeFrom(CodedInputStream), but also parses extensions. /// The extensions that you want to be able to parse must be registered /// in . Extensions not in the registry /// will be treated as unknown fields. /// TBuilder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry); /// /// Get's the message's type's default instance. /// /// TMessage DefaultInstanceForType { get; } /// /// Clears the field. This is exactly equivalent to calling the generated /// Clear method corresponding to the field. /// /// /// TBuilder ClearField(FieldDescriptor field); /// /// Appends the given value as a new element for the specified repeated field. /// /// 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 /// TBuilder AddRepeatedField(FieldDescriptor field, object value); /// /// Merge some unknown fields into the set for this message. /// TBuilder MergeUnknownFields(UnknownFieldSet unknownFields); #region Convenience methods // TODO(jonskeet): Implement these as extension methods? /// /// Parse as a message of this type and merge /// it with the message being built. This is just a small wrapper around /// MergeFrom(CodedInputStream). /// TBuilder MergeFrom(ByteString data); /// /// Parse as a message of this type and merge /// it with the message being built. This is just a small wrapper around /// MergeFrom(CodedInputStream, ExtensionRegistry). /// TBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry); /// /// Parse as a message of this type and merge /// it with the message being built. This is just a small wrapper around /// MergeFrom(CodedInputStream). /// TBuilder MergeFrom(byte[] data); /// /// Parse as a message of this type and merge /// it with the message being built. This is just a small wrapper around /// MergeFrom(CodedInputStream, ExtensionRegistry). /// TBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry); /// /// Parse 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. Despite usually reading the entire /// stream, this method never closes the stream. /// TBuilder MergeFrom(Stream input); /// /// Parse as a message of this type and merge /// it with the message being built. This is just a small wrapper around /// MergeFrom(CodedInputStream, ExtensionRegistry). /// TBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry); #endregion } }