blob: 12e6c77a676dbbb7a939b82ca3c123c00e9142e9 [file] [log] [blame]
Jon Skeet60c059b2008-10-23 21:17:56 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// http://github.com/jskeet/dotnet-protobufs/
4// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01005// http://code.google.com/p/protobuf/
6//
Jon Skeet60c059b2008-10-23 21:17:56 +01007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
Jon Skeet68036862008-10-22 13:30:34 +010010//
Jon Skeet60c059b2008-10-23 21:17:56 +010011// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010020//
Jon Skeet60c059b2008-10-23 21:17:56 +010021// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet68036862008-10-22 13:30:34 +010032using System;
33using System.Collections;
34using System.Collections.Generic;
35using System.Reflection;
36using Google.ProtocolBuffers.Descriptors;
37
38namespace Google.ProtocolBuffers {
39 /// <summary>
40 /// Base type for all generated extensions.
41 /// </summary>
42 /// <remarks>
43 /// The protocol compiler generates a static singleton instance of this
44 /// class for each extension. For exmaple, imagine a .proto file with:
45 /// <code>
46 /// message Foo {
47 /// extensions 1000 to max
48 /// }
49 ///
50 /// extend Foo {
51 /// optional int32 bar;
52 /// }
53 /// </code>
54 /// Then MyProto.Foo.Bar has type GeneratedExtensionBase&lt;MyProto.Foo,int&gt;.
55 /// <para />
56 /// In general, users should ignore the details of this type, and
57 /// simply use the static singletons as parameters to the extension accessors
58 /// in ExtendableMessage and ExtendableBuilder.
59 /// The interface implemented by both GeneratedException and GeneratedRepeatException,
60 /// to make it easier to cope with repeats separately.
61 /// </remarks>
62 public abstract class GeneratedExtensionBase<TExtension> {
63
64 private readonly FieldDescriptor descriptor;
65 private readonly IMessage messageDefaultInstance;
66
67 protected GeneratedExtensionBase(FieldDescriptor descriptor, Type singularExtensionType) {
68 if (!descriptor.IsExtension) {
69 throw new ArgumentException("GeneratedExtension given a regular (non-extension) field.");
70 }
71
72 this.descriptor = descriptor;
73 if (descriptor.MappedType == MappedType.Message) {
74 PropertyInfo defaultInstanceProperty = singularExtensionType
75 .GetProperty("DefaultInstance", BindingFlags.Static | BindingFlags.Public);
76 if (defaultInstanceProperty == null) {
77 throw new ArgumentException("No public static DefaultInstance property for type " + typeof(TExtension).Name);
78 }
79 messageDefaultInstance = (IMessage)defaultInstanceProperty.GetValue(null, null);
80 }
81 }
82
83 public FieldDescriptor Descriptor {
84 get { return descriptor; }
85 }
86
87 /// <summary>
88 /// Returns the default message instance for extensions which are message types.
89 /// </summary>
90 public IMessage MessageDefaultInstance {
91 get { return messageDefaultInstance; }
92 }
93
94 public object SingularFromReflectionType(object value) {
95 switch (Descriptor.MappedType) {
96 case MappedType.Message:
97 if (value is TExtension) {
98 return value;
99 } else {
100 // It seems the copy of the embedded message stored inside the
101 // extended message is not of the exact type the user was
102 // expecting. This can happen if a user defines a
103 // GeneratedExtension manually and gives it a different type.
104 // This should not happen in normal use. But, to be nice, we'll
105 // copy the message to whatever type the caller was expecting.
106 return MessageDefaultInstance.WeakCreateBuilderForType()
107 .WeakMergeFrom((IMessage)value).WeakBuild();
108 }
109 case MappedType.Enum:
110 // Just return a boxed int - that can be unboxed to the enum
111 EnumValueDescriptor enumValue = (EnumValueDescriptor) value;
112 return enumValue.Number;
113 default:
114 return value;
115 }
116 }
117
118 /// <summary>
119 /// Converts from the type used by the native accessors to the type
120 /// used by reflection accessors. For example, the reflection accessors
121 /// for enums use EnumValueDescriptors but the native accessors use
122 /// the generated enum type.
123 /// </summary>
124 public object ToReflectionType(object value) {
125 if (descriptor.IsRepeated) {
126 if (descriptor.MappedType == MappedType.Enum) {
127 // Must convert the whole list.
128 IList<object> result = new List<object>();
129 foreach (object element in (IEnumerable) value) {
130 result.Add(SingularToReflectionType(element));
131 }
132 return result;
133 } else {
134 return value;
135 }
136 } else {
137 return SingularToReflectionType(value);
138 }
139 }
140
141 /// <summary>
142 /// Like ToReflectionType(object) but for a single element.
143 /// </summary>
144 internal Object SingularToReflectionType(object value) {
145 return descriptor.MappedType == MappedType.Enum
146 ? descriptor.EnumType.FindValueByNumber((int) value)
147 : value;
148 }
149
150 public abstract object FromReflectionType(object value);
151 }
152}