codegen

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package codegen -- decode_enum.go contains enum-level descriptor decoding: EnumDescriptorProto and EnumValueDescriptorProto wire parsing, and the buildEnumDescriptor pass-2 builder.

Package codegen -- decode_file.go contains file-level descriptor decoding: raw type definitions, lookup tables, the two-pass DecodeFileDescriptors entry-point, and helper functions shared across all decode_*.go files.

Package codegen -- decode_message.go contains message-level descriptor decoding: DescriptorProto, FieldDescriptorProto, OneofDescriptorProto wire parsing, and the buildMessageDescriptor pass-2 builder.

Package codegen -- decode_service.go contains service-level descriptor decoding: ServiceDescriptorProto and MethodDescriptorProto wire parsing, and the buildServiceDescriptor pass-2 builder.

Package codegen implements the protoc code generation engine for Go. It transforms decoded file descriptors into Go source files implementing the protobuf message, enum, and service types defined in .proto files.

The primary entry point is Generate, which accepts a set of linked file descriptors, their raw wire-format counterparts, a set of files to generate, and parsed generator parameters. It returns a map of output file paths to generated Go source content.

The package also implements the protoc plugin wire protocol through CodeGeneratorRequest and CodeGeneratorResponse. CodeGeneratorRequest is unmarshaled from the binary input provided by protoc on stdin, and CodeGeneratorResponse is marshaled to stdout. The RawFileDescriptor type captures the subset of FileDescriptorProto fields needed for code generation without requiring a full descriptor decode.

Code generation produces several categories of output:

  • Message structs with Marshal, Unmarshal, Size, Merge, Clone, Reset, Validate, Equal, and ProtoReflect methods
  • Enum types with String, Number, and lookup helpers
  • Service interfaces and method descriptors
  • Builder types for constructing messages with a fluent API
  • Oneof interface types and accessor methods
  • Pool-integrated allocation helpers with build-tagged GC and TinyGo variants
  • File-level descriptor registration via init functions

The GenerateFile function produces the complete Go source for a single .proto file. GenerateAuxFiles produces build-tagged auxiliary files for TinyGo compatibility. Both are called by Generate for each file in the generation set.

Go package resolution is handled by ResolveGoPackage, which parses the go_package option string into an import path and package name. The ImportTable type maps proto file paths and packages to their resolved Go package information, enabling cross-file type reference resolution.

This package depends on descriptor, scalar, field, encode, decode, and wire from this module, plus the Go standard library. It has zero external dependencies.

gen_api_mode.go provides helpers for API-mode-aware code generation. When the resolved GoAPIMode is GoAPIModeOpen, fields use exported PascalCase names (current behavior). When GoAPIModeOpaque, fields use unexported camelCase names with getter/setter accessors.

Package codegen -- gen_binary.go generates MarshalBinary and UnmarshalBinary methods for protobuf messages so that generated types satisfy the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler interfaces. The methods are thin wrappers that delegate to the existing Marshal and Unmarshal methods; no serialization logic is duplicated here. These methods enable generated types to work with encoding/gob, database/sql drivers, and other stdlib-based serialization.

