Source File
value_union.go
Belonging Package
google.golang.org/protobuf/reflect/protoreflect
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protoreflect
import (
)
// Value is a union where only one Go type may be set at a time.
// The Value is used to represent all possible values a field may take.
// The following shows which Go type is used to represent each proto Kind:
//
// ╔════════════╤═════════════════════════════════════╗
// ║ Go type │ Protobuf kind ║
// ╠════════════╪═════════════════════════════════════╣
// ║ bool │ BoolKind ║
// ║ int32 │ Int32Kind, Sint32Kind, Sfixed32Kind ║
// ║ int64 │ Int64Kind, Sint64Kind, Sfixed64Kind ║
// ║ uint32 │ Uint32Kind, Fixed32Kind ║
// ║ uint64 │ Uint64Kind, Fixed64Kind ║
// ║ float32 │ FloatKind ║
// ║ float64 │ DoubleKind ║
// ║ string │ StringKind ║
// ║ []byte │ BytesKind ║
// ║ EnumNumber │ EnumKind ║
// ║ Message │ MessageKind, GroupKind ║
// ╚════════════╧═════════════════════════════════════╝
//
// Multiple protobuf Kinds may be represented by a single Go type if the type
// can losslessly represent the information for the proto kind. For example,
// Int64Kind, Sint64Kind, and Sfixed64Kind are all represented by int64,
// but use different integer encoding methods.
//
// The List or Map types are used if the field cardinality is repeated.
// A field is a List if FieldDescriptor.IsList reports true.
// A field is a Map if FieldDescriptor.IsMap reports true.
//
// Converting to/from a Value and a concrete Go value panics on type mismatch.
// For example, ValueOf("hello").Int() panics because this attempts to
// retrieve an int64 from a string.
//
// List, Map, and Message Values are called "composite" values.
//
// A composite Value may alias (reference) memory at some location,
// such that changes to the Value updates the that location.
// A composite value acquired with a Mutable method, such as Message.Mutable,
// always references the source object.
//
// For example:
//
// // Append a 0 to a "repeated int32" field.
// // Since the Value returned by Mutable is guaranteed to alias
// // the source message, modifying the Value modifies the message.
// message.Mutable(fieldDesc).(List).Append(protoreflect.ValueOfInt32(0))
//
// // Assign [0] to a "repeated int32" field by creating a new Value,
// // modifying it, and assigning it.
// list := message.NewField(fieldDesc).(List)
// list.Append(protoreflect.ValueOfInt32(0))
// message.Set(fieldDesc, list)
// // ERROR: Since it is not defined whether Set aliases the source,
// // appending to the List here may or may not modify the message.
// list.Append(protoreflect.ValueOfInt32(0))
//
// Some operations, such as Message.Get, may return an "empty, read-only"
// composite Value. Modifying an empty, read-only value panics.
type Value value
// The protoreflect API uses a custom Value union type instead of interface{}
// to keep the future open for performance optimizations. Using an interface{}
// always incurs an allocation for primitives (e.g., int64) since it needs to
// be boxed on the heap (as interfaces can only contain pointers natively).
// Instead, we represent the Value union as a flat struct that internally keeps
// track of which type is set. Using unsafe, the Value union can be reduced
// down to 24B, which is identical in size to a slice.
//
// The latest compiler (Go1.11) currently suffers from some limitations:
// • With inlining, the compiler should be able to statically prove that
// only one of these switch cases are taken and inline one specific case.
// See https://golang.org/issue/22310.
// ValueOf returns a Value initialized with the concrete value stored in v.
// This panics if the type does not match one of the allowed types in the
// Value union.
func ( interface{}) Value {
switch v := .(type) {
case nil:
return Value{}
case bool:
return ValueOfBool()
case int32:
return ValueOfInt32()
case int64:
return ValueOfInt64()
case uint32:
return ValueOfUint32()
case uint64:
return ValueOfUint64()
case float32:
return ValueOfFloat32()
case float64:
return ValueOfFloat64()
case string:
return ValueOfString()
case []byte:
return ValueOfBytes()
case EnumNumber:
return ValueOfEnum()
case Message, List, Map:
return valueOfIface()
case ProtoMessage:
panic(fmt.Sprintf("invalid proto.Message(%T) type, expected a protoreflect.Message type", ))
default:
panic(fmt.Sprintf("invalid type: %T", ))
}
}
// ValueOfBool returns a new boolean value.
func ( bool) Value {
if {
return Value{typ: boolType, num: 1}
} else {
return Value{typ: boolType, num: 0}
}
}
// ValueOfInt32 returns a new int32 value.
func ( int32) Value {
return Value{typ: int32Type, num: uint64()}
}
// ValueOfInt64 returns a new int64 value.
func ( int64) Value {
return Value{typ: int64Type, num: uint64()}
}
// ValueOfUint32 returns a new uint32 value.
func ( uint32) Value {
return Value{typ: uint32Type, num: uint64()}
}
// ValueOfUint64 returns a new uint64 value.
func ( uint64) Value {
return Value{typ: uint64Type, num: }
}
// ValueOfFloat32 returns a new float32 value.
func ( float32) Value {
return Value{typ: float32Type, num: uint64(math.Float64bits(float64()))}
}
// ValueOfFloat64 returns a new float64 value.
func ( float64) Value {
return Value{typ: float64Type, num: uint64(math.Float64bits(float64()))}
}
// ValueOfString returns a new string value.
func ( string) Value {
return valueOfString()
}
// ValueOfBytes returns a new bytes value.
func ( []byte) Value {
return valueOfBytes([:len():len()])
}
// ValueOfEnum returns a new enum value.
func ( EnumNumber) Value {
return Value{typ: enumType, num: uint64()}
}
// ValueOfMessage returns a new Message value.
func ( Message) Value {
return valueOfIface()
}
// ValueOfList returns a new List value.
func ( List) Value {
return valueOfIface()
}
// ValueOfMap returns a new Map value.
func ( Map) Value {
return valueOfIface()
}
// IsValid reports whether v is populated with a value.
func ( Value) () bool {
return .typ != nilType
}
// Interface returns v as an interface{}.
//
// Invariant: v == ValueOf(v).Interface()
func ( Value) () interface{} {
switch .typ {
case nilType:
return nil
case boolType:
return .Bool()
case int32Type:
return int32(.Int())
case int64Type:
return int64(.Int())
case uint32Type:
return uint32(.Uint())
case uint64Type:
return uint64(.Uint())
case float32Type:
return float32(.Float())
case float64Type:
return float64(.Float())
case stringType:
return .String()
case bytesType:
return .Bytes()
case enumType:
return .Enum()
default:
return .getIface()
}
}
func ( Value) () string {
switch .typ {
case nilType:
return "nil"
case boolType:
return "bool"
case int32Type:
return "int32"
case int64Type:
return "int64"
case uint32Type:
return "uint32"
case uint64Type:
return "uint64"
case float32Type:
return "float32"
case float64Type:
return "float64"
case stringType:
return "string"
case bytesType:
return "bytes"
case enumType:
return "enum"
default:
switch v := .getIface().(type) {
case Message:
return "message"
case List:
return "list"
case Map:
return "map"
default:
return fmt.Sprintf("<unknown: %T>", )
}
}
}
func ( Value) ( string) string {
return fmt.Sprintf("type mismatch: cannot convert %v to %s", .typeName(), )
}
// Bool returns v as a bool and panics if the type is not a bool.
func ( Value) () bool {
switch .typ {
case boolType:
return .num > 0
default:
panic(.panicMessage("bool"))
}
}
// Int returns v as a int64 and panics if the type is not a int32 or int64.
func ( Value) () int64 {
switch .typ {
case int32Type, int64Type:
return int64(.num)
default:
panic(.panicMessage("int"))
}
}
// Uint returns v as a uint64 and panics if the type is not a uint32 or uint64.
func ( Value) () uint64 {
switch .typ {
case uint32Type, uint64Type:
return uint64(.num)
default:
panic(.panicMessage("uint"))
}
}
// Float returns v as a float64 and panics if the type is not a float32 or float64.
func ( Value) () float64 {
switch .typ {
case float32Type, float64Type:
return math.Float64frombits(uint64(.num))
default:
panic(.panicMessage("float"))
}
}
// String returns v as a string. Since this method implements fmt.Stringer,
// this returns the formatted string value for any non-string type.
func ( Value) () string {
switch .typ {
case stringType:
return .getString()
default:
return fmt.Sprint(.Interface())
}
}
// Bytes returns v as a []byte and panics if the type is not a []byte.
func ( Value) () []byte {
switch .typ {
case bytesType:
return .getBytes()
default:
panic(.panicMessage("bytes"))
}
}
// Enum returns v as a EnumNumber and panics if the type is not a EnumNumber.
func ( Value) () EnumNumber {
switch .typ {
case enumType:
return EnumNumber(.num)
default:
panic(.panicMessage("enum"))
}
}
// Message returns v as a Message and panics if the type is not a Message.
func ( Value) () Message {
switch vi := .getIface().(type) {
case Message:
return
default:
panic(.panicMessage("message"))
}
}
// List returns v as a List and panics if the type is not a List.
func ( Value) () List {
switch vi := .getIface().(type) {
case List:
return
default:
panic(.panicMessage("list"))
}
}
// Map returns v as a Map and panics if the type is not a Map.
func ( Value) () Map {
switch vi := .getIface().(type) {
case Map:
return
default:
panic(.panicMessage("map"))
}
}
// MapKey returns v as a MapKey and panics for invalid MapKey types.
func ( Value) () MapKey {
switch .typ {
case boolType, int32Type, int64Type, uint32Type, uint64Type, stringType:
return MapKey()
default:
panic(.panicMessage("map key"))
}
}
// MapKey is used to index maps, where the Go type of the MapKey must match
// the specified key Kind (see MessageDescriptor.IsMapEntry).
// The following shows what Go type is used to represent each proto Kind:
//
// ╔═════════╤═════════════════════════════════════╗
// ║ Go type │ Protobuf kind ║
// ╠═════════╪═════════════════════════════════════╣
// ║ bool │ BoolKind ║
// ║ int32 │ Int32Kind, Sint32Kind, Sfixed32Kind ║
// ║ int64 │ Int64Kind, Sint64Kind, Sfixed64Kind ║
// ║ uint32 │ Uint32Kind, Fixed32Kind ║
// ║ uint64 │ Uint64Kind, Fixed64Kind ║
// ║ string │ StringKind ║
// ╚═════════╧═════════════════════════════════════╝
//
// A MapKey is constructed and accessed through a Value:
//
// k := ValueOf("hash").MapKey() // convert string to MapKey
// s := k.String() // convert MapKey to string
//
// The MapKey is a strict subset of valid types used in Value;
// converting a Value to a MapKey with an invalid type panics.
type MapKey value
// IsValid reports whether k is populated with a value.
func ( MapKey) () bool {
return Value().IsValid()
}
// Interface returns k as an interface{}.
func ( MapKey) () interface{} {
return Value().Interface()
}
// Bool returns k as a bool and panics if the type is not a bool.
func ( MapKey) () bool {
return Value().Bool()
}
// Int returns k as a int64 and panics if the type is not a int32 or int64.
func ( MapKey) () int64 {
return Value().Int()
}
// Uint returns k as a uint64 and panics if the type is not a uint32 or uint64.
func ( MapKey) () uint64 {
return Value().Uint()
}
// String returns k as a string. Since this method implements fmt.Stringer,
// this returns the formatted string value for any non-string type.
func ( MapKey) () string {
return Value().String()
}
// Value returns k as a Value.
func ( MapKey) () Value {
return Value()
}
The pages are generated with Golds v0.4.9. (GOOS=linux GOARCH=amd64)