or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

compiler-protogen.mdcore.mdencoding.mdindex.mdreflection.mdruntime.mdtesting.mdtypes-descriptorpb.mdtypes-dynamicpb.mdtypes-known.mdtypes-pluginpb.md
tile.json

core.mddocs/

Core Protocol Buffer Operations

The core proto package provides essential functions for working with protocol buffer messages, including marshaling to/from wire format, message manipulation (cloning, merging, equality), and extension field support. The protoadapt package bridges v1 and v2 proto APIs for backward compatibility.

Package Imports

import (
    "google.golang.org/protobuf/proto"
    "google.golang.org/protobuf/protoadapt"
    "google.golang.org/protobuf/reflect/protoreflect"
)

Binary Serialization

Wire Format Marshaling

Convert protocol buffer messages to and from the wire format binary encoding.

// Marshal returns the wire-format encoding of m
func Marshal(m Message) ([]byte, error)

// Unmarshal parses the wire-format message in b and places the result in m
// The provided message must be mutable (e.g., a non-nil pointer to a message)
func Unmarshal(b []byte, m Message) error

// Size returns the size in bytes of the wire-format encoding of m
func Size(m Message) int

Usage example:

msg := &pb.MyMessage{
    Name: "example",
    Value: 42,
}

// Marshal to wire format
data, err := proto.Marshal(msg)
if err != nil {
    log.Fatal(err)
}

// Unmarshal from wire format
msg2 := &pb.MyMessage{}
err = proto.Unmarshal(data, msg2)
if err != nil {
    log.Fatal(err)
}

// Get size without marshaling
size := proto.Size(msg)

Advanced Marshaling Options

Configure marshaling behavior with fine-grained control over serialization.

// MarshalOptions configures the marshaler
type MarshalOptions struct {
    pragma.NoUnkeyedLiterals

    // AllowPartial allows messages that have missing required fields to marshal
    // without returning an error. If AllowPartial is false (the default),
    // Marshal will return an error if there are any missing required fields.
    AllowPartial bool

    // Deterministic controls whether the same message will always be
    // serialized to the same bytes within the same binary.
    //
    // Setting this option guarantees that repeated serialization of
    // the same message will return the same bytes, and that different
    // processes of the same binary (which may be executing on different
    // machines) will serialize equal messages to the same bytes.
    // It has no effect on the resulting size of the encoded message compared
    // to a non-deterministic marshal.
    //
    // Note that the deterministic serialization is NOT canonical across
    // languages. It is not guaranteed to remain stable over time. It is
    // unstable across different builds with schema changes due to unknown
    // fields. Users who need canonical serialization (e.g., persistent
    // storage in a canonical form, fingerprinting, etc.) must define
    // their own canonicalization specification and implement their own
    // serializer rather than relying on this API.
    //
    // If deterministic serialization is requested, map entries will be
    // sorted by keys in lexographical order. This is an implementation
    // detail and subject to change.
    Deterministic bool

    // UseCachedSize indicates that the result of a previous Size call
    // may be reused.
    //
    // Setting this option asserts that:
    //
    // 1. Size has previously been called on this message with identical
    // options (except for UseCachedSize itself).
    //
    // 2. The message and all its submessages have not changed in any
    // way since the Size call. For lazily decoded messages, accessing
    // a message results in decoding the message, which is a change.
    //
    // If either of these invariants is violated,
    // the results are undefined and may include panics or corrupted output.
    //
    // Implementations MAY take this option into account to provide
    // better performance, but there is no guarantee that they will do so.
    // There is absolutely no guarantee that Size followed by Marshal with
    // UseCachedSize set will perform equivalently to Marshal alone.
    UseCachedSize bool
}

// Marshal returns the wire-format encoding of m
func (o MarshalOptions) Marshal(m Message) ([]byte, error)

// MarshalAppend appends the wire-format encoding of m to b, returning the result
// This is a less common entry point than Marshal, which is only needed if you
// need to supply your own buffers for performance reasons.
func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error)

// MarshalState returns the wire-format encoding of a message
// This method permits fine-grained control over the marshaler. Most users
// should use Marshal instead.
func (o MarshalOptions) MarshalState(in protoiface.MarshalInput) (protoiface.MarshalOutput, error)

// Size returns the size in bytes of the wire-format encoding of m
func (o MarshalOptions) Size(m Message) int

Usage example:

opts := proto.MarshalOptions{
    Deterministic: true,
    AllowPartial: false,
}

data, err := opts.Marshal(msg)
if err != nil {
    log.Fatal(err)
}

Advanced Unmarshaling Options

Configure unmarshaling behavior including merge mode, partial messages, and type resolution.

// UnmarshalOptions configures the unmarshaler
type UnmarshalOptions struct {
    pragma.NoUnkeyedLiterals

    // Merge merges the input into the destination message.
    // The default behavior is to always reset the message before unmarshaling,
    // unless Merge is specified.
    Merge bool

    // AllowPartial accepts input for messages that will result in missing
    // required fields. If AllowPartial is false (the default), Unmarshal will
    // return an error if there are any missing required fields.
    AllowPartial bool

    // If DiscardUnknown is set, unknown fields are ignored.
    DiscardUnknown bool

    // Resolver is used for looking up types when unmarshaling extension fields.
    // If nil, this defaults to using protoregistry.GlobalTypes.
    Resolver interface {
        FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
        FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
    }

    // RecursionLimit limits how deeply messages may be nested.
    // If zero, a default limit is applied.
    RecursionLimit int

    // NoLazyDecoding turns off lazy decoding, which otherwise is enabled by
    // default. Lazy decoding only affects submessages (annotated with [lazy =
    // true] in the .proto file) within messages that use the Opaque API.
    NoLazyDecoding bool
}

// Unmarshal parses the wire-format message in b and places the result in m
// The provided message must be mutable (e.g., a non-nil pointer to a message)
func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error

// UnmarshalState parses a wire-format message and places the result in m
// This method permits fine-grained control over the unmarshaler. Most users
// should use Unmarshal instead.
func (o UnmarshalOptions) UnmarshalState(in protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error)

Usage example:

opts := proto.UnmarshalOptions{
    DiscardUnknown: true,
    AllowPartial: false,
}

msg := &pb.MyMessage{}
err := opts.Unmarshal(data, msg)
if err != nil {
    log.Fatal(err)
}

Message Operations

Cloning Messages

Create deep copies of protocol buffer messages.

// Clone returns a deep copy of m
// If the top-level message is invalid, it returns an invalid message as well
func Clone(m Message) Message

// CloneOf returns a deep copy of m
// If the top-level message is invalid, it returns an invalid message as well
func CloneOf[M Message](m M) M

Usage example:

original := &pb.MyMessage{Name: "test"}

// Type-erased clone
cloned := proto.Clone(original).(*pb.MyMessage)

// Type-safe generic clone
cloned2 := proto.CloneOf(original)

Merging Messages

Merge one message into another, combining their field values.

// Merge merges src into dst, which must be a message with the same descriptor
//
// Populated scalar fields in src are copied to dst, while populated singular
// messages in src are merged into dst by recursively calling Merge.
// The elements of every list field in src is appended to the corresponded
// list fields in dst. The entries of every map field in src is copied into
// the corresponding map field in dst, possibly replacing existing entries.
// The unknown fields of src are appended to the unknown fields of dst.
//
// It is semantically equivalent to unmarshaling the encoded form of src into
// dst with the UnmarshalOptions.Merge option specified.
func Merge(dst, src Message)

Usage example:

dst := &pb.MyMessage{Name: "original"}
src := &pb.MyMessage{Value: 42}

proto.Merge(dst, src)
// dst now has Name="original" and Value=42

Comparing Messages

Test equality between protocol buffer messages.

// Equal reports whether two messages are equal, by recursively comparing the
// fields of the message.
//
//   - Bytes fields are equal if they contain identical bytes. Empty bytes
//     (regardless of nil-ness) are considered equal.
//
//   - Floating-point fields are equal if they contain the same value. Unlike
//     the == operator, a NaN is equal to another NaN.
//
//   - Other scalar fields are equal if they contain the same value.
//
//   - Message fields are equal if they have the same set of populated known
//     and extension field values, and the same set of unknown fields values.
//
//   - Lists are equal if they are the same length and each corresponding
//     element is equal.
//
//   - Maps are equal if they have the same set of keys and the corresponding
//     value for each key is equal.
//
// An invalid message is not equal to a valid message. An invalid message
// is only equal to another invalid message of the same type. An invalid
// message often corresponds to a nil pointer of the concrete message type.
// For example, (*pb.M)(nil) is not equal to &pb.M{}. If two valid messages
// marshal to the same bytes under deterministic serialization, then Equal is
// guaranteed to report true.
func Equal(x, y Message) bool

