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 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} 368