• 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 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using System.Collections.Generic;
11 using System.Collections.ObjectModel;
12 using System.Diagnostics;
13 using System.Linq;
14 
15 namespace Google.Protobuf.Reflection
16 {
17     /// <summary>
18     /// A collection to simplify retrieving the descriptors of extensions in a descriptor for a message
19     /// </summary>
20     [DebuggerDisplay("Count = {UnorderedExtensions.Count}")]
21     [DebuggerTypeProxy(typeof(ExtensionCollectionDebugView))]
22     public sealed class ExtensionCollection
23     {
24         private IDictionary<MessageDescriptor, IList<FieldDescriptor>> extensionsByTypeInDeclarationOrder;
25         private IDictionary<MessageDescriptor, IList<FieldDescriptor>> extensionsByTypeInNumberOrder;
26 
ExtensionCollection(FileDescriptor file, Extension[] extensions)27         internal ExtensionCollection(FileDescriptor file, Extension[] extensions)
28         {
29             UnorderedExtensions = DescriptorUtil.ConvertAndMakeReadOnly(
30                 file.Proto.Extension,
31                 (extension, i) => {
32                     if (extensions?.Length != 0)
33                     {
34                         return new FieldDescriptor(extension, file, null, i, null, extensions?[i]);
35                     }
36                     else
37                     {
38                         return new FieldDescriptor(extension, file, null, i, null, null); // return null if there's no extensions in this array for old code-gen
39                     }
40                 });
41         }
42 
ExtensionCollection(MessageDescriptor message, Extension[] extensions)43         internal ExtensionCollection(MessageDescriptor message, Extension[] extensions)
44         {
45             UnorderedExtensions = DescriptorUtil.ConvertAndMakeReadOnly(
46                 message.Proto.Extension,
47                 (extension, i) => {
48                     if (extensions?.Length != 0)
49                     {
50                         return new FieldDescriptor(extension, message.File, message, i, null, extensions?[i]);
51                     }
52                     else
53                     {
54                         return new FieldDescriptor(extension, message.File, message, i, null, null);
55                     }
56                 });
57         }
58 
59         /// <summary>
60         /// Returns a readonly list of all the extensions defined in this type in
61         /// the order they were defined in the source .proto file
62         /// </summary>
63         public IList<FieldDescriptor> UnorderedExtensions { get; }
64 
65         /// <summary>
66         /// Returns a readonly list of all the extensions define in this type that extend
67         /// the provided descriptor type in the order they were defined in the source .proto file
68         /// </summary>
GetExtensionsInDeclarationOrder(MessageDescriptor descriptor)69         public IList<FieldDescriptor> GetExtensionsInDeclarationOrder(MessageDescriptor descriptor)
70         {
71             return extensionsByTypeInDeclarationOrder[descriptor];
72         }
73 
74         /// <summary>
75         /// Returns a readonly list of all the extensions define in this type that extend
76         /// the provided descriptor type in ascending field order
77         /// </summary>
GetExtensionsInNumberOrder(MessageDescriptor descriptor)78         public IList<FieldDescriptor> GetExtensionsInNumberOrder(MessageDescriptor descriptor)
79         {
80             return extensionsByTypeInNumberOrder[descriptor];
81         }
82 
CrossLink()83         internal void CrossLink()
84         {
85             Dictionary<MessageDescriptor, IList<FieldDescriptor>> declarationOrder = new Dictionary<MessageDescriptor, IList<FieldDescriptor>>();
86             foreach (FieldDescriptor descriptor in UnorderedExtensions)
87             {
88                 descriptor.CrossLink();
89 
90                 if (!declarationOrder.TryGetValue(descriptor.ExtendeeType, out IList<FieldDescriptor> list))
91                 {
92                     list = new List<FieldDescriptor>();
93                     declarationOrder.Add(descriptor.ExtendeeType, list);
94                 }
95 
96                 list.Add(descriptor);
97             }
98 
99             extensionsByTypeInDeclarationOrder = declarationOrder
100                 .ToDictionary(kvp => kvp.Key, kvp => (IList<FieldDescriptor>)new ReadOnlyCollection<FieldDescriptor>(kvp.Value));
101             extensionsByTypeInNumberOrder = declarationOrder
102                 .ToDictionary(kvp => kvp.Key, kvp => (IList<FieldDescriptor>)new ReadOnlyCollection<FieldDescriptor>(kvp.Value.OrderBy(field => field.FieldNumber).ToArray()));
103         }
104 
105         private sealed class ExtensionCollectionDebugView
106         {
107             private readonly ExtensionCollection list;
108 
ExtensionCollectionDebugView(ExtensionCollection list)109             public ExtensionCollectionDebugView(ExtensionCollection list)
110             {
111                 this.list = list;
112             }
113 
114             [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
115             public FieldDescriptor[] Items => list.UnorderedExtensions.ToArray();
116         }
117     }
118 }
119