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.
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.
70 type Value value
71 72 // The protoreflect API uses a custom Value union type instead of any
73 // to keep the future open for performance optimizations. Using an any
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 any) 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 any.
196 //
197 // Invariant: v == ValueOf(v).Interface()
198 func (v Value) Interface() any {
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]:
396 //
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 any.
410 func (k MapKey) Interface() any {
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 }
439