Package codegen -- gen_buildtag.go generates auxiliary build-tagged Go source files for TinyGo compatibility. For each .proto file that contains messages, two additional files are produced alongside the main .pb.go:

  • *_pool_gc.go (//go:build !tinygo): sync.Pool variable, ResetVT, ReturnToPool, and FromPool using sync.Pool.
  • *_pool_tinygo.go (//go:build tinygo): ResetVT, ReturnToPool (calls ResetVT only), and FromPool (direct allocation).
  • *_unsafe_gc.go (//go:build !tinygo): UnmarshalUnsafe using unsafe.String for zero-copy string aliasing.
  • *_unsafe_tinygo.go (//go:build tinygo): UnmarshalUnsafe that delegates to standard Unmarshal (no unsafe import).

gen_equal.go generates the type-specific Equal method for protobuf messages.

The generated Equal(other *MsgType) bool method compares fields directly by name without going through protoreflect.Range or interface dispatch. Scalar fields use ==, bytes fields use bytes.Equal, message fields use recursive x.Field.Equal(other.Field), repeated fields use length check plus element- wise comparison, map fields use length check plus key-wise comparison, and oneof fields use a type-switch comparing the active variant.

For fields with native Go type substitution (go_type option), the comparison uses the substitution's EqualExpr: time.Time uses .Equal(), time.Duration uses ==, and map[string]any uses reflect.DeepEqual.

The reflection-based proto.Equal in proto/equal_message.go remains available as a fallback for dynamic messages and cross-type comparisons. The generated Equal method is used when both operands are the same concrete generated type.

Package codegen -- gen_file_descriptors.go contains functions that emit Go code to build descriptor.XxxDescriptor values via the builder API, used within the generated init() function.

Package codegen -- gen_file_header.go contains the GenerateFile entry-point that produces complete Go source code for a single .proto file, along with the recursive code collectors, file header, and package-level variable emitters.

Package codegen -- gen_file_imports.go contains import tracking and the import block writer for generated Go source files.

Package codegen -- gen_file_registration.go contains the init() function generator and the helper functions that convert descriptor/scalar constants to their Go source code string representations.

Package codegen -- gen_json.go generates MarshalJSON and UnmarshalJSON methods for protobuf messages so that generated types satisfy the encoding/json.Marshaler and encoding/json.Unmarshaler interfaces. The methods are thin wrappers that delegate to the jsoncodec package; no marshaling logic is duplicated here.

Package codegen -- gen_marshal.go generates the MarshalAppend and Marshal methods for protobuf messages, handling singular, repeated, and oneof field encoding using inline wire package calls for zero-dispatch serialization.

Package codegen -- gen_marshal_map.go generates encoding code for protobuf map fields, including map key type resolution, key sorting, and entry-level size computation and wire encoding using inline wire package calls.

gen_merge_clone.go generates the Merge and Clone methods for protobuf messages, handling field-by-field merging and deep copying of singular, repeated, map, and oneof fields. For fields with native Go type substitution (go_type option), values are treated as their native Go types: time.Time and time.Duration are value types (copy by assignment), and map[string]any is deep-copied via a helper.

gen_opaque.go generates getter, setter, Has, and Clear methods for protobuf messages using the opaque API mode (GoAPIModeOpaque). In opaque mode, struct fields are unexported and accessed only through these generated accessor methods. Message-typed fields support lazy decoding: raw bytes are stored in an internal _lazy_fieldName field and decoded on first Get call.

gen_pool.go generates message-level sync.Pool integration for protobuf messages. This includes ResetVT (capacity-preserving reset), ReturnToPool, MsgTypeFromPool, and the package-level pool variable declaration.

Message-level pools are separate from the buffer pool in pool/pool.go. The buffer pool manages reusable byte slices for serialization; message pools manage reusable message struct instances to reduce GC pressure.

For TinyGo compatibility, the pool code is split into two build-tagged files: a gc variant using sync.Pool and a tinygo variant using direct allocation.

gen_reflect.go generates the ProtoReflect method and its supporting reflection adapter struct for protobuf messages, providing access to the descriptor-based reflection API.

gen_shallow_clone.go generates the ShallowClone method for protobuf messages. Unlike the deep-copy Clone method, ShallowClone copies scalar fields by value and copies slice headers, map references, and message pointers without recursing. Mutations to shared slices, maps, or sub-messages will be visible from both the original and the clone.

gen_size.go generates the Size method for protobuf messages, computing the serialized wire size for singular, repeated, map, and oneof fields using inline wire.SizeVarint calls and pre-computed tag size constants.

gen_unmarshal.go generates the Unmarshal and UnmarshalUnsafe methods for protobuf messages, handling singular, repeated, map, and oneof field decoding with inline wire consumption calls for performance.

Package codegen -- gen_unmarshal_tinygo.go generates the TinyGo-variant and gc-variant UnmarshalUnsafe code for build-tagged file splitting. The gc variant uses the unsafe package for zero-copy string aliasing. The TinyGo variant delegates to the standard Unmarshal method since TinyGo does not support the unsafe package features used for zero-copy aliasing.

gen_validate.go generates the Reset and Validate methods for protobuf messages. Reset zeros all fields; Validate checks required fields and closed enum values. In opaque mode, field access uses camelCase names.

native_types.go defines the native Go type substitution table for well-known protobuf types. When a field has the `go_type` option set, the code generator substitutes the default WKT pointer type (e.g., *wkt.Timestamp) with a native Go type (e.g., time.Time). The substitution is opt-in per field; when no `go_type` option is present, behavior is unchanged.

Supported substitutions:

  • google.protobuf.Timestamp -> time.Time (import: "time")
  • google.protobuf.Duration -> time.Duration (import: "time")
  • google.protobuf.Struct -> map[string]any (no import needed)

Each substitution includes conversion function names for marshal (Go native type -> WKT type) and unmarshal (WKT type -> Go native type) directions, enabling the generated code to round-trip through the WKT types for wire encoding.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DecodeFileDescriptors

func DecodeFileDescriptors(raws []RawFileDescriptor) ([]*descriptor.FileDescriptor, error)

DecodeFileDescriptors decodes a slice of RawFileDescriptor values into fully resolved descriptor.FileDescriptor objects. It uses a two-pass approach: pass 1 decodes all raw data and registers type stubs in lookup maps, pass 2 builds all descriptors with cross-references resolved.

func Generate

func Generate(
	files []*descriptor.FileDescriptor,
	raws []RawFileDescriptor,
	fileToGenerate map[string]bool,
	params GeneratorParams,
) (map[string]string, error)

Generate produces Go source files for the requested proto files. It accepts decoded file descriptors, the corresponding raw descriptors, the set of file names to generate, and parsed parameters. It returns a map of output file path to generated Go source content. Files not in the fileToGenerate set and well-known proto files are skipped.

In addition to the main .pb.go file, Generate produces build-tagged auxiliary files for TinyGo compatibility: pool gc/tinygo variants and unsafe gc/tinygo variants.

func GenerateAuxFiles

func GenerateAuxFiles(
	fd *descriptor.FileDescriptor,
	raw RawFileDescriptor,
	allFiles []*descriptor.FileDescriptor,
	allRaws []RawFileDescriptor,
) (map[string]string, error)

GenerateAuxFiles produces the build-tagged auxiliary files for a single .proto file. It returns a map of output file path suffix to formatted Go source content. The caller is responsible for prepending the appropriate directory path. If the file contains no messages, an empty map is returned.

func GenerateFile

func GenerateFile(
	fd *descriptor.FileDescriptor,
	raw RawFileDescriptor,
	allFiles []*descriptor.FileDescriptor,
	allRaws []RawFileDescriptor,
) (content string, skip bool, err error)

GenerateFile produces the complete Go source code for a single .proto file. It combines output from enum, oneof, message, message methods, and service generators into a formatted .pb.go file. If the proto file corresponds to a well-known type proto file, it returns empty content and skip=true.

func GenerateMessage

func GenerateMessage(
	md descriptor.MessageDescriptorAccessor,
	parentMsgName string,
	currentPkg string,
	imports ImportTable,
) string

GenerateMessage generates Go source code for a single protobuf message descriptor. It emits the struct type declaration with fields, getters (or opaque getter/setter accessors), and a compile-time proto.Message interface check. Nested messages are emitted at package level with ParentName_NestedName naming. Map entry messages are skipped since they are represented as Go map fields on the parent message.

When the descriptor's resolved EditionFeatures specify a non-default DefaultSymbolVisibility, the generated type name is adjusted: EXPORT_TOP_LEVEL makes nested types unexported, LOCAL_ALL makes all types unexported, and STRICT requires names to pass PascalCase validation.

When GoAPIModeOpaque is active, struct fields are emitted as unexported (camelCase) and opaque getter/setter methods are generated instead of the standard getters. Message-typed fields additionally get Has/Clear methods and a _lazy_fieldName internal field for lazy decoding support.

func GenerateMessageMethods

func GenerateMessageMethods(
	md descriptor.MessageDescriptorAccessor,
	parentMsgName string,
	currentPkg string,
	imports ImportTable,
	syntax descriptor.Syntax,
) string

GenerateMessageMethods generates the proto.Message interface methods, a type-specific Equal and ShallowClone methods, the MarshalJSON/UnmarshalJSON methods for encoding/json compatibility, and the MarshalBinary/ UnmarshalBinary methods for encoding.BinaryMarshaler/BinaryUnmarshaler compatibility for a single message descriptor.

Pool integration methods (ResetVT, ReturnToPool, FromPool, pool variable) and the UnmarshalUnsafe method are emitted into separate build-tagged files by GeneratePoolGC/GeneratePoolTinyGo and GenerateUnsafeGC/GenerateUnsafeTinyGo for TinyGo compatibility.

func GenerateMessages

func GenerateMessages(
	fd descriptor.FileDescriptorAccessor,
	currentPkg string,
	imports ImportTable,
) string

GenerateMessages generates Go source code for all top-level messages in a file descriptor, including their nested messages, getters, and compile-time interface checks.

func GenerateOneof

func GenerateOneof(
	od descriptor.OneofDescriptorAccessor,
	msgName string,
	currentPkg string,
	imports ImportTable,
) string

GenerateOneof generates Go source code for a single non-synthetic oneof descriptor belonging to the given parent message name. It emits a sealed interface type with an unexported marker method and a wrapper struct for each variant field. When a variant field has a go_tag custom struct tag, the tag is emitted on the wrapper struct's field line. Synthetic oneofs (proto3 optional) are skipped and produce no output.

func GenerateOneofs

func GenerateOneofs(
	md descriptor.MessageDescriptorAccessor,
	msgName string,
	currentPkg string,
	imports ImportTable,
) string

GenerateOneofs generates Go source code for all non-synthetic oneofs in the given message descriptor. It concatenates the output of GenerateOneof for each qualifying oneof.

func GeneratePoolGC

func GeneratePoolGC(
	fd *descriptor.FileDescriptor,
	currentPkg string,
	imports ImportTable,
) string

GeneratePoolGC generates the gc-variant pool code for all messages in a file. The output includes the sync.Pool variable, ResetVT, ReturnToPool, and FromPool methods for each message. This code is placed in a file with //go:build !tinygo.

func GeneratePoolTinyGo

func GeneratePoolTinyGo(
	fd *descriptor.FileDescriptor,
	currentPkg string,
	imports ImportTable,
) string

GeneratePoolTinyGo generates the tinygo-variant pool code for all messages in a file. The output omits sync.Pool entirely: ReturnToPool calls ResetVT, and FromPool allocates directly. ResetVT is shared and appears in the gc file. This code is placed in a file with //go:build tinygo.

func GenerateServices

func GenerateServices(fd descriptor.FileDescriptorAccessor, currentPkg string, imports ImportTable) (string, bool)

GenerateServices generates Go interface declarations for all services in a file descriptor. It returns the generated source text and a boolean indicating whether the context import is needed (true when at least one service is present). The currentPkg parameter is the proto package name of the current file, used for resolving type references. The imports parameter provides cross-package type resolution.

func GenerateUnsafeGC

func GenerateUnsafeGC(
	fd *descriptor.FileDescriptor,
	currentPkg string,
	imports ImportTable,
) string

GenerateUnsafeGC generates the gc-variant UnmarshalUnsafe code for all messages in a file. The output includes the full UnmarshalUnsafe method using the unsafe package for zero-copy aliasing. This code is placed in a file with //go:build !tinygo.

func GenerateUnsafeTinyGo

func GenerateUnsafeTinyGo(
	fd *descriptor.FileDescriptor,
	currentPkg string,
	imports ImportTable,
) string

GenerateUnsafeTinyGo generates the tinygo-variant UnmarshalUnsafe code for all messages in a file. The TinyGo variant delegates to the standard Unmarshal method since the unsafe package is not available under TinyGo. This code is placed in a file with //go:build tinygo.

func IsWellKnownProtoFile

func IsWellKnownProtoFile(protoFilePath string) bool

IsWellKnownProtoFile reports whether the given proto file path corresponds to a well-known proto file whose types are already implemented in the wkt package. Files matching this check should be skipped during code generation.

func IsWellKnownType

func IsWellKnownType(fullName string) bool

IsWellKnownType reports whether the given full name corresponds to a well-known protobuf type implemented in the wkt package.

func ProtoToCamelCase

func ProtoToCamelCase(s string) string

ProtoToCamelCase converts a snake_case proto field name to a CamelCase Go exported name. It handles leading underscores, consecutive underscores, and trailing underscores by capitalizing the letter immediately following each underscore. Leading underscores are prefixed with "X_". Examples:

"field_name"   -> "FieldName"
"_private"     -> "X_Private"
"foo__bar"     -> "FooBar"
"trailing_"    -> "Trailing_"

func ProtoToGoType

func ProtoToGoType(kind scalar.Kind) string

ProtoToGoType maps a proto scalar kind to its Go type name. For message, group, and enum kinds it returns an empty string because those types require context-specific resolution.

func QualifiedGoType

func QualifiedGoType(fd descriptor.FieldDescriptorAccessor, currentPkg string, imports ImportTable) string

QualifiedGoType produces the Go type reference for a field descriptor. If the field references a message or enum in a different Go package, it returns a qualified name (e.g., "*otherpkg.MessageName"). If the reference is within the same package, it returns the unqualified name. For well-known types, it returns the wkt-qualified name (e.g., "*wkt.Timestamp").

Types

type CodeGeneratorRequest

type CodeGeneratorRequest struct {
	FileToGenerate []string
	Parameter      string
	ProtoFile      []RawFileDescriptor
}

CodeGeneratorRequest represents the protoc plugin protocol request message. It holds the list of files to generate, an optional parameter string, and the full set of file descriptors provided by protoc.

func (*CodeGeneratorRequest) Unmarshal

func (r *CodeGeneratorRequest) Unmarshal(b []byte) error

Unmarshal decodes wire-format bytes into the CodeGeneratorRequest. It uses the decoder's DecodeMessage with a field handler dispatching on field numbers 1 (FileToGenerate), 2 (Parameter), and 15 (ProtoFile).

type CodeGeneratorResponse

type CodeGeneratorResponse struct {
	Error *string
	File  []ResponseFile
}

CodeGeneratorResponse represents the protoc plugin protocol response message. It holds an optional error string and a list of output files.

func (*CodeGeneratorResponse) Marshal

func (r *CodeGeneratorResponse) Marshal() ([]byte, error)

Marshal returns the wire-format encoding of the CodeGeneratorResponse.

func (*CodeGeneratorResponse) MarshalAppend

func (r *CodeGeneratorResponse) MarshalAppend(b []byte) ([]byte, error)

MarshalAppend appends the wire-format encoding of the CodeGeneratorResponse to b and returns the extended slice.

func (*CodeGeneratorResponse) Size

func (r *CodeGeneratorResponse) Size() int

Size returns the exact number of bytes the serialized CodeGeneratorResponse will occupy.

type GeneratorParams

type GeneratorParams struct {
	Paths PathMode
}

GeneratorParams holds parsed parameters from the plugin request's parameter string.

func ParseParams

func ParseParams(param string) GeneratorParams

ParseParams parses a comma-separated key=value parameter string into a GeneratorParams. Unrecognized keys are silently ignored. The default path mode is source_relative.

type GoPackageInfo

type GoPackageInfo struct {
	ImportPath   string
	PackageName  string
	ProtoPackage string
}

GoPackageInfo holds the resolved Go import path and package name for a proto file, along with the proto package name for cross-reference resolution.

func ResolveGoPackage

func ResolveGoPackage(goPackage, protoPackage string) GoPackageInfo

ResolveGoPackage derives the Go import path and package name from a go_package option string and a proto package name. It handles three formats:

  • Semicolon-separated: "github.com/foo/bar;barpb" yields import path "github.com/foo/bar" and package name "barpb".
  • Slash-only: "github.com/foo/bar" yields import path "github.com/foo/bar" and package name "bar".
  • Plain or empty: falls back to the proto package name for both import path and package name.

type ImportTable

type ImportTable struct {
	// contains filtered or unexported fields
}

ImportTable maps proto file paths to their resolved Go package information. It also maintains a reverse lookup from proto package name to Go package info for cross-file type reference resolution.

func NewImportTable

func NewImportTable(files []*descriptor.FileDescriptor, raws []RawFileDescriptor) ImportTable

NewImportTable builds an ImportTable from the decoded file descriptors and their corresponding raw descriptors. The two slices must be the same length and in the same order.

func (ImportTable) LookupImport

func (t ImportTable) LookupImport(protoFilePath string) GoPackageInfo

LookupImport returns the GoPackageInfo for the given proto file path. If the file is not found, it returns a zero-value GoPackageInfo.

type NativeTypeInfo

type NativeTypeInfo struct {
	// GoType is the Go type string to emit in the generated struct field.
	GoType string

	// ImportPath is the Go import path needed for the native type, or empty
	// if no import is required (e.g., map[string]any).
	ImportPath string

	// MarshalConv is the Go expression template for converting a native Go
	// value to the WKT type before encoding. The placeholder %s is replaced
	// with the field expression. The result is a pointer to the WKT type.
	MarshalConv string

	// UnmarshalConv is the Go expression template for converting a decoded
	// WKT value to the native Go type. The placeholder %s is replaced with
	// the WKT temporary variable name.
	UnmarshalConv string

	// WKTType is the WKT type name used for the temporary variable during
	// unmarshal (e.g., "wkt.Timestamp").
	WKTType string

	// ZeroValue is the Go zero-value literal for the native type.
	ZeroValue string

	// EqualExpr is a format string for comparing two values of the native
	// type. It takes two arguments: the x field expression and the other
	// field expression. When empty, use == comparison.
	EqualExpr string
}

NativeTypeInfo holds the details of a native Go type substitution for a WKT.

type PathMode

type PathMode int

PathMode controls how output file paths are computed from proto file paths.

const (
	// PathModeSourceRelative produces output paths adjacent to the proto source
	// file by replacing the .proto suffix with .pb.go.
	PathModeSourceRelative PathMode = iota

	// PathModeImport produces output paths derived from the Go import path
	// resolved from the go_package option.
	PathModeImport
)

type RawFileDescriptor

type RawFileDescriptor struct {
	Name        string
	Package     string
	Dependency  []string
	MessageType [][]byte
	EnumType    [][]byte
	Service     [][]byte
	Options     []byte
	Syntax      string
	GoPackage   string
}

RawFileDescriptor captures the serialized FileDescriptorProto fields needed to construct descriptor.FileDescriptor objects. Only the fields required for code generation are decoded; sub-message bytes for message types, enum types, and services are stored raw for later processing by the descriptor decoder.

func (*RawFileDescriptor) Unmarshal

func (d *RawFileDescriptor) Unmarshal(b []byte) error

Unmarshal decodes wire-format bytes into the RawFileDescriptor. It extracts name (field 1), package (field 2), dependency list (field 3), message types (field 4), enum types (field 5), services (field 6), options (field 8), and syntax (field 12). The go_package option is extracted from the serialized FileOptions bytes.

type ResponseFile

type ResponseFile struct {
	Name           string
	InsertionPoint string
	Content        string
}

ResponseFile represents a single output file in a CodeGeneratorResponse.

func (*ResponseFile) Marshal

func (f *ResponseFile) Marshal() ([]byte, error)

Marshal returns the wire-format encoding of the ResponseFile.

func (*ResponseFile) MarshalAppend

func (f *ResponseFile) MarshalAppend(b []byte) ([]byte, error)

MarshalAppend appends the wire-format encoding of the ResponseFile to b and returns the extended slice. Empty fields are omitted.

func (*ResponseFile) Size

func (f *ResponseFile) Size() int

Size returns the exact number of bytes the serialized ResponseFile will occupy. Empty fields are omitted.

func (*ResponseFile) Unmarshal

func (f *ResponseFile) Unmarshal(b []byte) error

Unmarshal decodes wire-format bytes into the ResponseFile.

type WKTInfo

type WKTInfo struct {
	GoImportPath string
	GoTypeName   string
}

WKTInfo holds information about a well-known type's Go representation.

func LookupWKT

func LookupWKT(fullName string) (WKTInfo, bool)

LookupWKT returns the WKTInfo for a given full name, and a boolean indicating whether it was found.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL