Documentation
¶
Overview ¶
Package protoreflect provides the runtime reflection layer that bridges protobuf descriptors (schema) and message instances (data). It enables reading and writing message fields by descriptor, iterating over populated fields, and accessing oneof and map fields dynamically, without compile-time knowledge of the message schema.
The central type is Value, a tagged-union struct that can hold any protobuf value. Value stores scalar types (bool, int32, int64, uint32, uint64, float32, float64, enum) inline using fixed-width fields, achieving zero-allocation construction on hot paths. Strings are stored in a dedicated field. Reference types (bytes, message, list, map) are stored in a single interface{} field. The zero value of Value is invalid by design.
Kind is a small enum that discriminates the 13 possible value types stored in a Value. EnumNumber is a named int32 type representing a protobuf enum value number, providing type safety in Value constructors and accessors. MapKey wraps a Value restricted to the protobuf-legal map key types (bool, int32, int64, uint32, uint64, string) and panics on construction with any other kind.
Three interfaces define the reflection contracts for composite protobuf types:
Message provides dynamic access to message fields by descriptor, including Get, Set, Has, Clear, Range, and WhichOneof. It also exposes the message's schema via Descriptor and unknown field bytes via GetUnknown/SetUnknown.
List provides indexed access to repeated field elements with Get, Set, Append, and Truncate, following Go slice semantics.
Map provides key-based access to map field entries with Get, Set, Has, Clear, and Range, following Go map semantics with undefined iteration order.
These three interfaces are definition-only in this package. Concrete implementations are provided by generated code and the dynamic message package.
ProtoMessage is the marker interface that generated Go message types satisfy. Its single method, ProtoReflect, returns a Message, forming the bridge between concrete generated types and the reflection API.
Accessor methods on Value and MapKey panic on type mismatch rather than returning errors, following the project convention that programmer errors are signaled by panics. All panic messages are prefixed with "protoreflect: " for easy identification (e.g., "protoreflect: Value.Int32: type mismatch, have bool").
This package consumes the descriptor package for field, message, and oneof descriptor accessor interfaces (FieldDescriptorAccessor, MessageDescriptorAccessor, OneofDescriptorAccessor). The proto package defines MessageReflection as a type alias for protoreflect.Message, allowing the ProtoReflector interface in proto to return the full reflection contract without a circular dependency.
This package depends on fmt and math from the standard library and on descriptor from the module. It has zero external dependencies.
Index ¶
- type EnumNumber
- type Kind
- type List
- type Map
- type MapKey
- type Message
- type ProtoMessage
- type Value
- func ValueOfBool(v bool) Value
- func ValueOfBytes(v []byte) Value
- func ValueOfEnum(v EnumNumber) Value
- func ValueOfFloat32(v float32) Value
- func ValueOfFloat64(v float64) Value
- func ValueOfInt32(v int32) Value
- func ValueOfInt64(v int64) Value
- func ValueOfList(v List) Value
- func ValueOfMap(v Map) Value
- func ValueOfMessage(v Message) Value
- func ValueOfString(v string) Value
- func ValueOfUint32(v uint32) Value
- func ValueOfUint64(v uint64) Value
- func (v Value) Bool() bool
- func (v Value) Bytes() []byte
- func (v Value) Enum() EnumNumber
- func (v Value) Float32() float32
- func (v Value) Float64() float64
- func (v Value) Int32() int32
- func (v Value) Int64() int64
- func (v Value) Interface() interface{}
- func (v Value) IsValid() bool
- func (v Value) Kind() Kind
- func (v Value) List() List
- func (v Value) Map() Map
- func (v Value) Message() Message
- func (v Value) String() string
- func (v Value) Uint32() uint32
- func (v Value) Uint64() uint64
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type EnumNumber ¶
type EnumNumber int32
EnumNumber represents a protobuf enum value number for dynamic access. It is a named type over int32 to provide type safety in Value constructors and accessors.
type Kind ¶
type Kind int8
Kind represents the type discriminator for a protoreflect Value. It distinguishes the 13 possible value kinds stored in the tagged-union Value struct. The zero value is intentionally invalid.
const ( KindBool Kind = iota + 1 // 1 KindInt32 // 2 KindInt64 // 3 KindUint32 // 4 KindUint64 // 5 KindFloat32 // 6 KindFloat64 // 7 KindString // 8 KindBytes // 9 KindEnum // 10 KindMessage // 11 KindList // 12 KindMap // 13 )
Kind constants for all 13 protoreflect value kinds. Values start at 1 so that the zero value of Kind is invalid by design.
type List ¶
type List interface {
// Len returns the number of elements in the list.
Len() int
// Get returns the element at the given index. It panics if the index is
// out of range (i < 0 or i >= Len), matching Go slice semantics.
Get(int) Value
// Set replaces the element at the given index with the provided value.
// It panics if the index is out of range (i < 0 or i >= Len).
Set(int, Value)
// Append appends the given value to the end of the list, increasing
// Len by one.
Append(Value)
// Truncate reduces the list length to n elements, discarding elements
// beyond index n-1. It panics if n is negative or greater than Len.
Truncate(int)
// NewElement returns the zero/default Value for the list's element type.
// This is useful for constructing values to append without knowing the
// concrete element type at compile time.
NewElement() Value
// IsValid reports whether the List is non-nil and usable. A List
// obtained from an unset repeated field returns false.
IsValid() bool
}
List is the reflection interface for a protobuf repeated field. It provides indexed access to repeated field elements. Concrete implementations are provided by generated code and the dynamic message package.
ISP note: List has 7 methods. This is a standard collection interface (Len, Get, Set, Append, Truncate, NewElement, IsValid) analogous to a Go slice. All consumers use both read and mutation methods during unmarshal, merge, and clone operations. Splitting into read-only and write-only sub-interfaces was evaluated, but no consumer uses only the read subset or only the write subset independently. This is documented as an accepted exception to the 5-method guideline.
A List obtained from a nil or invalid source should return false from IsValid. All other methods on an invalid List may panic.
type Map ¶
type Map interface {
// Len returns the number of entries in the map.
Len() int
// Get returns the value associated with the given key. If the key is not
// present in the map, it returns an invalid Value (where IsValid returns
// false). Callers should check IsValid on the returned Value to
// distinguish a missing key from a zero-valued entry.
Get(MapKey) Value
// Set inserts or updates the entry for the given key with the provided
// value.
Set(MapKey, Value)
// Has reports whether the map contains an entry for the given key.
Has(MapKey) bool
// Clear removes the entry for the given key from the map. If the key is
// not present, Clear is a no-op.
Clear(MapKey)
// Range iterates over all entries in the map, calling the given function
// for each key-value pair. Iteration stops early if the function returns
// false. Iteration order is undefined, matching Go map semantics.
Range(func(MapKey, Value) bool)
// NewValue returns the zero/default Value for the map's value type.
// This is useful for constructing values to insert without knowing the
// concrete value type at compile time.
NewValue() Value
// IsValid reports whether the Map is non-nil and usable. A Map obtained
// from an unset map field returns false.
IsValid() bool
}
Map is the reflection interface for a protobuf map field. It provides key-based access to map field entries. Concrete implementations are provided by generated code and the dynamic message package.
ISP note: Map has 8 methods. This is a standard collection interface (Len, Get, Set, Has, Clear, Range, NewValue, IsValid) analogous to a Go map. All consumers use both read and mutation methods during unmarshal, merge, and clone operations. Splitting into read-only and write-only sub-interfaces was evaluated, but no consumer uses only one subset independently. This is documented as an accepted exception to the 5-method guideline.
A Map obtained from a nil or invalid source should return false from IsValid. All other methods on an invalid Map may panic.
type MapKey ¶
type MapKey struct {
// contains filtered or unexported fields
}
MapKey wraps a Value restricted to valid protobuf map key types: bool, int32, int64, uint32, uint64, and string. It is used as the key parameter for Map interface methods.
func MapKeyOf ¶
MapKeyOf returns a MapKey wrapping the given Value. It panics if the Value's kind is not a valid protobuf map key type (bool, int32, int64, uint32, uint64, or string).
func MapKeyOfBool ¶
MapKeyOfBool returns a MapKey containing the given bool value.
func MapKeyOfInt32 ¶
MapKeyOfInt32 returns a MapKey containing the given int32 value.
func MapKeyOfInt64 ¶
MapKeyOfInt64 returns a MapKey containing the given int64 value.
func MapKeyOfString ¶
MapKeyOfString returns a MapKey containing the given string value.
func MapKeyOfUint32 ¶
MapKeyOfUint32 returns a MapKey containing the given uint32 value.
func MapKeyOfUint64 ¶
MapKeyOfUint64 returns a MapKey containing the given uint64 value.
func (MapKey) Bool ¶
Bool returns the bool value of the map key. It panics if the underlying Value kind is not KindBool.
func (MapKey) Int32 ¶
Int32 returns the int32 value of the map key. It panics if the underlying Value kind is not KindInt32.
func (MapKey) Int64 ¶
Int64 returns the int64 value of the map key. It panics if the underlying Value kind is not KindInt64.
func (MapKey) Interface ¶
func (k MapKey) Interface() interface{}
Interface returns the underlying Go value for debugging and test assertions. It delegates to the wrapped Value's Interface method.
func (MapKey) String ¶
String returns the string value of the map key. It panics if the underlying Value kind is not KindString.
func (MapKey) Uint32 ¶
Uint32 returns the uint32 value of the map key. It panics if the underlying Value kind is not KindUint32.
type Message ¶
type Message interface {
// Descriptor returns the message's schema descriptor. The returned
// descriptor describes the message's fields, oneofs, and nested types.
Descriptor() descriptor.MessageDescriptorAccessor
// New creates a new empty instance of the same concrete message type.
// This is a factory method that allows generic code to construct new
// messages without compile-time knowledge of the concrete type.
New() Message
// Interface returns the underlying concrete Go message value. Callers
// use type assertions on the returned ProtoMessage to access the
// generated message type.
Interface() ProtoMessage
// Get reads a field value by its field descriptor. For unset singular
// scalar fields it returns the field's default value. For unset singular
// message fields it returns an invalid Message (where IsValid returns
// false). For unset repeated fields it returns an empty read-only List.
// For unset map fields it returns an empty read-only Map. It panics if
// the field descriptor does not belong to this message's descriptor.
Get(descriptor.FieldDescriptorAccessor) Value
// Set writes a field value by its field descriptor. It panics if the
// field descriptor does not belong to this message's descriptor. It
// panics if the Value kind does not match the field's expected kind.
Set(descriptor.FieldDescriptorAccessor, Value)
// Has reports whether a field is populated. For singular scalar fields
// it reports whether the value differs from the default. For singular
// message fields it reports whether the field is set. For repeated and
// map fields it reports whether the field is non-empty.
Has(descriptor.FieldDescriptorAccessor) bool
// Clear clears a field to its zero/default state. After clearing, Has
// returns false and Get returns the default value. It panics if the
// field descriptor does not belong to this message's descriptor.
Clear(descriptor.FieldDescriptorAccessor)
// Range iterates over every populated field, calling the given function
// for each field descriptor and its current value. Iteration stops early
// if the function returns false. Iteration order is by field number.
Range(func(descriptor.FieldDescriptorAccessor, Value) bool)
// WhichOneof returns the field descriptor of the currently set field in
// the given oneof, or nil if no field in the oneof is set. It panics if
// the oneof descriptor does not belong to this message's descriptor.
WhichOneof(descriptor.OneofDescriptorAccessor) descriptor.FieldDescriptorAccessor
// GetUnknown returns the raw bytes of unknown fields preserved during
// decoding. It returns nil if no unknown fields are present.
GetUnknown() []byte
// SetUnknown replaces the raw bytes of unknown fields. Passing nil
// clears all unknown fields.
SetUnknown([]byte)
// IsValid reports whether the Message is non-nil and usable. A Message
// obtained from a nil pointer or an unset message field returns false.
IsValid() bool
}
Message is the reflection interface for a protobuf message. It provides dynamic access to message fields by descriptor. Concrete implementations are provided by generated code and the dynamic message package.
ISP note: Message has 13 methods. This is a reflection API analogous to Go's reflect.Value -- every method is essential to the unified field-access contract. Splitting into read-only vs. write-only sub-interfaces was evaluated, but all consumers (dynamicpb, codegen, jsoncodec, textcodec, proto/merge, proto/equal, protorange) use both read and write operations together during marshal, unmarshal, merge, and comparison. Splitting would force consumers to accept two interfaces instead of one with no practical benefit. This is documented as an accepted exception to the 5-method guideline.
A Message obtained from a nil or invalid source should return false from IsValid. All other methods on an invalid Message may panic.
type ProtoMessage ¶
type ProtoMessage interface {
// ProtoReflect returns a reflection Message for dynamic field access.
ProtoReflect() Message
}
ProtoMessage is the bridge interface that concrete generated Go message types satisfy. Each generated message type implements ProtoReflect to return a Message that provides dynamic access to the message's fields.
type Value ¶
type Value struct {
// contains filtered or unexported fields
}
Value is a tagged-union container for all protobuf value types. It stores scalar values inline to avoid heap allocations on hot paths. The zero value is invalid (Kind() returns 0, IsValid() returns false).
Scalar types (bool, integers, floats, enum) are stored in the num field. Strings use the dedicated str field. Reference types (bytes, message, list, map) are stored in the ref field.
Fields are ordered with pointer-containing fields first (ref, str), then non-pointer scalars (num), then small types (typ) to minimize GC pointer scanning overhead and padding.
func ValueOfBool ¶
ValueOfBool returns a Value containing the given bool.
func ValueOfBytes ¶
ValueOfBytes returns a Value containing the given byte slice.
func ValueOfEnum ¶
func ValueOfEnum(v EnumNumber) Value
ValueOfEnum returns a Value containing the given EnumNumber.
func ValueOfFloat32 ¶
ValueOfFloat32 returns a Value containing the given float32. The float is stored as its IEEE 754 bit pattern in the num field.
func ValueOfFloat64 ¶
ValueOfFloat64 returns a Value containing the given float64. The float is stored as its IEEE 754 bit pattern in the num field.
func ValueOfInt32 ¶
ValueOfInt32 returns a Value containing the given int32.
func ValueOfInt64 ¶
ValueOfInt64 returns a Value containing the given int64.
func ValueOfList ¶
ValueOfList returns a Value containing the given List.
func ValueOfMessage ¶
ValueOfMessage returns a Value containing the given Message.
func ValueOfString ¶
ValueOfString returns a Value containing the given string.
func ValueOfUint32 ¶
ValueOfUint32 returns a Value containing the given uint32.
func ValueOfUint64 ¶
ValueOfUint64 returns a Value containing the given uint64.
func (Value) Bytes ¶
Bytes returns the byte slice value. It panics if the Value kind is not KindBytes.
func (Value) Enum ¶
func (v Value) Enum() EnumNumber
Enum returns the EnumNumber value. It panics if the Value kind is not KindEnum.
func (Value) Float32 ¶
Float32 returns the float32 value. It panics if the Value kind is not KindFloat32. The value is reconstructed from the IEEE 754 bit pattern.
func (Value) Float64 ¶
Float64 returns the float64 value. It panics if the Value kind is not KindFloat64. The value is reconstructed from the IEEE 754 bit pattern.
func (Value) Interface ¶
func (v Value) Interface() interface{}
Interface returns the underlying Go value for debugging and test assertions. It switches on the value kind and returns the natural Go type. For an invalid Value it returns nil.
func (Value) IsValid ¶
IsValid reports whether this Value was constructed by one of the ValueOf constructors. The zero value of Value is not valid.
func (Value) Kind ¶
Kind returns the type discriminator for this Value. The zero value of Value returns Kind(0), which is invalid.
func (Value) Message ¶
Message returns the Message value. It panics if the Value kind is not KindMessage.
func (Value) String ¶
String returns the string value. It panics if the Value kind is not KindString. This method intentionally does not implement fmt.Stringer; callers should use Interface() for debug output.