diff options
author | Jon Skeet <skeet@pobox.com> | 2008-08-14 20:33:33 +0100 |
---|---|---|
committer | Jon Skeet <skeet@pobox.com> | 2008-08-14 20:33:33 +0100 |
commit | 621bb698e54a7e0d2fdf74ab1f380183461ce7fa (patch) | |
tree | f1750773eee92541401126c66c811a382b0b22a7 /csharp/ProtocolBuffers/ExtensionRegistry.cs | |
parent | a7246897ab87bc52951cc208f3775c7dfc1d6e09 (diff) | |
download | protobuf-621bb698e54a7e0d2fdf74ab1f380183461ce7fa.tar.gz protobuf-621bb698e54a7e0d2fdf74ab1f380183461ce7fa.tar.bz2 protobuf-621bb698e54a7e0d2fdf74ab1f380183461ce7fa.zip |
Some work on AbstractBuilder, and complete implementation of UnknownField and UnknownFieldSet
Diffstat (limited to 'csharp/ProtocolBuffers/ExtensionRegistry.cs')
-rw-r--r-- | csharp/ProtocolBuffers/ExtensionRegistry.cs | 162 |
1 files changed, 161 insertions, 1 deletions
diff --git a/csharp/ProtocolBuffers/ExtensionRegistry.cs b/csharp/ProtocolBuffers/ExtensionRegistry.cs index a8ed661d..6c36aff4 100644 --- a/csharp/ProtocolBuffers/ExtensionRegistry.cs +++ b/csharp/ProtocolBuffers/ExtensionRegistry.cs @@ -13,7 +13,167 @@ // 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.Collections.Generic; +using Google.ProtocolBuffers.Descriptors; +using System; + namespace Google.ProtocolBuffers { - public class ExtensionRegistry { + /// <summary> + /// TODO(jonskeet): Copy docs from Java + /// </summary> + 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<TContainer, TExtension> (GeneratedExtension<TContainer, TExtension> extension) + where TContainer : IMessage<TContainer> { + 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.IsMessageSetWireFormat + && 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; + } + } } } |