...

Source file src/google.golang.org/protobuf/reflect/protoreflect/value_union.go

Documentation: google.golang.org/protobuf/reflect/protoreflect

     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  

View as plain text