ExtensionRegistry.cs 6.98 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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;
using System.Collections.Generic;
using System.Linq;

namespace Google.Protobuf
{
    /// <summary>
41
    /// Provides extensions to messages while parsing. This API is experimental and subject to change.
42 43 44
    /// </summary>
    public sealed class ExtensionRegistry : ICollection<Extension>, IDeepCloneable<ExtensionRegistry>
    {
45 46 47 48 49 50 51 52 53 54 55 56 57
        internal sealed class ExtensionComparer : IEqualityComparer<Extension>
        {
            public bool Equals(Extension a, Extension b)
            {
                return new ObjectIntPair<Type>(a.TargetType, a.FieldNumber).Equals(new ObjectIntPair<Type>(b.TargetType, b.FieldNumber));
            }
            public int GetHashCode(Extension a)
            {
                return new ObjectIntPair<Type>(a.TargetType, a.FieldNumber).GetHashCode();
            }

            internal static ExtensionComparer Instance = new ExtensionComparer();
        }
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
        private IDictionary<ObjectIntPair<Type>, Extension> extensions;

        /// <summary>
        /// Creates a new empty extension registry
        /// </summary>
        public ExtensionRegistry()
        {
            extensions = new Dictionary<ObjectIntPair<Type>, Extension>();
        }

        private ExtensionRegistry(IDictionary<ObjectIntPair<Type>, Extension> collection)
        {
            extensions = collection.ToDictionary(k => k.Key, v => v.Value);
        }

        /// <summary>
        /// Gets the total number of extensions in this extension registry
        /// </summary>
        public int Count => extensions.Count;

        /// <summary>
        /// Returns whether the registry is readonly
        /// </summary>
        bool ICollection<Extension>.IsReadOnly => false;

83 84 85
        internal bool ContainsInputField(CodedInputStream stream, Type target, out Extension extension)
        {
            return extensions.TryGetValue(new ObjectIntPair<Type>(target, WireFormat.GetTagFieldNumber(stream.LastTag)), out extension);
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
        }

        /// <summary>
        /// Adds the specified extension to the registry
        /// </summary>
        public void Add(Extension extension)
        {
            ProtoPreconditions.CheckNotNull(extension, nameof(extension));

            extensions.Add(new ObjectIntPair<Type>(extension.TargetType, extension.FieldNumber), extension);
        }

        /// <summary>
        /// Adds the specified extensions to the reigstry
        /// </summary>
101
        public void AddRange(IEnumerable<Extension> extensions)
102
        {
103
            ProtoPreconditions.CheckNotNull(extensions, nameof(extensions));
104

105
            foreach (var extension in extensions)
106
            {
107
                Add(extension);
108
            }
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
        }

        /// <summary>
        /// Clears the registry of all values
        /// </summary>
        public void Clear()
        {
            extensions.Clear();
        }

        /// <summary>
        /// Gets whether the extension registry contains the specified extension
        /// </summary>
        public bool Contains(Extension item)
        {
            ProtoPreconditions.CheckNotNull(item, nameof(item));

            return extensions.ContainsKey(new ObjectIntPair<Type>(item.TargetType, item.FieldNumber));
        }

        /// <summary>
        /// Copies the arrays in the registry set to the specified array at the specified index
        /// </summary>
        /// <param name="array">The array to copy to</param>
        /// <param name="arrayIndex">The array index to start at</param>
        void ICollection<Extension>.CopyTo(Extension[] array, int arrayIndex)
        {
            ProtoPreconditions.CheckNotNull(array, nameof(array));
            if (arrayIndex < 0 || arrayIndex >= array.Length)
138
            {
139
                throw new ArgumentOutOfRangeException(nameof(arrayIndex));
140
            }
141
            if (array.Length - arrayIndex < Count)
142
            {
143
                throw new ArgumentException("The provided array is shorter than the number of elements in the registry");
144
            }
145

146 147 148 149
            for (int i = 0; i < array.Length; i++)
            {
                Extension extension = array[i];
                extensions.Add(new ObjectIntPair<Type>(extension.TargetType, extension.FieldNumber), extension);
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
            }
        }

        /// <summary>
        /// Returns an enumerator to enumerate through the items in the registry
        /// </summary>
        /// <returns>Returns an enumerator for the extensions in this registry</returns>
        public IEnumerator<Extension> GetEnumerator()
        {
            return extensions.Values.GetEnumerator();
        }

        /// <summary>
        /// Removes the specified extension from the set
        /// </summary>
        /// <param name="item">The extension</param>
        /// <returns><c>true</c> if the extension was removed, otherwise <c>false</c></returns>
        public bool Remove(Extension item)
        {
            ProtoPreconditions.CheckNotNull(item, nameof(item));

            return extensions.Remove(new ObjectIntPair<Type>(item.TargetType, item.FieldNumber));
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

        /// <summary>
        /// Clones the registry into a new registry
        /// </summary>
        public ExtensionRegistry Clone()
        {
            return new ExtensionRegistry(extensions);
        }
    }
}