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