xref: /aosp_15_r20/external/protobuf/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license
2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2017 Google Inc.  All rights reserved.
4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/
5*1b3f573fSAndroid Build Coastguard Worker //
6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
8*1b3f573fSAndroid Build Coastguard Worker // met:
9*1b3f573fSAndroid Build Coastguard Worker //
10*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
12*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
15*1b3f573fSAndroid Build Coastguard Worker // distribution.
16*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
19*1b3f573fSAndroid Build Coastguard Worker //
20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*1b3f573fSAndroid Build Coastguard Worker #endregion
32*1b3f573fSAndroid Build Coastguard Worker 
33*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.Collections;
34*1b3f573fSAndroid Build Coastguard Worker using System;
35*1b3f573fSAndroid Build Coastguard Worker using System.Collections;
36*1b3f573fSAndroid Build Coastguard Worker using System.Collections.Generic;
37*1b3f573fSAndroid Build Coastguard Worker using System.Diagnostics.CodeAnalysis;
38*1b3f573fSAndroid Build Coastguard Worker using System.Linq;
39*1b3f573fSAndroid Build Coastguard Worker using System.Reflection;
40*1b3f573fSAndroid Build Coastguard Worker 
41*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf.Reflection
42*1b3f573fSAndroid Build Coastguard Worker {
43*1b3f573fSAndroid Build Coastguard Worker     /// <summary>
44*1b3f573fSAndroid Build Coastguard Worker     /// Container for a set of custom options specified within a message, field etc.
45*1b3f573fSAndroid Build Coastguard Worker     /// </summary>
46*1b3f573fSAndroid Build Coastguard Worker     /// <remarks>
47*1b3f573fSAndroid Build Coastguard Worker     /// <para>
48*1b3f573fSAndroid Build Coastguard Worker     /// This type is publicly immutable, but internally mutable. It is only populated
49*1b3f573fSAndroid Build Coastguard Worker     /// by the descriptor parsing code - by the time any user code is able to see an instance,
50*1b3f573fSAndroid Build Coastguard Worker     /// it will be fully initialized.
51*1b3f573fSAndroid Build Coastguard Worker     /// </para>
52*1b3f573fSAndroid Build Coastguard Worker     /// <para>
53*1b3f573fSAndroid Build Coastguard Worker     /// If an option is requested using the incorrect method, an answer may still be returned: all
54*1b3f573fSAndroid Build Coastguard Worker     /// of the numeric types are represented internally using 64-bit integers, for example. It is up to
55*1b3f573fSAndroid Build Coastguard Worker     /// the caller to ensure that they make the appropriate method call for the option they're interested in.
56*1b3f573fSAndroid Build Coastguard Worker     /// Note that enum options are simply stored as integers, so the value should be fetched using
57*1b3f573fSAndroid Build Coastguard Worker     /// <see cref="TryGetInt32(int, out int)"/> and then cast appropriately.
58*1b3f573fSAndroid Build Coastguard Worker     /// </para>
59*1b3f573fSAndroid Build Coastguard Worker     /// <para>
60*1b3f573fSAndroid Build Coastguard Worker     /// Repeated options are currently not supported. Asking for a single value of an option
61*1b3f573fSAndroid Build Coastguard Worker     /// which was actually repeated will return the last value, except for message types where
62*1b3f573fSAndroid Build Coastguard Worker     /// all the set values are merged together.
63*1b3f573fSAndroid Build Coastguard Worker     /// </para>
64*1b3f573fSAndroid Build Coastguard Worker     /// </remarks>
65*1b3f573fSAndroid Build Coastguard Worker     public sealed class CustomOptions
66*1b3f573fSAndroid Build Coastguard Worker     {
67*1b3f573fSAndroid Build Coastguard Worker         private const string UnreferencedCodeMessage = "CustomOptions is incompatible with trimming.";
68*1b3f573fSAndroid Build Coastguard Worker 
69*1b3f573fSAndroid Build Coastguard Worker         private static readonly object[] EmptyParameters = new object[0];
70*1b3f573fSAndroid Build Coastguard Worker         private readonly IDictionary<int, IExtensionValue> values;
71*1b3f573fSAndroid Build Coastguard Worker 
CustomOptions(IDictionary<int, IExtensionValue> values)72*1b3f573fSAndroid Build Coastguard Worker         internal CustomOptions(IDictionary<int, IExtensionValue> values)
73*1b3f573fSAndroid Build Coastguard Worker         {
74*1b3f573fSAndroid Build Coastguard Worker             this.values = values;
75*1b3f573fSAndroid Build Coastguard Worker         }
76*1b3f573fSAndroid Build Coastguard Worker 
77*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
78*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a Boolean value for the specified option field.
79*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
80*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
81*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
82*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
83*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetBool(int field, out bool value)84*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetBool(int field, out bool value) => TryGetPrimitiveValue(field, out value);
85*1b3f573fSAndroid Build Coastguard Worker 
86*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
87*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a signed 32-bit integer value for the specified option field.
88*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
89*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
90*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
91*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
92*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetInt32(int field, out int value)93*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetInt32(int field, out int value) => TryGetPrimitiveValue(field, out value);
94*1b3f573fSAndroid Build Coastguard Worker 
95*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
96*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a signed 64-bit integer value for the specified option field.
97*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
98*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
99*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
100*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
101*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetInt64(int field, out long value)102*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetInt64(int field, out long value) => TryGetPrimitiveValue(field, out value);
103*1b3f573fSAndroid Build Coastguard Worker 
104*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
105*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves an unsigned 32-bit integer value for the specified option field,
106*1b3f573fSAndroid Build Coastguard Worker         /// assuming a fixed-length representation.
107*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
108*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
109*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
110*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
111*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetFixed32(int field, out uint value)112*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetFixed32(int field, out uint value) => TryGetUInt32(field, out value);
113*1b3f573fSAndroid Build Coastguard Worker 
114*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
115*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves an unsigned 64-bit integer value for the specified option field,
116*1b3f573fSAndroid Build Coastguard Worker         /// assuming a fixed-length representation.
117*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
118*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
119*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
120*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
121*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetFixed64(int field, out ulong value)122*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetFixed64(int field, out ulong value) => TryGetUInt64(field, out value);
123*1b3f573fSAndroid Build Coastguard Worker 
124*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
125*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a signed 32-bit integer value for the specified option field,
126*1b3f573fSAndroid Build Coastguard Worker         /// assuming a fixed-length representation.
127*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
128*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
129*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
130*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
131*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetSFixed32(int field, out int value)132*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetSFixed32(int field, out int value) => TryGetInt32(field, out value);
133*1b3f573fSAndroid Build Coastguard Worker 
134*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
135*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a signed 64-bit integer value for the specified option field,
136*1b3f573fSAndroid Build Coastguard Worker         /// assuming a fixed-length representation.
137*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
138*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
139*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
140*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
141*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetSFixed64(int field, out long value)142*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetSFixed64(int field, out long value) => TryGetInt64(field, out value);
143*1b3f573fSAndroid Build Coastguard Worker 
144*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
145*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a signed 32-bit integer value for the specified option field,
146*1b3f573fSAndroid Build Coastguard Worker         /// assuming a zigzag encoding.
147*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
148*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
149*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
150*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
151*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetSInt32(int field, out int value)152*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetSInt32(int field, out int value) => TryGetPrimitiveValue(field, out value);
153*1b3f573fSAndroid Build Coastguard Worker 
154*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
155*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a signed 64-bit integer value for the specified option field,
156*1b3f573fSAndroid Build Coastguard Worker         /// assuming a zigzag encoding.
157*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
158*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
159*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
160*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
161*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetSInt64(int field, out long value)162*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetSInt64(int field, out long value) => TryGetPrimitiveValue(field, out value);
163*1b3f573fSAndroid Build Coastguard Worker 
164*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
165*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves an unsigned 32-bit integer value for the specified option field.
166*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
167*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
168*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
169*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
170*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetUInt32(int field, out uint value)171*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetUInt32(int field, out uint value) => TryGetPrimitiveValue(field, out value);
172*1b3f573fSAndroid Build Coastguard Worker 
173*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
174*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves an unsigned 64-bit integer value for the specified option field.
175*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
176*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
177*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
178*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
179*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetUInt64(int field, out ulong value)180*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetUInt64(int field, out ulong value) => TryGetPrimitiveValue(field, out value);
181*1b3f573fSAndroid Build Coastguard Worker 
182*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
183*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a 32-bit floating point value for the specified option field.
184*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
185*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
186*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
187*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
188*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetFloat(int field, out float value)189*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetFloat(int field, out float value) => TryGetPrimitiveValue(field, out value);
190*1b3f573fSAndroid Build Coastguard Worker 
191*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
192*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a 64-bit floating point value for the specified option field.
193*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
194*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
195*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
196*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
197*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetDouble(int field, out double value)198*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetDouble(int field, out double value) => TryGetPrimitiveValue(field, out value);
199*1b3f573fSAndroid Build Coastguard Worker 
200*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
201*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a string value for the specified option field.
202*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
203*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
204*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
205*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
206*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetString(int field, out string value)207*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetString(int field, out string value) => TryGetPrimitiveValue(field, out value);
208*1b3f573fSAndroid Build Coastguard Worker 
209*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
210*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a bytes value for the specified option field.
211*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
212*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
213*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
214*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
215*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetBytes(int field, out ByteString value)216*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetBytes(int field, out ByteString value) => TryGetPrimitiveValue(field, out value);
217*1b3f573fSAndroid Build Coastguard Worker 
218*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
219*1b3f573fSAndroid Build Coastguard Worker         /// Retrieves a message value for the specified option field.
220*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
221*1b3f573fSAndroid Build Coastguard Worker         /// <param name="field">The field to fetch the value for.</param>
222*1b3f573fSAndroid Build Coastguard Worker         /// <param name="value">The output variable to populate.</param>
223*1b3f573fSAndroid Build Coastguard Worker         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
224*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
225*1b3f573fSAndroid Build Coastguard Worker         public bool TryGetMessage<T>(int field, out T value) where T : class, IMessage, new()
226*1b3f573fSAndroid Build Coastguard Worker         {
227*1b3f573fSAndroid Build Coastguard Worker             if (values == null)
228*1b3f573fSAndroid Build Coastguard Worker             {
229*1b3f573fSAndroid Build Coastguard Worker                 value = default(T);
230*1b3f573fSAndroid Build Coastguard Worker                 return false;
231*1b3f573fSAndroid Build Coastguard Worker             }
232*1b3f573fSAndroid Build Coastguard Worker 
233*1b3f573fSAndroid Build Coastguard Worker             IExtensionValue extensionValue;
234*1b3f573fSAndroid Build Coastguard Worker             if (values.TryGetValue(field, out extensionValue))
235*1b3f573fSAndroid Build Coastguard Worker             {
236*1b3f573fSAndroid Build Coastguard Worker                 if (extensionValue is ExtensionValue<T>)
237*1b3f573fSAndroid Build Coastguard Worker                 {
238*1b3f573fSAndroid Build Coastguard Worker                     ExtensionValue<T> single = extensionValue as ExtensionValue<T>;
239*1b3f573fSAndroid Build Coastguard Worker                     ByteString bytes = single.GetValue().ToByteString();
240*1b3f573fSAndroid Build Coastguard Worker                     value = new T();
241*1b3f573fSAndroid Build Coastguard Worker                     value.MergeFrom(bytes);
242*1b3f573fSAndroid Build Coastguard Worker                     return true;
243*1b3f573fSAndroid Build Coastguard Worker                 }
244*1b3f573fSAndroid Build Coastguard Worker                 else if (extensionValue is RepeatedExtensionValue<T>)
245*1b3f573fSAndroid Build Coastguard Worker                 {
246*1b3f573fSAndroid Build Coastguard Worker                     RepeatedExtensionValue<T> repeated = extensionValue as RepeatedExtensionValue<T>;
247*1b3f573fSAndroid Build Coastguard Worker                     value = repeated.GetValue()
248*1b3f573fSAndroid Build Coastguard Worker                         .Select(v => v.ToByteString())
249*1b3f573fSAndroid Build Coastguard Worker                         .Aggregate(new T(), (t, b) =>
250*1b3f573fSAndroid Build Coastguard Worker                         {
251*1b3f573fSAndroid Build Coastguard Worker                             t.MergeFrom(b);
252*1b3f573fSAndroid Build Coastguard Worker                             return t;
253*1b3f573fSAndroid Build Coastguard Worker                         });
254*1b3f573fSAndroid Build Coastguard Worker                     return true;
255*1b3f573fSAndroid Build Coastguard Worker                 }
256*1b3f573fSAndroid Build Coastguard Worker             }
257*1b3f573fSAndroid Build Coastguard Worker 
258*1b3f573fSAndroid Build Coastguard Worker             value = null;
259*1b3f573fSAndroid Build Coastguard Worker             return false;
260*1b3f573fSAndroid Build Coastguard Worker         }
261*1b3f573fSAndroid Build Coastguard Worker 
262*1b3f573fSAndroid Build Coastguard Worker         [RequiresUnreferencedCode(UnreferencedCodeMessage)]
TryGetPrimitiveValue(int field, out T value)263*1b3f573fSAndroid Build Coastguard Worker         private bool TryGetPrimitiveValue<T>(int field, out T value)
264*1b3f573fSAndroid Build Coastguard Worker         {
265*1b3f573fSAndroid Build Coastguard Worker             if (values == null)
266*1b3f573fSAndroid Build Coastguard Worker             {
267*1b3f573fSAndroid Build Coastguard Worker                 value = default(T);
268*1b3f573fSAndroid Build Coastguard Worker                 return false;
269*1b3f573fSAndroid Build Coastguard Worker             }
270*1b3f573fSAndroid Build Coastguard Worker 
271*1b3f573fSAndroid Build Coastguard Worker             IExtensionValue extensionValue;
272*1b3f573fSAndroid Build Coastguard Worker             if (values.TryGetValue(field, out extensionValue))
273*1b3f573fSAndroid Build Coastguard Worker             {
274*1b3f573fSAndroid Build Coastguard Worker                 if (extensionValue is ExtensionValue<T>)
275*1b3f573fSAndroid Build Coastguard Worker                 {
276*1b3f573fSAndroid Build Coastguard Worker                     ExtensionValue<T> single = extensionValue as ExtensionValue<T>;
277*1b3f573fSAndroid Build Coastguard Worker                     value = single.GetValue();
278*1b3f573fSAndroid Build Coastguard Worker                     return true;
279*1b3f573fSAndroid Build Coastguard Worker                 }
280*1b3f573fSAndroid Build Coastguard Worker                 else if (extensionValue is RepeatedExtensionValue<T>)
281*1b3f573fSAndroid Build Coastguard Worker                 {
282*1b3f573fSAndroid Build Coastguard Worker                     RepeatedExtensionValue<T> repeated = extensionValue as RepeatedExtensionValue<T>;
283*1b3f573fSAndroid Build Coastguard Worker                     if (repeated.GetValue().Count != 0)
284*1b3f573fSAndroid Build Coastguard Worker                     {
285*1b3f573fSAndroid Build Coastguard Worker                         RepeatedField<T> repeatedField = repeated.GetValue();
286*1b3f573fSAndroid Build Coastguard Worker                         value = repeatedField[repeatedField.Count - 1];
287*1b3f573fSAndroid Build Coastguard Worker                         return true;
288*1b3f573fSAndroid Build Coastguard Worker                     }
289*1b3f573fSAndroid Build Coastguard Worker                 }
290*1b3f573fSAndroid Build Coastguard Worker                 else // and here we find explicit enum handling since T : Enum ! x is ExtensionValue<Enum>
291*1b3f573fSAndroid Build Coastguard Worker                 {
292*1b3f573fSAndroid Build Coastguard Worker                     var type = extensionValue.GetType();
293*1b3f573fSAndroid Build Coastguard Worker                     if (type.GetGenericTypeDefinition() == typeof(ExtensionValue<>))
294*1b3f573fSAndroid Build Coastguard Worker                     {
295*1b3f573fSAndroid Build Coastguard Worker                         var typeInfo = type.GetTypeInfo();
296*1b3f573fSAndroid Build Coastguard Worker                         var typeArgs = typeInfo.GenericTypeArguments;
297*1b3f573fSAndroid Build Coastguard Worker                         if (typeArgs.Length == 1 && typeArgs[0].GetTypeInfo().IsEnum)
298*1b3f573fSAndroid Build Coastguard Worker                         {
299*1b3f573fSAndroid Build Coastguard Worker                             value = (T)typeInfo.GetDeclaredMethod(nameof(ExtensionValue<T>.GetValue)).Invoke(extensionValue, EmptyParameters);
300*1b3f573fSAndroid Build Coastguard Worker                             return true;
301*1b3f573fSAndroid Build Coastguard Worker                         }
302*1b3f573fSAndroid Build Coastguard Worker                     }
303*1b3f573fSAndroid Build Coastguard Worker                     else if (type.GetGenericTypeDefinition() == typeof(RepeatedExtensionValue<>))
304*1b3f573fSAndroid Build Coastguard Worker                     {
305*1b3f573fSAndroid Build Coastguard Worker                         var typeInfo = type.GetTypeInfo();
306*1b3f573fSAndroid Build Coastguard Worker                         var typeArgs = typeInfo.GenericTypeArguments;
307*1b3f573fSAndroid Build Coastguard Worker                         if (typeArgs.Length == 1 && typeArgs[0].GetTypeInfo().IsEnum)
308*1b3f573fSAndroid Build Coastguard Worker                         {
309*1b3f573fSAndroid Build Coastguard Worker                             var values = (IList)typeInfo.GetDeclaredMethod(nameof(RepeatedExtensionValue<T>.GetValue)).Invoke(extensionValue, EmptyParameters);
310*1b3f573fSAndroid Build Coastguard Worker                             if (values.Count != 0)
311*1b3f573fSAndroid Build Coastguard Worker                             {
312*1b3f573fSAndroid Build Coastguard Worker                                 value = (T)values[values.Count - 1];
313*1b3f573fSAndroid Build Coastguard Worker                                 return true;
314*1b3f573fSAndroid Build Coastguard Worker                             }
315*1b3f573fSAndroid Build Coastguard Worker                         }
316*1b3f573fSAndroid Build Coastguard Worker                     }
317*1b3f573fSAndroid Build Coastguard Worker                 }
318*1b3f573fSAndroid Build Coastguard Worker             }
319*1b3f573fSAndroid Build Coastguard Worker 
320*1b3f573fSAndroid Build Coastguard Worker             value = default(T);
321*1b3f573fSAndroid Build Coastguard Worker             return false;
322*1b3f573fSAndroid Build Coastguard Worker         }
323*1b3f573fSAndroid Build Coastguard Worker     }
324*1b3f573fSAndroid Build Coastguard Worker }
325