Usage example:

msg1 := &pb.MyMessage{Name: "test", Value: 42}
msg2 := &pb.MyMessage{Name: "test", Value: 42}

if proto.Equal(msg1, msg2) {
    fmt.Println("Messages are equal")
}

Resetting Messages

Clear all fields in a message.

// Reset clears every field in the message
// The resulting message shares no observable memory with its previous state
// other than the memory for the message itself.
func Reset(m Message)

Usage example:

msg := &pb.MyMessage{Name: "test", Value: 42}
proto.Reset(msg)
// msg is now empty

Checking Initialization

Validate that all required fields are set.

// CheckInitialized returns an error if any required fields in m are not set
func CheckInitialized(m Message) error

Usage example:

msg := &pb.MyMessage{} // Missing required fields

err := proto.CheckInitialized(msg)
if err != nil {
    fmt.Println("Message not fully initialized:", err)
}

Message Introspection

Message Names

Retrieve the fully-qualified name of a message type.

// MessageName returns the full name of m
// If m is nil, it returns an empty string
func MessageName(m Message) protoreflect.FullName

Usage example:

msg := &pb.MyMessage{}
name := proto.MessageName(msg) // Returns "example.MyMessage"

Optional Field Helpers

Scalar Pointer Constructors

Helper functions to create pointers to scalar values for use with optional fields in proto2.

// Bool stores v in a new bool value and returns a pointer to it
func Bool(v bool) *bool

// Int32 stores v in a new int32 value and returns a pointer to it
func Int32(v int32) *int32

// Int64 stores v in a new int64 value and returns a pointer to it
func Int64(v int64) *int64

// Uint32 stores v in a new uint32 value and returns a pointer to it
func Uint32(v uint32) *uint32

// Uint64 stores v in a new uint64 value and returns a pointer to it
func Uint64(v uint64) *uint64

// Float32 stores v in a new float32 value and returns a pointer to it
func Float32(v float32) *float32

// Float64 stores v in a new float64 value and returns a pointer to it
func Float64(v float64) *float64

// String stores v in a new string value and returns a pointer to it
func String(v string) *string

Usage example:

msg := &pb.MyProto2Message{
    OptionalString: proto.String("hello"),
    OptionalInt32:  proto.Int32(42),
    OptionalBool:   proto.Bool(true),
}

Value Helper Functions

Advanced helpers for working with optional fields and the Opaque API.

// ValueOrDefault returns the protobuf message val if val is not nil, otherwise
// it returns a pointer to an empty val message.
//
// This function allows for translating code from the old Open Struct API to
// the new Opaque API.
func ValueOrDefault[T interface {
    *P
    Message
}, P any](val T) T

// ValueOrDefaultBytes is like ValueOrDefault but for working with fields of
// type []byte.
func ValueOrDefaultBytes(val []byte) []byte

// ValueOrNil returns nil if has is false, or a pointer to a new variable
// containing the value returned by the specified getter.
//
// This function is similar to the wrappers (proto.Int32(), proto.String(),
// etc.), but is generic (works for any field type) and works with the hasser
// and getter of a field, as opposed to a value.
//
// This is convenient when populating builder fields.
func ValueOrNil[T any](has bool, getter func() T) *T

Usage example for ValueOrNil:

hop := attr.GetDirectHop()
injectedRoute := ripb.InjectedRoute_builder{
    Prefixes: route.GetPrefixes(),
    NextHop:  proto.ValueOrNil(hop.HasAddress(), hop.GetAddress),
}

Extension Field Support

Extension Field Operations

Work with extension fields in proto2 messages.

// HasExtension reports whether an extension field is populated
// It returns false if m is invalid or if xt does not extend m
func HasExtension(m Message, xt protoreflect.ExtensionType) bool

// GetExtension retrieves the value for an extension field
// If the field is unpopulated, it returns the default value for scalars and an immutable,
// empty value for lists or messages. It panics if xt does not extend m.
func GetExtension(m Message, xt protoreflect.ExtensionType) any

