FieldDescriptor.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using Google.ProtocolBuffers.Collections;
  5. using Google.ProtocolBuffers.DescriptorProtos;
  6. using System.Collections.ObjectModel;
  7. namespace Google.ProtocolBuffers.Descriptors {
  8. public class FieldDescriptor : IndexedDescriptorBase<FieldDescriptorProto, FieldOptions>, IComparable<FieldDescriptor> {
  9. private readonly MessageDescriptor extensionScope;
  10. private EnumDescriptor enumType;
  11. private MessageDescriptor messageType;
  12. private MessageDescriptor containingType;
  13. private object defaultValue;
  14. private FieldType fieldType;
  15. private MappedType mappedType;
  16. internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
  17. MessageDescriptor parent, int index, bool isExtension)
  18. : base(proto, file, ComputeFullName(file, parent, proto.Name), index) {
  19. if (proto.HasType) {
  20. fieldType = GetFieldTypeFromProtoType(proto.Type);
  21. mappedType = FieldTypeToMappedTypeMap[fieldType];
  22. }
  23. if (FieldNumber <= 0) {
  24. throw new DescriptorValidationException(this,
  25. "Field numbers must be positive integers.");
  26. }
  27. if (isExtension) {
  28. if (!proto.HasExtendee) {
  29. throw new DescriptorValidationException(this,
  30. "FieldDescriptorProto.Extendee not set for extension field.");
  31. }
  32. containingType = null; // Will be filled in when cross-linking
  33. if (parent != null) {
  34. extensionScope = parent;
  35. } else {
  36. extensionScope = null;
  37. }
  38. } else {
  39. if (proto.HasExtendee) {
  40. throw new DescriptorValidationException(this,
  41. "FieldDescriptorProto.Extendee set for non-extension field.");
  42. }
  43. containingType = parent;
  44. extensionScope = null;
  45. }
  46. file.DescriptorPool.AddSymbol(this);
  47. }
  48. /// <summary>
  49. /// Maps a field type as included in the .proto file to a FieldType.
  50. /// </summary>
  51. private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.Types.Type type) {
  52. switch (type) {
  53. case FieldDescriptorProto.Types.Type.TYPE_DOUBLE: return FieldType.Double;
  54. case FieldDescriptorProto.Types.Type.TYPE_FLOAT: return FieldType.Float;
  55. case FieldDescriptorProto.Types.Type.TYPE_INT64: return FieldType.Int64;
  56. case FieldDescriptorProto.Types.Type.TYPE_UINT64: return FieldType.UInt64;
  57. case FieldDescriptorProto.Types.Type.TYPE_INT32: return FieldType.Int32;
  58. case FieldDescriptorProto.Types.Type.TYPE_FIXED64: return FieldType.Fixed64;
  59. case FieldDescriptorProto.Types.Type.TYPE_FIXED32: return FieldType.Fixed32;
  60. case FieldDescriptorProto.Types.Type.TYPE_BOOL: return FieldType.Bool;
  61. case FieldDescriptorProto.Types.Type.TYPE_STRING: return FieldType.String;
  62. case FieldDescriptorProto.Types.Type.TYPE_GROUP: return FieldType.Group;
  63. case FieldDescriptorProto.Types.Type.TYPE_MESSAGE: return FieldType.Message;
  64. case FieldDescriptorProto.Types.Type.TYPE_BYTES: return FieldType.Bytes;
  65. case FieldDescriptorProto.Types.Type.TYPE_UINT32: return FieldType.UInt32;
  66. case FieldDescriptorProto.Types.Type.TYPE_ENUM: return FieldType.Enum;
  67. case FieldDescriptorProto.Types.Type.TYPE_SFIXED32: return FieldType.SFixed32;
  68. case FieldDescriptorProto.Types.Type.TYPE_SFIXED64: return FieldType.SFixed64;
  69. case FieldDescriptorProto.Types.Type.TYPE_SINT32: return FieldType.SInt32;
  70. case FieldDescriptorProto.Types.Type.TYPE_SINT64: return FieldType.SInt64;
  71. default:
  72. throw new ArgumentException("Invalid type specified");
  73. }
  74. }
  75. /// <summary>
  76. /// Returns the default value for a mapped type.
  77. /// </summary>
  78. private static object GetDefaultValueForMappedType(MappedType type) {
  79. switch (type) {
  80. case MappedType.Int32: return 0;
  81. case MappedType.Int64: return (long) 0;
  82. case MappedType.UInt32: return (uint) 0;
  83. case MappedType.UInt64: return (ulong) 0;
  84. case MappedType.Single: return (float) 0;
  85. case MappedType.Double: return (double) 0;
  86. case MappedType.Boolean: return false;
  87. case MappedType.String: return "";
  88. case MappedType.ByteString: return ByteString.Empty;
  89. case MappedType.Message: return null;
  90. case MappedType.Enum: return null;
  91. default:
  92. throw new ArgumentException("Invalid type specified");
  93. }
  94. }
  95. public bool IsRequired {
  96. get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REQUIRED; }
  97. }
  98. public bool IsOptional {
  99. get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_OPTIONAL; }
  100. }
  101. public bool IsRepeated {
  102. get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
  103. }
  104. /// <valule>
  105. /// Indicates whether or not the field had an explicitly-defined default value.
  106. /// </value>
  107. public bool HasDefaultValue {
  108. get { return Proto.HasDefaultValue; }
  109. }
  110. /// <value>
  111. /// The field's default value. Valid for all types except messages
  112. /// and groups. For all other types, the object returned is of the
  113. /// same class that would be returned by IMessage[this].
  114. /// For repeated fields this will always be an empty immutable list compatible with IList[object].
  115. /// For message fields it will always be null. For singular values, it will depend on the descriptor.
  116. /// </value>
  117. public object DefaultValue {
  118. get {
  119. if (MappedType == MappedType.Message) {
  120. throw new InvalidOperationException("FieldDescriptor.DefaultValue called on an embedded message field.");
  121. }
  122. return defaultValue;
  123. }
  124. }
  125. /// <value>
  126. /// Indicates whether or not this field is an extension.
  127. /// </value>
  128. public bool IsExtension {
  129. get { return Proto.HasExtendee; }
  130. }
  131. /*
  132. * Get the field's containing type. For extensions, this is the type being
  133. * extended, not the location where the extension was defined. See
  134. * {@link #getExtensionScope()}.
  135. */
  136. /// <summary>
  137. /// Get the field's containing type. For extensions, this is the type being
  138. /// extended, not the location where the extension was defined. See
  139. /// <see cref="ExtensionScope" />.
  140. /// </summary>
  141. public MessageDescriptor ContainingType {
  142. get { return containingType; }
  143. }
  144. /// <summary>
  145. /// For extensions defined nested within message types, gets
  146. /// the outer type. Not valid for non-extension fields.
  147. /// </summary>
  148. /// <example>
  149. /// <code>
  150. /// message Foo {
  151. /// extensions 1000 to max;
  152. /// }
  153. /// extend Foo {
  154. /// optional int32 baz = 1234;
  155. /// }
  156. /// message Bar {
  157. /// extend Foo {
  158. /// optional int32 qux = 4321;
  159. /// }
  160. /// }
  161. /// </code>
  162. /// The containing type for both <c>baz</c> and <c>qux</c> is <c>Foo</c>.
  163. /// However, the extension scope for <c>baz</c> is <c>null</c> while
  164. /// the extension scope for <c>qux</c> is <c>Bar</c>.
  165. /// </example>
  166. public MessageDescriptor ExtensionScope {
  167. get {
  168. if (!IsExtension) {
  169. throw new InvalidOperationException("This field is not an extension.");
  170. }
  171. return extensionScope;
  172. }
  173. }
  174. public MappedType MappedType {
  175. get { return mappedType; }
  176. }
  177. public FieldType FieldType {
  178. get { return fieldType; }
  179. }
  180. public int FieldNumber {
  181. get { return Proto.Number; }
  182. }
  183. /// <summary>
  184. /// Compares this descriptor with another one, ordering in "canonical" order
  185. /// which simply means ascending order by field number. <paramref name="other"/>
  186. /// must be a field of the same type, i.e. the <see cref="ContainingType"/> of
  187. /// both fields must be the same.
  188. /// </summary>
  189. public int CompareTo(FieldDescriptor other) {
  190. if (other.containingType != containingType) {
  191. throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " +
  192. "for fields of the same message type.");
  193. }
  194. return FieldNumber - other.FieldNumber;
  195. }
  196. /// <summary>
  197. /// For enum fields, returns the field's type.
  198. /// </summary>
  199. public EnumDescriptor EnumType {
  200. get {
  201. if (MappedType != MappedType.Enum) {
  202. throw new InvalidOperationException("EnumType is only valid for enum fields.");
  203. }
  204. return enumType;
  205. }
  206. }
  207. /// <summary>
  208. /// For embedded message and group fields, returns the field's type.
  209. /// </summary>
  210. public MessageDescriptor MessageType {
  211. get {
  212. if (MappedType != MappedType.Message) {
  213. throw new InvalidOperationException("MessageType is only valid for enum fields.");
  214. }
  215. return messageType;
  216. }
  217. }
  218. /// <summary>
  219. /// Immutable mapping from field type to mapped type. Built using the attributes on
  220. /// FieldType values.
  221. /// </summary>
  222. public static readonly IDictionary<FieldType, MappedType> FieldTypeToMappedTypeMap = MapFieldTypes();
  223. private static IDictionary<FieldType, MappedType> MapFieldTypes() {
  224. var map = new Dictionary<FieldType, MappedType>();
  225. foreach (FieldInfo field in typeof(FieldType).GetFields(BindingFlags.Static | BindingFlags.Public)) {
  226. FieldType fieldType = (FieldType)field.GetValue(null);
  227. FieldMappingAttribute mapping = (FieldMappingAttribute)field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0];
  228. map[fieldType] = mapping.MappedType;
  229. }
  230. return Dictionaries.AsReadOnly(map);
  231. }
  232. /// <summary>
  233. /// Look up and cross-link all field types etc.
  234. /// </summary>
  235. internal void CrossLink() {
  236. if (Proto.HasExtendee) {
  237. IDescriptor extendee = File.DescriptorPool.LookupSymbol(Proto.Extendee, this);
  238. if (!(extendee is MessageDescriptor)) {
  239. throw new DescriptorValidationException(this, "\"" + Proto.Extendee + "\" is not a message type.");
  240. }
  241. containingType = (MessageDescriptor) extendee;
  242. if (!containingType.IsExtensionNumber(FieldNumber)) {
  243. throw new DescriptorValidationException(this,
  244. "\"" + containingType.FullName + "\" does not declare " + FieldNumber + " as an extension number.");
  245. }
  246. }
  247. if (Proto.HasTypeName) {
  248. IDescriptor typeDescriptor =
  249. File.DescriptorPool.LookupSymbol(Proto.TypeName, this);
  250. if (!Proto.HasType) {
  251. // Choose field type based on symbol.
  252. if (typeDescriptor is MessageDescriptor) {
  253. fieldType = FieldType.Message;
  254. mappedType = MappedType.Message;
  255. } else if (typeDescriptor is EnumDescriptor) {
  256. fieldType = FieldType.Enum;
  257. mappedType = MappedType.Enum;
  258. } else {
  259. throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not a type.");
  260. }
  261. }
  262. if (MappedType == MappedType.Message) {
  263. if (!(typeDescriptor is MessageDescriptor)) {
  264. throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not a message type.");
  265. }
  266. messageType = (MessageDescriptor) typeDescriptor;
  267. if (Proto.HasDefaultValue) {
  268. throw new DescriptorValidationException(this, "Messages can't have default values.");
  269. }
  270. } else if (MappedType == Descriptors.MappedType.Enum) {
  271. if (!(typeDescriptor is EnumDescriptor)) {
  272. throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not an enum type.");
  273. }
  274. enumType = (EnumDescriptor)typeDescriptor;
  275. } else {
  276. throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
  277. }
  278. } else {
  279. if (MappedType == MappedType.Message || MappedType == MappedType.Enum) {
  280. throw new DescriptorValidationException(this, "Field with message or enum type missing type_name.");
  281. }
  282. }
  283. // We don't attempt to parse the default value until here because for
  284. // enums we need the enum type's descriptor.
  285. if (Proto.HasDefaultValue) {
  286. if (IsRepeated) {
  287. throw new DescriptorValidationException(this, "Repeated fields cannot have default values.");
  288. }
  289. try {
  290. switch (FieldType) {
  291. case FieldType.Int32:
  292. case FieldType.SInt32:
  293. case FieldType.SFixed32:
  294. defaultValue = TextFormat.ParseInt32(Proto.DefaultValue);
  295. break;
  296. case FieldType.UInt32:
  297. case FieldType.Fixed32:
  298. defaultValue = TextFormat.ParseUInt32(Proto.DefaultValue);
  299. break;
  300. case FieldType.Int64:
  301. case FieldType.SInt64:
  302. case FieldType.SFixed64:
  303. defaultValue = TextFormat.ParseInt64(Proto.DefaultValue);
  304. break;
  305. case FieldType.UInt64:
  306. case FieldType.Fixed64:
  307. defaultValue = TextFormat.ParseUInt64(Proto.DefaultValue);
  308. break;
  309. case FieldType.Float:
  310. defaultValue = float.Parse(Proto.DefaultValue);
  311. break;
  312. case FieldType.Double:
  313. defaultValue = double.Parse(Proto.DefaultValue);
  314. break;
  315. case FieldType.Bool:
  316. if (Proto.DefaultValue == "true") {
  317. defaultValue = true;
  318. } else if (Proto.DefaultValue == "false") {
  319. defaultValue = false;
  320. } else {
  321. throw new FormatException("Boolean values must be \"true\" or \"false\"");
  322. }
  323. break;
  324. case FieldType.String:
  325. defaultValue = Proto.DefaultValue;
  326. break;
  327. case FieldType.Bytes:
  328. try {
  329. defaultValue = TextFormat.UnescapeBytes(Proto.DefaultValue);
  330. } catch (FormatException e) {
  331. throw new DescriptorValidationException(this, "Couldn't parse default value: " + e.Message);
  332. }
  333. break;
  334. case FieldType.Enum:
  335. defaultValue = enumType.FindValueByName(Proto.DefaultValue);
  336. if (defaultValue == null) {
  337. throw new DescriptorValidationException(this, "Unknown enum default value: \"" + Proto.DefaultValue + "\"");
  338. }
  339. break;
  340. case FieldType.Message:
  341. case FieldType.Group:
  342. throw new DescriptorValidationException(this, "Message type had default value.");
  343. }
  344. } catch (FormatException e) {
  345. DescriptorValidationException validationException =
  346. new DescriptorValidationException(this, "Could not parse default value: \"" + Proto.DefaultValue + "\"", e);
  347. throw validationException;
  348. }
  349. } else {
  350. // Determine the default default for this field.
  351. if (IsRepeated) {
  352. defaultValue = Lists<object>.Empty;
  353. } else {
  354. switch (MappedType) {
  355. case MappedType.Enum:
  356. // We guarantee elsewhere that an enum type always has at least
  357. // one possible value.
  358. defaultValue = enumType.Values[0];
  359. break;
  360. case MappedType.Message:
  361. defaultValue = null;
  362. break;
  363. default:
  364. defaultValue = GetDefaultValueForMappedType(MappedType);
  365. break;
  366. }
  367. }
  368. }
  369. if (!IsExtension) {
  370. File.DescriptorPool.AddFieldByNumber(this);
  371. }
  372. if (containingType != null && containingType.Options.MessageSetWireFormat) {
  373. if (IsExtension) {
  374. if (!IsOptional || FieldType != FieldType.Message) {
  375. throw new DescriptorValidationException(this, "Extensions of MessageSets must be optional messages.");
  376. }
  377. } else {
  378. throw new DescriptorValidationException(this, "MessageSets cannot have fields, only extensions.");
  379. }
  380. }
  381. }
  382. }
  383. }