blob: 5d8e2845fe1a1ee578307f4cd05aa7be2b1e7732 [file] [log] [blame]
Jon Skeet68036862008-10-22 13:30:34 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.
3// http://code.google.com/p/protobuf/
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16using System;
17using System.Collections;
18using System.Collections.Generic;
19using System.Reflection;
20using Google.ProtocolBuffers.Descriptors;
21
22namespace Google.ProtocolBuffers {
23 /// <summary>
24 /// Base type for all generated extensions.
25 /// </summary>
26 /// <remarks>
27 /// The protocol compiler generates a static singleton instance of this
28 /// class for each extension. For exmaple, imagine a .proto file with:
29 /// <code>
30 /// message Foo {
31 /// extensions 1000 to max
32 /// }
33 ///
34 /// extend Foo {
35 /// optional int32 bar;
36 /// }
37 /// </code>
38 /// Then MyProto.Foo.Bar has type GeneratedExtensionBase&lt;MyProto.Foo,int&gt;.
39 /// <para />
40 /// In general, users should ignore the details of this type, and
41 /// simply use the static singletons as parameters to the extension accessors
42 /// in ExtendableMessage and ExtendableBuilder.
43 /// The interface implemented by both GeneratedException and GeneratedRepeatException,
44 /// to make it easier to cope with repeats separately.
45 /// </remarks>
46 public abstract class GeneratedExtensionBase<TExtension> {
47
48 private readonly FieldDescriptor descriptor;
49 private readonly IMessage messageDefaultInstance;
50
51 protected GeneratedExtensionBase(FieldDescriptor descriptor, Type singularExtensionType) {
52 if (!descriptor.IsExtension) {
53 throw new ArgumentException("GeneratedExtension given a regular (non-extension) field.");
54 }
55
56 this.descriptor = descriptor;
57 if (descriptor.MappedType == MappedType.Message) {
58 PropertyInfo defaultInstanceProperty = singularExtensionType
59 .GetProperty("DefaultInstance", BindingFlags.Static | BindingFlags.Public);
60 if (defaultInstanceProperty == null) {
61 throw new ArgumentException("No public static DefaultInstance property for type " + typeof(TExtension).Name);
62 }
63 messageDefaultInstance = (IMessage)defaultInstanceProperty.GetValue(null, null);
64 }
65 }
66
67 public FieldDescriptor Descriptor {
68 get { return descriptor; }
69 }
70
71 /// <summary>
72 /// Returns the default message instance for extensions which are message types.
73 /// </summary>
74 public IMessage MessageDefaultInstance {
75 get { return messageDefaultInstance; }
76 }
77
78 public object SingularFromReflectionType(object value) {
79 switch (Descriptor.MappedType) {
80 case MappedType.Message:
81 if (value is TExtension) {
82 return value;
83 } else {
84 // It seems the copy of the embedded message stored inside the
85 // extended message is not of the exact type the user was
86 // expecting. This can happen if a user defines a
87 // GeneratedExtension manually and gives it a different type.
88 // This should not happen in normal use. But, to be nice, we'll
89 // copy the message to whatever type the caller was expecting.
90 return MessageDefaultInstance.WeakCreateBuilderForType()
91 .WeakMergeFrom((IMessage)value).WeakBuild();
92 }
93 case MappedType.Enum:
94 // Just return a boxed int - that can be unboxed to the enum
95 EnumValueDescriptor enumValue = (EnumValueDescriptor) value;
96 return enumValue.Number;
97 default:
98 return value;
99 }
100 }
101
102 /// <summary>
103 /// Converts from the type used by the native accessors to the type
104 /// used by reflection accessors. For example, the reflection accessors
105 /// for enums use EnumValueDescriptors but the native accessors use
106 /// the generated enum type.
107 /// </summary>
108 public object ToReflectionType(object value) {
109 if (descriptor.IsRepeated) {
110 if (descriptor.MappedType == MappedType.Enum) {
111 // Must convert the whole list.
112 IList<object> result = new List<object>();
113 foreach (object element in (IEnumerable) value) {
114 result.Add(SingularToReflectionType(element));
115 }
116 return result;
117 } else {
118 return value;
119 }
120 } else {
121 return SingularToReflectionType(value);
122 }
123 }
124
125 /// <summary>
126 /// Like ToReflectionType(object) but for a single element.
127 /// </summary>
128 internal Object SingularToReflectionType(object value) {
129 return descriptor.MappedType == MappedType.Enum
130 ? descriptor.EnumType.FindValueByNumber((int) value)
131 : value;
132 }
133
134 public abstract object FromReflectionType(object value);
135 }
136}