OLD | NEW |
1 #region Copyright notice and license | 1 #region Copyright notice and license |
2 // Protocol Buffers - Google's data interchange format | 2 // Protocol Buffers - Google's data interchange format |
3 // Copyright 2008 Google Inc. All rights reserved. | 3 // Copyright 2008 Google Inc. All rights reserved. |
4 // https://developers.google.com/protocol-buffers/ | 4 // https://developers.google.com/protocol-buffers/ |
5 // | 5 // |
6 // Redistribution and use in source and binary forms, with or without | 6 // Redistribution and use in source and binary forms, with or without |
7 // modification, are permitted provided that the following conditions are | 7 // modification, are permitted provided that the following conditions are |
8 // met: | 8 // met: |
9 // | 9 // |
10 // * Redistributions of source code must retain the above copyright | 10 // * Redistributions of source code must retain the above copyright |
(...skipping 12 matching lines...) Expand all Loading... |
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 #endregion | 31 #endregion |
32 | 32 |
| 33 using Google.Protobuf.Compatibility; |
33 using System; | 34 using System; |
34 using System.Linq; | |
35 using Google.Protobuf.Compatibility; | |
36 | 35 |
37 namespace Google.Protobuf.Reflection | 36 namespace Google.Protobuf.Reflection |
38 { | 37 { |
39 /// <summary> | 38 /// <summary> |
40 /// Descriptor for a field or extension within a message in a .proto file. | 39 /// Descriptor for a field or extension within a message in a .proto file. |
41 /// </summary> | 40 /// </summary> |
42 public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescr
iptor> | 41 public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescr
iptor> |
43 { | 42 { |
44 private readonly FieldDescriptorProto proto; | |
45 private EnumDescriptor enumType; | 43 private EnumDescriptor enumType; |
46 private MessageDescriptor messageType; | 44 private MessageDescriptor messageType; |
47 private readonly MessageDescriptor containingType; | |
48 private readonly OneofDescriptor containingOneof; | |
49 private FieldType fieldType; | 45 private FieldType fieldType; |
50 private readonly string propertyName; // Annoyingly, needed in Crosslink
. | 46 private readonly string propertyName; // Annoyingly, needed in Crosslink
. |
51 private IFieldAccessor accessor; | 47 private IFieldAccessor accessor; |
52 | 48 |
| 49 /// <summary> |
| 50 /// Get the field's containing message type. |
| 51 /// </summary> |
| 52 public MessageDescriptor ContainingType { get; } |
| 53 |
| 54 /// <summary> |
| 55 /// Returns the oneof containing this field, or <c>null</c> if it is not
part of a oneof. |
| 56 /// </summary> |
| 57 public OneofDescriptor ContainingOneof { get; } |
| 58 |
| 59 /// <summary> |
| 60 /// The effective JSON name for this field. This is usually the lower-ca
mel-cased form of the field name, |
| 61 /// but can be overridden using the <c>json_name</c> option in the .prot
o file. |
| 62 /// </summary> |
| 63 public string JsonName { get; } |
| 64 |
| 65 internal FieldDescriptorProto Proto { get; } |
| 66 |
53 internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file
, | 67 internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file
, |
54 MessageDescriptor parent, int index, string pro
pertyName) | 68 MessageDescriptor parent, int index, string pro
pertyName) |
55 : base(file, file.ComputeFullName(parent, proto.Name), index) | 69 : base(file, file.ComputeFullName(parent, proto.Name), index) |
56 { | 70 { |
57 this.proto = proto; | 71 Proto = proto; |
58 if (proto.Type != 0) | 72 if (proto.Type != 0) |
59 { | 73 { |
60 fieldType = GetFieldTypeFromProtoType(proto.Type); | 74 fieldType = GetFieldTypeFromProtoType(proto.Type); |
61 } | 75 } |
62 | 76 |
63 if (FieldNumber <= 0) | 77 if (FieldNumber <= 0) |
64 { | 78 { |
65 throw new DescriptorValidationException(this, "Field numbers mus
t be positive integers."); | 79 throw new DescriptorValidationException(this, "Field numbers mus
t be positive integers."); |
66 } | 80 } |
67 containingType = parent; | 81 ContainingType = parent; |
68 // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnCo
nstruction. | 82 // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnCo
nstruction. |
69 if (proto.OneofIndex != -1) | 83 if (proto.OneofIndex != -1) |
70 { | 84 { |
71 if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.One
ofDecl.Count) | 85 if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.One
ofDecl.Count) |
72 { | 86 { |
73 throw new DescriptorValidationException(this, | 87 throw new DescriptorValidationException(this, |
74 $"FieldDescriptorProto.oneof_index is out of range for t
ype {parent.Name}"); | 88 $"FieldDescriptorProto.oneof_index is out of range for t
ype {parent.Name}"); |
75 } | 89 } |
76 containingOneof = parent.Oneofs[proto.OneofIndex]; | 90 ContainingOneof = parent.Oneofs[proto.OneofIndex]; |
77 } | 91 } |
78 | 92 |
79 file.DescriptorPool.AddSymbol(this); | 93 file.DescriptorPool.AddSymbol(this); |
80 // We can't create the accessor until we've cross-linked, unfortunat
ely, as we | 94 // We can't create the accessor until we've cross-linked, unfortunat
ely, as we |
81 // may not know whether the type of the field is a map or not. Remem
ber the property name | 95 // may not know whether the type of the field is a map or not. Remem
ber the property name |
82 // for later. | 96 // for later. |
83 // We could trust the generated code and check whether the type of t
he property is | 97 // We could trust the generated code and check whether the type of t
he property is |
84 // a MapField, but that feels a tad nasty. | 98 // a MapField, but that feels a tad nasty. |
85 this.propertyName = propertyName; | 99 this.propertyName = propertyName; |
| 100 JsonName = Proto.JsonName == "" ? JsonFormatter.ToCamelCase(Proto.N
ame) : Proto.JsonName; |
86 } | 101 } |
| 102 |
87 | 103 |
88 /// <summary> | 104 /// <summary> |
89 /// The brief name of the descriptor's target. | 105 /// The brief name of the descriptor's target. |
90 /// </summary> | 106 /// </summary> |
91 public override string Name { get { return proto.Name; } } | 107 public override string Name => Proto.Name; |
92 | |
93 internal FieldDescriptorProto Proto { get { return proto; } } | |
94 | 108 |
95 /// <summary> | 109 /// <summary> |
96 /// Returns the accessor for this field. | 110 /// Returns the accessor for this field. |
97 /// </summary> | 111 /// </summary> |
98 /// <remarks> | 112 /// <remarks> |
99 /// <para> | 113 /// <para> |
100 /// While a <see cref="FieldDescriptor"/> describes the field, it does n
ot provide | 114 /// While a <see cref="FieldDescriptor"/> describes the field, it does n
ot provide |
101 /// any way of obtaining or changing the value of the field within a spe
cific message; | 115 /// any way of obtaining or changing the value of the field within a spe
cific message; |
102 /// that is the responsibility of the accessor. | 116 /// that is the responsibility of the accessor. |
103 /// </para> | 117 /// </para> |
104 /// <para> | 118 /// <para> |
105 /// The value returned by this property will be non-null for all regular
fields. However, | 119 /// The value returned by this property will be non-null for all regular
fields. However, |
106 /// if a message containing a map field is introspected, the list of nes
ted messages will include | 120 /// if a message containing a map field is introspected, the list of nes
ted messages will include |
107 /// an auto-generated nested key/value pair message for the field. This
is not represented in any | 121 /// an auto-generated nested key/value pair message for the field. This
is not represented in any |
108 /// generated type, and the value of the map field itself is represented
by a dictionary in the | 122 /// generated type, and the value of the map field itself is represented
by a dictionary in the |
109 /// reflection API. There are never instances of those "hidden" messages
, so no accessor is provided | 123 /// reflection API. There are never instances of those "hidden" messages
, so no accessor is provided |
110 /// and this property will return null. | 124 /// and this property will return null. |
111 /// </para> | 125 /// </para> |
112 /// </remarks> | 126 /// </remarks> |
113 public IFieldAccessor Accessor { get { return accessor; } } | 127 public IFieldAccessor Accessor => accessor; |
114 | 128 |
115 /// <summary> | 129 /// <summary> |
116 /// Maps a field type as included in the .proto file to a FieldType. | 130 /// Maps a field type as included in the .proto file to a FieldType. |
117 /// </summary> | 131 /// </summary> |
118 private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.
Types.Type type) | 132 private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.
Types.Type type) |
119 { | 133 { |
120 switch (type) | 134 switch (type) |
121 { | 135 { |
122 case FieldDescriptorProto.Types.Type.TYPE_DOUBLE: | 136 case FieldDescriptorProto.Types.Type.Double: |
123 return FieldType.Double; | 137 return FieldType.Double; |
124 case FieldDescriptorProto.Types.Type.TYPE_FLOAT: | 138 case FieldDescriptorProto.Types.Type.Float: |
125 return FieldType.Float; | 139 return FieldType.Float; |
126 case FieldDescriptorProto.Types.Type.TYPE_INT64: | 140 case FieldDescriptorProto.Types.Type.Int64: |
127 return FieldType.Int64; | 141 return FieldType.Int64; |
128 case FieldDescriptorProto.Types.Type.TYPE_UINT64: | 142 case FieldDescriptorProto.Types.Type.Uint64: |
129 return FieldType.UInt64; | 143 return FieldType.UInt64; |
130 case FieldDescriptorProto.Types.Type.TYPE_INT32: | 144 case FieldDescriptorProto.Types.Type.Int32: |
131 return FieldType.Int32; | 145 return FieldType.Int32; |
132 case FieldDescriptorProto.Types.Type.TYPE_FIXED64: | 146 case FieldDescriptorProto.Types.Type.Fixed64: |
133 return FieldType.Fixed64; | 147 return FieldType.Fixed64; |
134 case FieldDescriptorProto.Types.Type.TYPE_FIXED32: | 148 case FieldDescriptorProto.Types.Type.Fixed32: |
135 return FieldType.Fixed32; | 149 return FieldType.Fixed32; |
136 case FieldDescriptorProto.Types.Type.TYPE_BOOL: | 150 case FieldDescriptorProto.Types.Type.Bool: |
137 return FieldType.Bool; | 151 return FieldType.Bool; |
138 case FieldDescriptorProto.Types.Type.TYPE_STRING: | 152 case FieldDescriptorProto.Types.Type.String: |
139 return FieldType.String; | 153 return FieldType.String; |
140 case FieldDescriptorProto.Types.Type.TYPE_GROUP: | 154 case FieldDescriptorProto.Types.Type.Group: |
141 return FieldType.Group; | 155 return FieldType.Group; |
142 case FieldDescriptorProto.Types.Type.TYPE_MESSAGE: | 156 case FieldDescriptorProto.Types.Type.Message: |
143 return FieldType.Message; | 157 return FieldType.Message; |
144 case FieldDescriptorProto.Types.Type.TYPE_BYTES: | 158 case FieldDescriptorProto.Types.Type.Bytes: |
145 return FieldType.Bytes; | 159 return FieldType.Bytes; |
146 case FieldDescriptorProto.Types.Type.TYPE_UINT32: | 160 case FieldDescriptorProto.Types.Type.Uint32: |
147 return FieldType.UInt32; | 161 return FieldType.UInt32; |
148 case FieldDescriptorProto.Types.Type.TYPE_ENUM: | 162 case FieldDescriptorProto.Types.Type.Enum: |
149 return FieldType.Enum; | 163 return FieldType.Enum; |
150 case FieldDescriptorProto.Types.Type.TYPE_SFIXED32: | 164 case FieldDescriptorProto.Types.Type.Sfixed32: |
151 return FieldType.SFixed32; | 165 return FieldType.SFixed32; |
152 case FieldDescriptorProto.Types.Type.TYPE_SFIXED64: | 166 case FieldDescriptorProto.Types.Type.Sfixed64: |
153 return FieldType.SFixed64; | 167 return FieldType.SFixed64; |
154 case FieldDescriptorProto.Types.Type.TYPE_SINT32: | 168 case FieldDescriptorProto.Types.Type.Sint32: |
155 return FieldType.SInt32; | 169 return FieldType.SInt32; |
156 case FieldDescriptorProto.Types.Type.TYPE_SINT64: | 170 case FieldDescriptorProto.Types.Type.Sint64: |
157 return FieldType.SInt64; | 171 return FieldType.SInt64; |
158 default: | 172 default: |
159 throw new ArgumentException("Invalid type specified"); | 173 throw new ArgumentException("Invalid type specified"); |
160 } | 174 } |
161 } | 175 } |
162 | 176 |
163 /// <summary> | 177 /// <summary> |
164 /// Returns <c>true</c> if this field is a repeated field; <c>false</c>
otherwise. | 178 /// Returns <c>true</c> if this field is a repeated field; <c>false</c>
otherwise. |
165 /// </summary> | 179 /// </summary> |
166 public bool IsRepeated | 180 public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Labe
l.Repeated; |
167 { | |
168 get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_R
EPEATED; } | |
169 } | |
170 | 181 |
171 /// <summary> | 182 /// <summary> |
172 /// Returns <c>true</c> if this field is a map field; <c>false</c> other
wise. | 183 /// Returns <c>true</c> if this field is a map field; <c>false</c> other
wise. |
173 /// </summary> | 184 /// </summary> |
174 public bool IsMap | 185 public bool IsMap => fieldType == FieldType.Message && messageType.Proto
.Options != null && messageType.Proto.Options.MapEntry; |
175 { | |
176 get { return fieldType == FieldType.Message && messageType.Proto.Opt
ions != null && messageType.Proto.Options.MapEntry; } | |
177 } | |
178 | 186 |
179 /// <summary> | 187 /// <summary> |
180 /// Returns <c>true</c> if this field is a packed, repeated field; <c>fa
lse</c> otherwise. | 188 /// Returns <c>true</c> if this field is a packed, repeated field; <c>fa
lse</c> otherwise. |
181 /// </summary> | 189 /// </summary> |
182 public bool IsPacked | 190 public bool IsPacked => |
183 { | |
184 // Note the || rather than && here - we're effectively defaulting to
packed, because that *is* | 191 // Note the || rather than && here - we're effectively defaulting to
packed, because that *is* |
185 // the default in proto3, which is all we support. We may give the w
rong result for the protos | 192 // the default in proto3, which is all we support. We may give the w
rong result for the protos |
186 // within descriptor.proto, but that's okay, as they're never expose
d and we don't use IsPacked | 193 // within descriptor.proto, but that's okay, as they're never expose
d and we don't use IsPacked |
187 // within the runtime. | 194 // within the runtime. |
188 get { return Proto.Options == null || Proto.Options.Packed; } | 195 Proto.Options == null || Proto.Options.Packed; |
189 } | 196 |
190 | |
191 /// <summary> | |
192 /// Get the field's containing message type. | |
193 /// </summary> | |
194 public MessageDescriptor ContainingType | |
195 { | |
196 get { return containingType; } | |
197 } | |
198 | |
199 /// <summary> | |
200 /// Returns the oneof containing this field, or <c>null</c> if it is not
part of a oneof. | |
201 /// </summary> | |
202 public OneofDescriptor ContainingOneof | |
203 { | |
204 get { return containingOneof; } | |
205 } | |
206 | |
207 /// <summary> | 197 /// <summary> |
208 /// Returns the type of the field. | 198 /// Returns the type of the field. |
209 /// </summary> | 199 /// </summary> |
210 public FieldType FieldType | 200 public FieldType FieldType => fieldType; |
211 { | |
212 get { return fieldType; } | |
213 } | |
214 | 201 |
215 /// <summary> | 202 /// <summary> |
216 /// Returns the field number declared in the proto file. | 203 /// Returns the field number declared in the proto file. |
217 /// </summary> | 204 /// </summary> |
218 public int FieldNumber | 205 public int FieldNumber => Proto.Number; |
219 { | |
220 get { return Proto.Number; } | |
221 } | |
222 | 206 |
223 /// <summary> | 207 /// <summary> |
224 /// Compares this descriptor with another one, ordering in "canonical" o
rder | 208 /// Compares this descriptor with another one, ordering in "canonical" o
rder |
225 /// which simply means ascending order by field number. <paramref name="
other"/> | 209 /// which simply means ascending order by field number. <paramref name="
other"/> |
226 /// must be a field of the same type, i.e. the <see cref="ContainingType
"/> of | 210 /// must be a field of the same type, i.e. the <see cref="ContainingType
"/> of |
227 /// both fields must be the same. | 211 /// both fields must be the same. |
228 /// </summary> | 212 /// </summary> |
229 public int CompareTo(FieldDescriptor other) | 213 public int CompareTo(FieldDescriptor other) |
230 { | 214 { |
231 if (other.containingType != containingType) | 215 if (other.ContainingType != ContainingType) |
232 { | 216 { |
233 throw new ArgumentException("FieldDescriptors can only be compar
ed to other FieldDescriptors " + | 217 throw new ArgumentException("FieldDescriptors can only be compar
ed to other FieldDescriptors " + |
234 "for fields of the same message type
."); | 218 "for fields of the same message type
."); |
235 } | 219 } |
236 return FieldNumber - other.FieldNumber; | 220 return FieldNumber - other.FieldNumber; |
237 } | 221 } |
238 | 222 |
239 /// <summary> | 223 /// <summary> |
240 /// For enum fields, returns the field's type. | 224 /// For enum fields, returns the field's type. |
241 /// </summary> | 225 /// </summary> |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 if (fieldType == FieldType.Message || fieldType == FieldType.Enu
m) | 308 if (fieldType == FieldType.Message || fieldType == FieldType.Enu
m) |
325 { | 309 { |
326 throw new DescriptorValidationException(this, "Field with me
ssage or enum type missing type_name."); | 310 throw new DescriptorValidationException(this, "Field with me
ssage or enum type missing type_name."); |
327 } | 311 } |
328 } | 312 } |
329 | 313 |
330 // Note: no attempt to perform any default value parsing | 314 // Note: no attempt to perform any default value parsing |
331 | 315 |
332 File.DescriptorPool.AddFieldByNumber(this); | 316 File.DescriptorPool.AddFieldByNumber(this); |
333 | 317 |
334 if (containingType != null && containingType.Proto.Options != null &
& containingType.Proto.Options.MessageSetWireFormat) | 318 if (ContainingType != null && ContainingType.Proto.Options != null &
& ContainingType.Proto.Options.MessageSetWireFormat) |
335 { | 319 { |
336 throw new DescriptorValidationException(this, "MessageSet format
is not supported."); | 320 throw new DescriptorValidationException(this, "MessageSet format
is not supported."); |
337 } | 321 } |
338 accessor = CreateAccessor(propertyName); | 322 accessor = CreateAccessor(); |
339 } | 323 } |
340 | 324 |
341 private IFieldAccessor CreateAccessor(string propertyName) | 325 private IFieldAccessor CreateAccessor() |
342 { | 326 { |
343 // If we're given no property name, that's because we really don't w
ant an accessor. | 327 // If we're given no property name, that's because we really don't w
ant an accessor. |
344 // (At the moment, that means it's a map entry message...) | 328 // (At the moment, that means it's a map entry message...) |
345 if (propertyName == null) | 329 if (propertyName == null) |
346 { | 330 { |
347 return null; | 331 return null; |
348 } | 332 } |
349 var property = containingType.ClrType.GetProperty(propertyName); | 333 var property = ContainingType.ClrType.GetProperty(propertyName); |
350 if (property == null) | 334 if (property == null) |
351 { | 335 { |
352 throw new DescriptorValidationException(this, $"Property {proper
tyName} not found in {containingType.ClrType}"); | 336 throw new DescriptorValidationException(this, $"Property {proper
tyName} not found in {ContainingType.ClrType}"); |
353 } | 337 } |
354 return IsMap ? new MapFieldAccessor(property, this) | 338 return IsMap ? new MapFieldAccessor(property, this) |
355 : IsRepeated ? new RepeatedFieldAccessor(property, this) | 339 : IsRepeated ? new RepeatedFieldAccessor(property, this) |
356 : (IFieldAccessor) new SingleFieldAccessor(property, this); | 340 : (IFieldAccessor) new SingleFieldAccessor(property, this); |
357 } | 341 } |
358 } | 342 } |
359 } | 343 } |
OLD | NEW |