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// 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. 70type Value value 71 72// The protoreflect API uses a custom Value union type instead of interface{} 73// to keep the future open for performance optimizations. Using an interface{} 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. 88func ValueOf(v interface{}) 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. 122func 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. 131func ValueOfInt32(v int32) Value { 132 return Value{typ: int32Type, num: uint64(v)} 133} 134 135// ValueOfInt64 returns a new int64 value. 136func ValueOfInt64(v int64) Value { 137 return Value{typ: int64Type, num: uint64(v)} 138} 139 140// ValueOfUint32 returns a new uint32 value. 141func ValueOfUint32(v uint32) Value { 142 return Value{typ: uint32Type, num: uint64(v)} 143} 144 145// ValueOfUint64 returns a new uint64 value. 146func ValueOfUint64(v uint64) Value { 147 return Value{typ: uint64Type, num: v} 148} 149 150// ValueOfFloat32 returns a new float32 value. 151func ValueOfFloat32(v float32) Value { 152 return Value{typ: float32Type, num: uint64(math.Float64bits(float64(v)))} 153} 154 155// ValueOfFloat64 returns a new float64 value. 156func ValueOfFloat64(v float64) Value { 157 return Value{typ: float64Type, num: uint64(math.Float64bits(float64(v)))} 158} 159 160// ValueOfString returns a new string value. 161func ValueOfString(v string) Value { 162 return valueOfString(v) 163} 164 165// ValueOfBytes returns a new bytes value. 166func ValueOfBytes(v []byte) Value { 167 return valueOfBytes(v[:len(v):len(v)]) 168} 169 170// ValueOfEnum returns a new enum value. 171func ValueOfEnum(v EnumNumber) Value { 172 return Value{typ: enumType, num: uint64(v)} 173} 174 175// ValueOfMessage returns a new Message value. 176func ValueOfMessage(v Message) Value { 177 return valueOfIface(v) 178} 179 180// ValueOfList returns a new List value. 181func ValueOfList(v List) Value { 182 return valueOfIface(v) 183} 184 185// ValueOfMap returns a new Map value. 186func ValueOfMap(v Map) Value { 187 return valueOfIface(v) 188} 189 190// IsValid reports whether v is populated with a value. 191func (v Value) IsValid() bool { 192 return v.typ != nilType 193} 194 195// Interface returns v as an interface{}. 196// 197// Invariant: v == ValueOf(v).Interface() 198func (v Value) Interface() interface{} { 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 227func (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 265func (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. 270func (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. 280func (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. 290func (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. 300func (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. 311func (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. 321func (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. 331func (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. 341func (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. 351func (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. 361func (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. 371func (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. 402type MapKey value 403 404// IsValid reports whether k is populated with a value. 405func (k MapKey) IsValid() bool { 406 return Value(k).IsValid() 407} 408 409// Interface returns k as an interface{}. 410func (k MapKey) Interface() interface{} { 411 return Value(k).Interface() 412} 413 414// Bool returns k as a bool and panics if the type is not a bool. 415func (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. 420func (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. 425func (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. 431func (k MapKey) String() string { 432 return Value(k).String() 433} 434 435// Value returns k as a Value. 436func (k MapKey) Value() Value { 437 return Value(k) 438} 439