FieldDescriptor.cs 16 KB

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