256
|
1 |
// Copyright 2018 The Go Authors. All rights reserved. |
|
2 |
// Use of this source code is governed by a BSD-style |
|
3 |
// license that can be found in the LICENSE file. |
|
4 |
|
|
5 |
package protoreflect |
|
6 |
|
|
7 |
import ( |
|
8 |
"fmt" |
|
9 |
"math" |
|
10 |
) |
|
11 |
|
|
12 |
// Value is a union where only one Go type may be set at a time. |
|
13 |
// The Value is used to represent all possible values a field may take. |
|
14 |
// The following shows which Go type is used to represent each proto Kind: |
|
15 |
// |
|
16 |
// ╔════════════╤═════════════════════════════════════╗ |
|
17 |
// ║ Go type │ Protobuf kind ║ |
|
18 |
// ╠════════════╪═════════════════════════════════════╣ |
|
19 |
// ║ bool │ BoolKind ║ |
|
20 |
// ║ int32 │ Int32Kind, Sint32Kind, Sfixed32Kind ║ |
|
21 |
// ║ int64 │ Int64Kind, Sint64Kind, Sfixed64Kind ║ |
|
22 |
// ║ uint32 │ Uint32Kind, Fixed32Kind ║ |
|
23 |
// ║ uint64 │ Uint64Kind, Fixed64Kind ║ |
|
24 |
// ║ float32 │ FloatKind ║ |
|
25 |
// ║ float64 │ DoubleKind ║ |
|
26 |
// ║ string │ StringKind ║ |
|
27 |
// ║ []byte │ BytesKind ║ |
|
28 |
// ║ EnumNumber │ EnumKind ║ |
|
29 |
// ║ Message │ MessageKind, GroupKind ║ |
|
30 |
// ╚════════════╧═════════════════════════════════════╝ |
|
31 |
// |
|
32 |
// Multiple protobuf Kinds may be represented by a single Go type if the type |
|
33 |
// can losslessly represent the information for the proto kind. For example, |
|
34 |
// Int64Kind, Sint64Kind, and Sfixed64Kind are all represented by int64, |
|
35 |
// but use different integer encoding methods. |
|
36 |
// |
|
37 |
// The List or Map types are used if the field cardinality is repeated. |
|
38 |
// A field is a List if FieldDescriptor.IsList reports true. |
|
39 |
// A field is a Map if FieldDescriptor.IsMap reports true. |
|
40 |
// |
|
41 |
// Converting to/from a Value and a concrete Go value panics on type mismatch. |
|
42 |
// For example, ValueOf("hello").Int() panics because this attempts to |
|
43 |
// retrieve an int64 from a string. |
260
|
44 |
// |
|
45 |
// List, Map, and Message Values are called "composite" values. |
|
46 |
// |
|
47 |
// A composite Value may alias (reference) memory at some location, |
|
48 |
// such that changes to the Value updates the that location. |
|
49 |
// A composite value acquired with a Mutable method, such as Message.Mutable, |
|
50 |
// always references the source object. |
|
51 |
// |
|
52 |
// For example: |
|
53 |
// |
|
54 |
// // Append a 0 to a "repeated int32" field. |
|
55 |
// // Since the Value returned by Mutable is guaranteed to alias |
|
56 |
// // the source message, modifying the Value modifies the message. |
|
57 |
// message.Mutable(fieldDesc).(List).Append(protoreflect.ValueOfInt32(0)) |
|
58 |
// |
|
59 |
// // Assign [0] to a "repeated int32" field by creating a new Value, |
|
60 |
// // modifying it, and assigning it. |
|
61 |
// list := message.NewField(fieldDesc).(List) |
|
62 |
// list.Append(protoreflect.ValueOfInt32(0)) |
|
63 |
// message.Set(fieldDesc, list) |
|
64 |
// // ERROR: Since it is not defined whether Set aliases the source, |
|
65 |
// // appending to the List here may or may not modify the message. |
|
66 |
// list.Append(protoreflect.ValueOfInt32(0)) |
|
67 |
// |
|
68 |
// Some operations, such as Message.Get, may return an "empty, read-only" |
|
69 |
// composite Value. Modifying an empty, read-only value panics. |
256
|
70 |
type Value value |
|
71 |
|
|
72 |
// The protoreflect API uses a custom Value union type instead of interface{} |
|
73 |
// to keep the future open for performance optimizations. Using an interface{} |
|
74 |
// always incurs an allocation for primitives (e.g., int64) since it needs to |
|
75 |
// be boxed on the heap (as interfaces can only contain pointers natively). |
|
76 |
// Instead, we represent the Value union as a flat struct that internally keeps |
|
77 |
// track of which type is set. Using unsafe, the Value union can be reduced |
|
78 |
// down to 24B, which is identical in size to a slice. |
|
79 |
// |
|
80 |
// The latest compiler (Go1.11) currently suffers from some limitations: |
|
81 |
// • With inlining, the compiler should be able to statically prove that |
|
82 |
// only one of these switch cases are taken and inline one specific case. |
|
83 |
// See https://golang.org/issue/22310. |
|
84 |
|
|
85 |
// ValueOf returns a Value initialized with the concrete value stored in v. |
|
86 |
// This panics if the type does not match one of the allowed types in the |
|
87 |
// Value union. |
|
88 |
func ValueOf(v interface{}) Value { |
|
89 |
switch v := v.(type) { |
|
90 |
case nil: |
|
91 |
return Value{} |
|
92 |
case bool: |
|
93 |
return ValueOfBool(v) |
|
94 |
case int32: |
|
95 |
return ValueOfInt32(v) |
|
96 |
case int64: |
|
97 |
return ValueOfInt64(v) |
|
98 |
case uint32: |
|
99 |
return ValueOfUint32(v) |
|
100 |
case uint64: |
|
101 |
return ValueOfUint64(v) |
|
102 |
case float32: |
|
103 |
return ValueOfFloat32(v) |
|
104 |
case float64: |
|
105 |
return ValueOfFloat64(v) |
|
106 |
case string: |
|
107 |
return ValueOfString(v) |
|
108 |
case []byte: |
|
109 |
return ValueOfBytes(v) |
|
110 |
case EnumNumber: |
|
111 |
return ValueOfEnum(v) |
|
112 |
case Message, List, Map: |
|
113 |
return valueOfIface(v) |
|
114 |
case ProtoMessage: |
|
115 |
panic(fmt.Sprintf("invalid proto.Message(%T) type, expected a protoreflect.Message type", v)) |
|
116 |
default: |
|
117 |
panic(fmt.Sprintf("invalid type: %T", v)) |
|
118 |
} |
|
119 |
} |
|
120 |
|
|
121 |
// ValueOfBool returns a new boolean value. |
|
122 |
func ValueOfBool(v bool) Value { |
|
123 |
if v { |
|
124 |
return Value{typ: boolType, num: 1} |
|
125 |
} else { |
|
126 |
return Value{typ: boolType, num: 0} |
|
127 |
} |
|
128 |
} |
|
129 |
|
|
130 |
// ValueOfInt32 returns a new int32 value. |
|
131 |
func ValueOfInt32(v int32) Value { |
|
132 |
return Value{typ: int32Type, num: uint64(v)} |
|
133 |
} |
|
134 |
|
|
135 |
// ValueOfInt64 returns a new int64 value. |
|
136 |
func ValueOfInt64(v int64) Value { |
|
137 |
return Value{typ: int64Type, num: uint64(v)} |
|
138 |
} |
|
139 |
|
|
140 |
// ValueOfUint32 returns a new uint32 value. |
|
141 |
func ValueOfUint32(v uint32) Value { |
|
142 |
return Value{typ: uint32Type, num: uint64(v)} |
|
143 |
} |
|
144 |
|
|
145 |
// ValueOfUint64 returns a new uint64 value. |
|
146 |
func ValueOfUint64(v uint64) Value { |
|
147 |
return Value{typ: uint64Type, num: v} |
|
148 |
} |
|
149 |
|
|
150 |
// ValueOfFloat32 returns a new float32 value. |
|
151 |
func ValueOfFloat32(v float32) Value { |
|
152 |
return Value{typ: float32Type, num: uint64(math.Float64bits(float64(v)))} |
|
153 |
} |
|
154 |
|
|
155 |
// ValueOfFloat64 returns a new float64 value. |
|
156 |
func ValueOfFloat64(v float64) Value { |
|
157 |
return Value{typ: float64Type, num: uint64(math.Float64bits(float64(v)))} |
|
158 |
} |
|
159 |
|
|
160 |
// ValueOfString returns a new string value. |
|
161 |
func ValueOfString(v string) Value { |
|
162 |
return valueOfString(v) |
|
163 |
} |
|
164 |
|
|
165 |
// ValueOfBytes returns a new bytes value. |
|
166 |
func ValueOfBytes(v []byte) Value { |
|
167 |
return valueOfBytes(v[:len(v):len(v)]) |
|
168 |
} |
|
169 |
|
|
170 |
// ValueOfEnum returns a new enum value. |
|
171 |
func ValueOfEnum(v EnumNumber) Value { |
|
172 |
return Value{typ: enumType, num: uint64(v)} |
|
173 |
} |
|
174 |
|
|
175 |
// ValueOfMessage returns a new Message value. |
|
176 |
func ValueOfMessage(v Message) Value { |
|
177 |
return valueOfIface(v) |
|
178 |
} |
|
179 |
|
|
180 |
// ValueOfList returns a new List value. |
|
181 |
func ValueOfList(v List) Value { |
|
182 |
return valueOfIface(v) |
|
183 |
} |
|
184 |
|
|
185 |
// ValueOfMap returns a new Map value. |
|
186 |
func ValueOfMap(v Map) Value { |
|
187 |
return valueOfIface(v) |
|
188 |
} |
|
189 |
|
|
190 |
// IsValid reports whether v is populated with a value. |
|
191 |
func (v Value) IsValid() bool { |
|
192 |
return v.typ != nilType |
|
193 |
} |
|
194 |
|
|
195 |
// Interface returns v as an interface{}. |
|
196 |
// |
|
197 |
// Invariant: v == ValueOf(v).Interface() |
|
198 |
func (v Value) Interface() interface{} { |
|
199 |
switch v.typ { |
|
200 |
case nilType: |
|
201 |
return nil |
|
202 |
case boolType: |
|
203 |
return v.Bool() |
|
204 |
case int32Type: |
|
205 |
return int32(v.Int()) |
|
206 |
case int64Type: |
|
207 |
return int64(v.Int()) |
|
208 |
case uint32Type: |
|
209 |
return uint32(v.Uint()) |
|
210 |
case uint64Type: |
|
211 |
return uint64(v.Uint()) |
|
212 |
case float32Type: |
|
213 |
return float32(v.Float()) |
|
214 |
case float64Type: |
|
215 |
return float64(v.Float()) |
|
216 |
case stringType: |
|
217 |
return v.String() |
|
218 |
case bytesType: |
|
219 |
return v.Bytes() |
|
220 |
case enumType: |
|
221 |
return v.Enum() |
|
222 |
default: |
|
223 |
return v.getIface() |
|
224 |
} |
|
225 |
} |
|
226 |
|
|
227 |
func (v Value) typeName() string { |
|
228 |
switch v.typ { |
|
229 |
case nilType: |
|
230 |
return "nil" |
|
231 |
case boolType: |
|
232 |
return "bool" |
|
233 |
case int32Type: |
|
234 |
return "int32" |
|
235 |
case int64Type: |
|
236 |
return "int64" |
|
237 |
case uint32Type: |
|
238 |
return "uint32" |
|
239 |
case uint64Type: |
|
240 |
return "uint64" |
|
241 |
case float32Type: |
|
242 |
return "float32" |
|
243 |
case float64Type: |
|
244 |
return "float64" |
|
245 |
case stringType: |
|
246 |
return "string" |
|
247 |
case bytesType: |
|
248 |
return "bytes" |
|
249 |
case enumType: |
|
250 |
return "enum" |
|
251 |
default: |
|
252 |
switch v := v.getIface().(type) { |
|
253 |
case Message: |
|
254 |
return "message" |
|
255 |
case List: |
|
256 |
return "list" |
|
257 |
case Map: |
|
258 |
return "map" |
|
259 |
default: |
|
260 |
return fmt.Sprintf("<unknown: %T>", v) |
|
261 |
} |
|
262 |
} |
|
263 |
} |
|
264 |
|
|
265 |
func (v Value) panicMessage(what string) string { |
|
266 |
return fmt.Sprintf("type mismatch: cannot convert %v to %s", v.typeName(), what) |
|
267 |
} |
|
268 |
|
|
269 |
// Bool returns v as a bool and panics if the type is not a bool. |
|
270 |
func (v Value) Bool() bool { |
|
271 |
switch v.typ { |
|
272 |
case boolType: |
|
273 |
return v.num > 0 |
|
274 |
default: |
|
275 |
panic(v.panicMessage("bool")) |
|
276 |
} |
|
277 |
} |
|
278 |
|
|
279 |
// Int returns v as a int64 and panics if the type is not a int32 or int64. |
|
280 |
func (v Value) Int() int64 { |
|
281 |
switch v.typ { |
|
282 |
case int32Type, int64Type: |
|
283 |
return int64(v.num) |
|
284 |
default: |
|
285 |
panic(v.panicMessage("int")) |
|
286 |
} |
|
287 |
} |
|
288 |
|
|
289 |
// Uint returns v as a uint64 and panics if the type is not a uint32 or uint64. |
|
290 |
func (v Value) Uint() uint64 { |
|
291 |
switch v.typ { |
|
292 |
case uint32Type, uint64Type: |
|
293 |
return uint64(v.num) |
|
294 |
default: |
|
295 |
panic(v.panicMessage("uint")) |
|
296 |
} |
|
297 |
} |
|
298 |
|
|
299 |
// Float returns v as a float64 and panics if the type is not a float32 or float64. |
|
300 |
func (v Value) Float() float64 { |
|
301 |
switch v.typ { |
|
302 |
case float32Type, float64Type: |
|
303 |
return math.Float64frombits(uint64(v.num)) |
|
304 |
default: |
|
305 |
panic(v.panicMessage("float")) |
|
306 |
} |
|
307 |
} |
|
308 |
|
|
309 |
// String returns v as a string. Since this method implements fmt.Stringer, |
|
310 |
// this returns the formatted string value for any non-string type. |
|
311 |
func (v Value) String() string { |
|
312 |
switch v.typ { |
|
313 |
case stringType: |
|
314 |
return v.getString() |
|
315 |
default: |
|
316 |
return fmt.Sprint(v.Interface()) |
|
317 |
} |
|
318 |
} |
|
319 |
|
|
320 |
// Bytes returns v as a []byte and panics if the type is not a []byte. |
|
321 |
func (v Value) Bytes() []byte { |
|
322 |
switch v.typ { |
|
323 |
case bytesType: |
|
324 |
return v.getBytes() |
|
325 |
default: |
|
326 |
panic(v.panicMessage("bytes")) |
|
327 |
} |
|
328 |
} |
|
329 |
|
|
330 |
// Enum returns v as a EnumNumber and panics if the type is not a EnumNumber. |
|
331 |
func (v Value) Enum() EnumNumber { |
|
332 |
switch v.typ { |
|
333 |
case enumType: |
|
334 |
return EnumNumber(v.num) |
|
335 |
default: |
|
336 |
panic(v.panicMessage("enum")) |
|
337 |
} |
|
338 |
} |
|
339 |
|
|
340 |
// Message returns v as a Message and panics if the type is not a Message. |
|
341 |
func (v Value) Message() Message { |
|
342 |
switch vi := v.getIface().(type) { |
|
343 |
case Message: |
|
344 |
return vi |
|
345 |
default: |
|
346 |
panic(v.panicMessage("message")) |
|
347 |
} |
|
348 |
} |
|
349 |
|
|
350 |
// List returns v as a List and panics if the type is not a List. |
|
351 |
func (v Value) List() List { |
|
352 |
switch vi := v.getIface().(type) { |
|
353 |
case List: |
|
354 |
return vi |
|
355 |
default: |
|
356 |
panic(v.panicMessage("list")) |
|
357 |
} |
|
358 |
} |
|
359 |
|
|
360 |
// Map returns v as a Map and panics if the type is not a Map. |
|
361 |
func (v Value) Map() Map { |
|
362 |
switch vi := v.getIface().(type) { |
|
363 |
case Map: |
|
364 |
return vi |
|
365 |
default: |
|
366 |
panic(v.panicMessage("map")) |
|
367 |
} |
|
368 |
} |
|
369 |
|
|
370 |
// MapKey returns v as a MapKey and panics for invalid MapKey types. |
|
371 |
func (v Value) MapKey() MapKey { |
|
372 |
switch v.typ { |
|
373 |
case boolType, int32Type, int64Type, uint32Type, uint64Type, stringType: |
|
374 |
return MapKey(v) |
|
375 |
default: |
|
376 |
panic(v.panicMessage("map key")) |
|
377 |
} |
|
378 |
} |
|
379 |
|
|
380 |
// MapKey is used to index maps, where the Go type of the MapKey must match |
|
381 |
// the specified key Kind (see MessageDescriptor.IsMapEntry). |
|
382 |
// The following shows what Go type is used to represent each proto Kind: |
|
383 |
// |
|
384 |
// ╔═════════╤═════════════════════════════════════╗ |
|
385 |
// ║ Go type │ Protobuf kind ║ |
|
386 |
// ╠═════════╪═════════════════════════════════════╣ |
|
387 |
// ║ bool │ BoolKind ║ |
|
388 |
// ║ int32 │ Int32Kind, Sint32Kind, Sfixed32Kind ║ |
|
389 |
// ║ int64 │ Int64Kind, Sint64Kind, Sfixed64Kind ║ |
|
390 |
// ║ uint32 │ Uint32Kind, Fixed32Kind ║ |
|
391 |
// ║ uint64 │ Uint64Kind, Fixed64Kind ║ |
|
392 |
// ║ string │ StringKind ║ |
|
393 |
// ╚═════════╧═════════════════════════════════════╝ |
|
394 |
// |
|
395 |
// A MapKey is constructed and accessed through a Value: |
260
|
396 |
// |
256
|
397 |
// k := ValueOf("hash").MapKey() // convert string to MapKey |
|
398 |
// s := k.String() // convert MapKey to string |
|
399 |
// |
|
400 |
// The MapKey is a strict subset of valid types used in Value; |
|
401 |
// converting a Value to a MapKey with an invalid type panics. |
|
402 |
type MapKey value |
|
403 |
|
|
404 |
// IsValid reports whether k is populated with a value. |
|
405 |
func (k MapKey) IsValid() bool { |
|
406 |
return Value(k).IsValid() |
|
407 |
} |
|
408 |
|
|
409 |
// Interface returns k as an interface{}. |
|
410 |
func (k MapKey) Interface() interface{} { |
|
411 |
return Value(k).Interface() |
|
412 |
} |
|
413 |
|
|
414 |
// Bool returns k as a bool and panics if the type is not a bool. |
|
415 |
func (k MapKey) Bool() bool { |
|
416 |
return Value(k).Bool() |
|
417 |
} |
|
418 |
|
|
419 |
// Int returns k as a int64 and panics if the type is not a int32 or int64. |
|
420 |
func (k MapKey) Int() int64 { |
|
421 |
return Value(k).Int() |
|
422 |
} |
|
423 |
|
|
424 |
// Uint returns k as a uint64 and panics if the type is not a uint32 or uint64. |
|
425 |
func (k MapKey) Uint() uint64 { |
|
426 |
return Value(k).Uint() |
|
427 |
} |
|
428 |
|
|
429 |
// String returns k as a string. Since this method implements fmt.Stringer, |
|
430 |
// this returns the formatted string value for any non-string type. |
|
431 |
func (k MapKey) String() string { |
|
432 |
return Value(k).String() |
|
433 |
} |
|
434 |
|
|
435 |
// Value returns k as a Value. |
|
436 |
func (k MapKey) Value() Value { |
|
437 |
return Value(k) |
|
438 |
} |