GeneratedExtensionLite.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Collections;
  36. using System.Collections.Generic;
  37. using Google.ProtocolBuffers.Collections;
  38. using Google.ProtocolBuffers.Descriptors;
  39. namespace Google.ProtocolBuffers {
  40. public interface IGeneratedExtensionLite {
  41. int Number { get; }
  42. object ContainingType { get; }
  43. IMessageLite MessageDefaultInstance { get; }
  44. }
  45. public class ExtensionDescriptorLite : IFieldDescriptorLite {
  46. /// <summary>
  47. /// Immutable mapping from field type to mapped type. Built using the attributes on
  48. /// FieldType values.
  49. /// </summary>
  50. public static readonly IDictionary<FieldType, MappedType> FieldTypeToMappedTypeMap = MapFieldTypes();
  51. private static IDictionary<FieldType, MappedType> MapFieldTypes() {
  52. var map = new Dictionary<FieldType, MappedType>();
  53. foreach (System.Reflection.FieldInfo field in typeof(FieldType).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)) {
  54. FieldType fieldType = (FieldType)field.GetValue(null);
  55. FieldMappingAttribute mapping = (FieldMappingAttribute)field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0];
  56. map[fieldType] = mapping.MappedType;
  57. }
  58. return Dictionaries.AsReadOnly(map);
  59. }
  60. private readonly IEnumLiteMap enumTypeMap;
  61. private readonly int number;
  62. private readonly FieldType type;
  63. private readonly bool isRepeated;
  64. private readonly bool isPacked;
  65. private readonly MappedType mapType;
  66. private readonly object defaultValue;
  67. public ExtensionDescriptorLite(IEnumLiteMap enumTypeMap, int number, FieldType type, object defaultValue, bool isRepeated, bool isPacked) {
  68. this.enumTypeMap = enumTypeMap;
  69. this.number = number;
  70. this.type = type;
  71. this.mapType = FieldTypeToMappedTypeMap[type];
  72. this.isRepeated = isRepeated;
  73. this.isPacked = isPacked;
  74. this.defaultValue = defaultValue;
  75. }
  76. public bool IsRepeated {
  77. get { return isRepeated; }
  78. }
  79. public bool IsRequired {
  80. get { return false; }
  81. }
  82. public bool IsPacked {
  83. get { return isPacked; }
  84. }
  85. public bool IsExtension {
  86. get { return true; }
  87. }
  88. #warning ToDo - Discover the meaning and purpose of this durring serialization and return the correct value
  89. public bool MessageSetWireFormat {
  90. get { return true; }
  91. }
  92. public int FieldNumber {
  93. get { return number; }
  94. }
  95. public IEnumLiteMap EnumType {
  96. get { return enumTypeMap; }
  97. }
  98. public FieldType FieldType {
  99. get { return type; }
  100. }
  101. public MappedType MappedType {
  102. get { return mapType; }
  103. }
  104. public object DefaultValue {
  105. get { return defaultValue; }
  106. }
  107. public int CompareTo(IFieldDescriptorLite other) {
  108. return FieldNumber.CompareTo(other.FieldNumber);
  109. }
  110. }
  111. public class GeneratedExtensionLite<TContainingType, TExtensionType> : IGeneratedExtensionLite
  112. where TContainingType : IMessageLite {
  113. private readonly TContainingType containingTypeDefaultInstance;
  114. private readonly TExtensionType defaultValue;
  115. private readonly IMessageLite messageDefaultInstance;
  116. private readonly ExtensionDescriptorLite descriptor;
  117. // We can't always initialize a GeneratedExtension when we first construct
  118. // it due to initialization order difficulties (namely, the default
  119. // instances may not have been constructed yet). So, we construct an
  120. // uninitialized GeneratedExtension once, then call internalInit() on it
  121. // later. Generated code will always call internalInit() on all extensions
  122. // as part of the static initialization code, and internalInit() throws an
  123. // exception if called more than once, so this method is useless to users.
  124. protected GeneratedExtensionLite(
  125. TContainingType containingTypeDefaultInstance,
  126. TExtensionType defaultValue,
  127. IMessageLite messageDefaultInstance,
  128. ExtensionDescriptorLite descriptor) {
  129. this.containingTypeDefaultInstance = containingTypeDefaultInstance;
  130. this.messageDefaultInstance = messageDefaultInstance;
  131. this.defaultValue = defaultValue;
  132. this.descriptor = descriptor;
  133. }
  134. /** For use by generated code only. */
  135. public GeneratedExtensionLite(
  136. TContainingType containingTypeDefaultInstance,
  137. TExtensionType defaultValue,
  138. IMessageLite messageDefaultInstance,
  139. IEnumLiteMap enumTypeMap,
  140. int number,
  141. FieldType type)
  142. : this(containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
  143. new ExtensionDescriptorLite(enumTypeMap, number, type, defaultValue,
  144. false /* isRepeated */, false /* isPacked */)) {
  145. }
  146. /** For use by generated code only. */
  147. public GeneratedExtensionLite(
  148. TContainingType containingTypeDefaultInstance,
  149. TExtensionType defaultValue,
  150. IMessageLite messageDefaultInstance,
  151. IEnumLiteMap enumTypeMap,
  152. int number,
  153. FieldType type,
  154. bool isPacked)
  155. : this(containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
  156. new ExtensionDescriptorLite(enumTypeMap, number, type, defaultValue,
  157. true /* isRepeated */, isPacked)) {
  158. }
  159. /// <summary>
  160. /// Returns information about this extension
  161. /// </summary>
  162. public IFieldDescriptorLite Descriptor {
  163. get { return descriptor; }
  164. }
  165. /// <summary>
  166. /// Returns the default value for this extension
  167. /// </summary>
  168. public TExtensionType DefaultValue {
  169. get { return defaultValue; }
  170. }
  171. /// <summary>
  172. /// used for the extension registry
  173. /// </summary>
  174. object IGeneratedExtensionLite.ContainingType {
  175. get { return ContainingTypeDefaultInstance; }
  176. }
  177. /**
  178. * Default instance of the type being extended, used to identify that type.
  179. */
  180. public TContainingType ContainingTypeDefaultInstance {
  181. get {
  182. return containingTypeDefaultInstance;
  183. }
  184. }
  185. /** Get the field number. */
  186. public int Number {
  187. get {
  188. return descriptor.FieldNumber;
  189. }
  190. }
  191. /**
  192. * If the extension is an embedded message, this is the default instance of
  193. * that type.
  194. */
  195. public IMessageLite MessageDefaultInstance {
  196. get {
  197. return messageDefaultInstance;
  198. }
  199. }
  200. /// <summary>
  201. /// Converts from the type used by the native accessors to the type
  202. /// used by reflection accessors. For example, the reflection accessors
  203. /// for enums use EnumValueDescriptors but the native accessors use
  204. /// the generated enum type.
  205. /// </summary>
  206. public object ToReflectionType(object value) {
  207. if (descriptor.IsRepeated) {
  208. if (descriptor.MappedType == MappedType.Enum) {
  209. // Must convert the whole list.
  210. IList<object> result = new List<object>();
  211. foreach (object element in (IEnumerable)value) {
  212. result.Add(SingularToReflectionType(element));
  213. }
  214. return result;
  215. } else {
  216. return value;
  217. }
  218. } else {
  219. return SingularToReflectionType(value);
  220. }
  221. }
  222. /// <summary>
  223. /// Like ToReflectionType(object) but for a single element.
  224. /// </summary>
  225. internal Object SingularToReflectionType(object value) {
  226. return descriptor.MappedType == MappedType.Enum
  227. ? descriptor.EnumType.FindValueByNumber((int)value)
  228. : value;
  229. }
  230. public object FromReflectionType(object value) {
  231. if (descriptor.IsRepeated) {
  232. if (Descriptor.MappedType == MappedType.Message ||
  233. Descriptor.MappedType == MappedType.Enum) {
  234. // Must convert the whole list.
  235. List<TExtensionType> result = new List<TExtensionType>();
  236. foreach (object element in (IEnumerable)value) {
  237. result.Add((TExtensionType)SingularFromReflectionType(element));
  238. }
  239. return result;
  240. } else {
  241. return value;
  242. }
  243. } else {
  244. return SingularFromReflectionType(value);
  245. }
  246. }
  247. public object SingularFromReflectionType(object value) {
  248. switch (Descriptor.MappedType) {
  249. case MappedType.Message:
  250. if (value is TExtensionType) {
  251. return value;
  252. } else {
  253. // It seems the copy of the embedded message stored inside the
  254. // extended message is not of the exact type the user was
  255. // expecting. This can happen if a user defines a
  256. // GeneratedExtension manually and gives it a different type.
  257. // This should not happen in normal use. But, to be nice, we'll
  258. // copy the message to whatever type the caller was expecting.
  259. return MessageDefaultInstance.WeakCreateBuilderForType()
  260. .WeakMergeFrom((IMessageLite)value).WeakBuild();
  261. }
  262. case MappedType.Enum:
  263. // Just return a boxed int - that can be unboxed to the enum
  264. IEnumLite enumValue = (IEnumLite)value;
  265. return enumValue.Number;
  266. default:
  267. return value;
  268. }
  269. }
  270. }
  271. }