• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2008 Google Inc.  All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32 
33 using System;
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.Linq;
37 
38 namespace Google.Protobuf
39 {
40     /// <summary>
41     /// Provides extensions to messages while parsing. This API is experimental and subject to change.
42     /// </summary>
43     public sealed class ExtensionRegistry : ICollection<Extension>, IDeepCloneable<ExtensionRegistry>
44     {
45         internal sealed class ExtensionComparer : IEqualityComparer<Extension>
46         {
Equals(Extension a, Extension b)47             public bool Equals(Extension a, Extension b)
48             {
49                 return new ObjectIntPair<Type>(a.TargetType, a.FieldNumber).Equals(new ObjectIntPair<Type>(b.TargetType, b.FieldNumber));
50             }
GetHashCode(Extension a)51             public int GetHashCode(Extension a)
52             {
53                 return new ObjectIntPair<Type>(a.TargetType, a.FieldNumber).GetHashCode();
54             }
55 
56             internal static ExtensionComparer Instance = new ExtensionComparer();
57         }
58         private IDictionary<ObjectIntPair<Type>, Extension> extensions;
59 
60         /// <summary>
61         /// Creates a new empty extension registry
62         /// </summary>
ExtensionRegistry()63         public ExtensionRegistry()
64         {
65             extensions = new Dictionary<ObjectIntPair<Type>, Extension>();
66         }
67 
ExtensionRegistry(IDictionary<ObjectIntPair<Type>, Extension> collection)68         private ExtensionRegistry(IDictionary<ObjectIntPair<Type>, Extension> collection)
69         {
70             extensions = collection.ToDictionary(k => k.Key, v => v.Value);
71         }
72 
73         /// <summary>
74         /// Gets the total number of extensions in this extension registry
75         /// </summary>
76         public int Count => extensions.Count;
77 
78         /// <summary>
79         /// Returns whether the registry is readonly
80         /// </summary>
81         bool ICollection<Extension>.IsReadOnly => false;
82 
ContainsInputField(uint lastTag, Type target, out Extension extension)83         internal bool ContainsInputField(uint lastTag, Type target, out Extension extension)
84         {
85             return extensions.TryGetValue(new ObjectIntPair<Type>(target, WireFormat.GetTagFieldNumber(lastTag)), out extension);
86         }
87 
88         /// <summary>
89         /// Adds the specified extension to the registry
90         /// </summary>
Add(Extension extension)91         public void Add(Extension extension)
92         {
93             ProtoPreconditions.CheckNotNull(extension, nameof(extension));
94 
95             extensions.Add(new ObjectIntPair<Type>(extension.TargetType, extension.FieldNumber), extension);
96         }
97 
98         /// <summary>
99         /// Adds the specified extensions to the registry
100         /// </summary>
AddRange(IEnumerable<Extension> extensions)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         /// <summary>
112         /// Clears the registry of all values
113         /// </summary>
Clear()114         public void Clear()
115         {
116             extensions.Clear();
117         }
118 
119         /// <summary>
120         /// Gets whether the extension registry contains the specified extension
121         /// </summary>
Contains(Extension item)122         public bool Contains(Extension item)
123         {
124             ProtoPreconditions.CheckNotNull(item, nameof(item));
125 
126             return extensions.ContainsKey(new ObjectIntPair<Type>(item.TargetType, item.FieldNumber));
127         }
128 
129         /// <summary>
130         /// Copies the arrays in the registry set to the specified array at the specified index
131         /// </summary>
132         /// <param name="array">The array to copy to</param>
133         /// <param name="arrayIndex">The array index to start at</param>
CopyTo(Extension[] array, int arrayIndex)134         void ICollection<Extension>.CopyTo(Extension[] array, int arrayIndex)
135         {
136             ProtoPreconditions.CheckNotNull(array, nameof(array));
137             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             for (int i = 0; i < array.Length; i++)
147             {
148                 Extension extension = array[i];
149                 extensions.Add(new ObjectIntPair<Type>(extension.TargetType, extension.FieldNumber), extension);
150             }
151         }
152 
153         /// <summary>
154         /// Returns an enumerator to enumerate through the items in the registry
155         /// </summary>
156         /// <returns>Returns an enumerator for the extensions in this registry</returns>
GetEnumerator()157         public IEnumerator<Extension> GetEnumerator()
158         {
159             return extensions.Values.GetEnumerator();
160         }
161 
162         /// <summary>
163         /// Removes the specified extension from the set
164         /// </summary>
165         /// <param name="item">The extension</param>
166         /// <returns><c>true</c> if the extension was removed, otherwise <c>false</c></returns>
Remove(Extension item)167         public bool Remove(Extension item)
168         {
169             ProtoPreconditions.CheckNotNull(item, nameof(item));
170 
171             return extensions.Remove(new ObjectIntPair<Type>(item.TargetType, item.FieldNumber));
172         }
173 
IEnumerable.GetEnumerator()174         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
175 
176         /// <summary>
177         /// Clones the registry into a new registry
178         /// </summary>
Clone()179         public ExtensionRegistry Clone()
180         {
181             return new ExtensionRegistry(extensions);
182         }
183     }
184 }
185