• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 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.Reflection;
35 using Google.Protobuf.Compatibility;
36 
37 namespace Google.Protobuf.Reflection
38 {
39     /// <summary>
40     /// Reflection access for a oneof, allowing clear and "get case" actions.
41     /// </summary>
42     public sealed class OneofAccessor
43     {
44         private readonly Func<IMessage, int> caseDelegate;
45         private readonly Action<IMessage> clearDelegate;
46 
OneofAccessor(OneofDescriptor descriptor, Func<IMessage, int> caseDelegate, Action<IMessage> clearDelegate)47         private OneofAccessor(OneofDescriptor descriptor, Func<IMessage, int> caseDelegate, Action<IMessage> clearDelegate)
48         {
49             Descriptor = descriptor;
50             this.caseDelegate = caseDelegate;
51             this.clearDelegate = clearDelegate;
52         }
53 
ForRegularOneof( OneofDescriptor descriptor, PropertyInfo caseProperty, MethodInfo clearMethod)54         internal static OneofAccessor ForRegularOneof(
55             OneofDescriptor descriptor,
56             PropertyInfo caseProperty,
57             MethodInfo clearMethod) =>
58             new OneofAccessor(
59                 descriptor,
60                 ReflectionUtil.CreateFuncIMessageInt32(caseProperty.GetGetMethod()),
61                 ReflectionUtil.CreateActionIMessage(clearMethod));
62 
ForSyntheticOneof(OneofDescriptor descriptor)63         internal static OneofAccessor ForSyntheticOneof(OneofDescriptor descriptor)
64         {
65             // Note: descriptor.Fields will be null when this method is called, because we haven't
66             // cross-linked yet. But by the time the delgates are called by user code, all will be
67             // well. (That's why we capture the descriptor itself rather than a field.)
68             return new OneofAccessor(descriptor,
69                 message => descriptor.Fields[0].Accessor.HasValue(message) ? descriptor.Fields[0].FieldNumber : 0,
70                 message => descriptor.Fields[0].Accessor.Clear(message));
71         }
72 
73         /// <summary>
74         /// Gets the descriptor for this oneof.
75         /// </summary>
76         /// <value>
77         /// The descriptor of the oneof.
78         /// </value>
79         public OneofDescriptor Descriptor { get; }
80 
81         /// <summary>
82         /// Clears the oneof in the specified message.
83         /// </summary>
84         public void Clear(IMessage message) => clearDelegate(message);
85 
86         /// <summary>
87         /// Indicates which field in the oneof is set for specified message
88         /// </summary>
GetCaseFieldDescriptor(IMessage message)89         public FieldDescriptor GetCaseFieldDescriptor(IMessage message)
90         {
91             int fieldNumber = caseDelegate(message);
92             return fieldNumber > 0
93                 ? Descriptor.ContainingType.FindFieldByNumber(fieldNumber)
94                 : null;
95         }
96     }
97 }
98