// SetExtension stores the value of an extension field
// It panics if m is invalid, xt does not extend m, or if type of v is invalid
// for the specified extension field
func SetExtension(m Message, xt protoreflect.ExtensionType, v any)

// ClearExtension clears an extension field such that subsequent HasExtension
// calls return false. It panics if m is invalid or if xt does not extend m
func ClearExtension(m Message, xt protoreflect.ExtensionType)

// RangeExtensions iterates over every populated extension field in m in an
// undefined order, calling f for each extension type and value encountered
// It returns immediately if f returns false. While iterating, mutating operations
// may only be performed on the current extension field
func RangeExtensions(m Message, f func(protoreflect.ExtensionType, any) bool)

Extension type mapping for GetExtension and SetExtension:

╔═══════════════════╤═════════════════════════╗
║ Go type           │ Protobuf kind           ║
╠═══════════════════╪═════════════════════════╣
║ bool              │ bool                    ║
║ int32             │ int32, sint32, sfixed32 ║
║ int64             │ int64, sint64, sfixed64 ║
║ uint32            │ uint32, fixed32         ║
║ uint64            │ uint64, fixed64         ║
║ float32           │ float                   ║
║ float64           │ double                  ║
║ string            │ string                  ║
║ []byte            │ bytes                   ║
║ protoreflect.Enum │ enum                    ║
║ proto.Message     │ message, group          ║
╚═══════════════════╧═════════════════════════╝

Usage example:

// Check if extension is present
if proto.HasExtension(msg, foopb.E_MyExtension) {
    // Get extension value with type assertion
    ext := proto.GetExtension(msg, foopb.E_MyExtension).(*foopb.MyMessage)
    fmt.Println(ext)
}

// Set extension value
proto.SetExtension(msg, foopb.E_MyExtension, &foopb.MyMessage{
    Field: "value",
})

// Clear extension
proto.ClearExtension(msg, foopb.E_MyExtension)

// Iterate over all extensions
proto.RangeExtensions(msg, func(xt protoreflect.ExtensionType, v any) bool {
    fmt.Printf("Extension %s: %v\n", xt.TypeDescriptor().FullName(), v)
    return true // continue iteration
})

API Version Compatibility

Proto Message Interface

The core Message type that all protocol buffer messages implement.

// Message is the top-level interface that all messages must implement
// It provides access to a reflective view of a message. Any implementation of
// this interface may be used with all functions in the protobuf module that
// accept a Message, except where otherwise specified.
//
// This is the v2 interface definition for protobuf messages. The v1 interface
// definition is github.com/golang/protobuf/proto.Message.
//
//   - To convert a v1 message to a v2 message, use
//     google.golang.org/protobuf/protoadapt.MessageV2Of.
//   - To convert a v2 message to a v1 message, use
//     google.golang.org/protobuf/protoadapt.MessageV1Of.
type Message = protoreflect.ProtoMessage

V1 and V2 API Bridging

Convert between the original (v1) and new (v2) proto APIs for backward compatibility.

// MessageV1 is the original github.com/golang/protobuf/proto.Message type
type MessageV1 = protoiface.MessageV1

// MessageV1Of converts a v2 message to a v1 message
// It returns nil if m is nil
func MessageV1Of(m MessageV2) MessageV1

// MessageV2 is the google.golang.org/protobuf/proto.Message type used by the
// current google.golang.org/protobuf module, adding support for reflection
type MessageV2 = proto.Message

// MessageV2Of converts a v1 message to a v2 message
// It returns nil if m is nil
func MessageV2Of(m MessageV1) MessageV2

Usage example:

import (
    "google.golang.org/protobuf/proto"
    "google.golang.org/protobuf/protoadapt"
    oldproto "github.com/golang/protobuf/proto"
)

// Convert v1 message to v2
var v1msg oldproto.Message
v2msg := protoadapt.MessageV2Of(v1msg)

// Convert v2 message to v1
var v2msg proto.Message
v1msg := protoadapt.MessageV1Of(v2msg)

Error Handling

// Error matches all errors produced by packages in the protobuf module
// according to errors.Is
var Error error

Usage example:

import (
    "errors"
    "google.golang.org/protobuf/proto"
)

data := []byte{0xff, 0xff} // Invalid proto data
msg := &pb.MyMessage{}
err := proto.Unmarshal(data, msg)

if errors.Is(err, proto.Error) {
    fmt.Println("Protocol buffer error occurred")
}