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