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