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