Documentation
¶
Overview ¶
Package pxf implements the PXF text format codec for protobuf messages.
PXF (Protocol-buffer eXchange Format) is a human-editable, comment-aware text encoding for protobuf messages. The format spec, grammar, and canonical fixtures live in the sibling repository trendvidia/protowire; this package is the Go reference implementation.
Choosing a code path ¶
Three top-level entry points serve different needs:
- Unmarshal / Marshal — fast path. A fused single-pass lexer+decoder writes directly into the google.golang.org/protobuf/proto.Message with zero-copy token strings and no AST allocations. Use this in hot paths or when you do not need the source comments.
- UnmarshalFull — like Unmarshal but returns a Result tracking which fields were set, null, or absent, validating required fields, and applying defaults from (pxf.required) / (pxf.default) annotations.
- Parse / FormatDocument — AST path. Produces a Document with comments attached to entries. Use when you need to round-trip a PXF document while preserving its formatting and comments.
Concurrency ¶
The package-level functions (Unmarshal, Marshal, Parse, FormatDocument) are safe for concurrent use — they do not share mutable state. The MarshalOptions and UnmarshalOptions value types are also safe to share, provided the TypeResolver embedded in them is concurrency-safe (the registry-client resolver from trendvidia/protoregistry is).
A Result returned from UnmarshalFull is not safe for concurrent modification, but read-only access from multiple goroutines is fine.
Index ¶
- Constants
- Variables
- func ApplyDefault(msg protoreflect.Message, fd protoreflect.FieldDescriptor, def string) error
- func BindRow(msg proto.Message, columns []string, row DatasetRow) error
- func Default(fd protoreflect.FieldDescriptor) (string, bool)
- func FormatDocument(doc *Document) []byte
- func IsRequired(fd protoreflect.FieldDescriptor) bool
- func Marshal(msg proto.Message) ([]byte, error)
- func Unmarshal(data []byte, msg proto.Message) error
- func UnmarshalDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, error)
- type Assignment
- type Block
- type BlockVal
- type BoolVal
- type BytesVal
- type Comment
- type DatasetDirective
- type DatasetReader
- type DatasetRow
- type Directive
- type Document
- type DurationVal
- type Entry
- type Error
- type FloatVal
- type IdentVal
- type IntVal
- type ListVal
- type MapEntry
- type MarshalOptions
- type NullVal
- type Position
- type ProtoDirective
- type ProtoShape
- type Result
- func (r *Result) Datasets() []DatasetDirective
- func (r *Result) Directives() []Directive
- func (r *Result) IsAbsent(path string) bool
- func (r *Result) IsNull(path string) bool
- func (r *Result) IsSet(path string) bool
- func (r *Result) NullFields() []string
- func (r *Result) PresentFields() []string
- func (r *Result) Protos() []ProtoDirective
- type StringVal
- type TimestampVal
- type Token
- type TokenKind
- type TypeResolver
- type UnmarshalOptions
- func (o UnmarshalOptions) Unmarshal(data []byte, msg proto.Message) error
- func (o UnmarshalOptions) UnmarshalDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, error)
- func (o UnmarshalOptions) UnmarshalFull(data []byte, msg proto.Message) (*Result, error)
- func (o UnmarshalOptions) UnmarshalFullDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, *Result, error)
- type Value
- type Violation
- type ViolationKind
Constants ¶
const MaxNestingDepth = 100
MaxNestingDepth caps PXF block / list nesting and PB submessage nesting, per protowire/docs/HARDENING.md § Recursion. The limit applies to the recursive-descent decoders for both formats; iterative skip routines (skipBraced/skipBracketed) use the same cap implicitly because they only run on already-bounded inputs.
Variables ¶
var ErrNoDataset = errors.New("pxf: no @dataset directive in stream")
ErrNoDataset is returned by NewDatasetReader when the input contains no @dataset directive before EOF. Inspect with errors.Is.
Functions ¶
func ApplyDefault ¶ added in v0.71.0
func ApplyDefault(msg protoreflect.Message, fd protoreflect.FieldDescriptor, def string) error
ApplyDefault parses a (pxf.default) value string and sets it on the given message field. The string is the same PXF literal form the annotation accepts: `42` for ints, `true`/`false` for bools, `"hello"` for strings, base64 for bytes, RFC3339 for timestamps inside their inner fields, etc.
Exported for layered-config consumers (e.g. chameleon) that run a post-merge defaults pass with [UnmarshalOptions.SkipPostDecode]. In-tree callers (postDecode) use the lowercase alias.
func BindRow ¶ added in v0.75.0
func BindRow(msg proto.Message, columns []string, row DatasetRow) error
BindRow binds row.Cells to the fields of msg by column name. The columns slice MUST have the same length as row.Cells; mismatch is a programmer error and panics.
Exported so callers iterating the materializing path's Result.Datasets()[i].Rows can reuse the same logic. Same cell-state semantics as DatasetReader.Scan.
func Default ¶ added in v0.71.0
func Default(fd protoreflect.FieldDescriptor) (string, bool)
Default returns the (pxf.default) value string if set. The string is a PXF literal (e.g. `42`, `true`, `"hello"`); callers parse it with ApplyDefault or their own logic. Exported for layered-config consumers running post-merge defaults passes.
func FormatDocument ¶
FormatDocument pretty-prints an AST Document, preserving comments. Unlike Marshal (which works from a proto.Message and loses comments), this formats directly from the parsed AST.
func IsRequired ¶ added in v0.71.0
func IsRequired(fd protoreflect.FieldDescriptor) bool
IsRequired reports whether the field has (pxf.required) = true. Exported for layered-config consumers (e.g. chameleon) that run their own post-merge required-validation pass with SkipPostDecode.
func UnmarshalDescriptor ¶
func UnmarshalDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, error)
UnmarshalDescriptor parses PXF data using the given message descriptor.
Types ¶
type Assignment ¶
type Assignment struct {
Pos Position
Key string
Value Value
LeadingComments []Comment // comments on lines before this entry
TrailingComment string // inline comment after value on same line
}
Assignment represents "key = value" (field assignment in message context).
type BlockVal ¶
BlockVal is an anonymous block value: { entries }. Used for maps (key: value pairs) and inline messages in lists.
type Comment ¶
type Comment struct {
Pos Position
Text string // raw text including the comment prefix (# or // or /* */)
}
Comment represents a comment in source text.
type DatasetDirective ¶ added in v1.0.0
type DatasetDirective struct {
Pos Position
Type string // row message type, e.g. "trades.v1.Trade"; empty if bound to a preceding anonymous @proto
Columns []string // top-level field names on Type; len(Columns) >= 1
Rows []DatasetRow // zero or more rows
LeadingComments []Comment
}
DatasetDirective is a `@dataset <type> ( col1, col2, ... ) row*` entry at document root (draft §3.4.4). It carries many instances of one message type in a single document — the protowire-native CSV.
Cells are scalar-shaped in v1: list ('[ ... ]') and block ('{ ... }') values are not permitted in cells. An empty cell (no value between commas) denotes an absent field; a `null` literal denotes a present- but-null field; any other value denotes a present field with that value. See DatasetRow for cell representation.
A document with any DatasetDirective MUST NOT have a @type directive or any top-level field entries: the @dataset header IS the document's type declaration. Decoders enforce this in Parse.
Type MAY be empty when an anonymous @proto directive (draft §3.4.5) precedes the @dataset in document order; the anonymous schema is consumed as the row message type.
type DatasetReader ¶ added in v1.0.0
type DatasetReader struct {
// contains filtered or unexported fields
}
DatasetReader streams rows of a single `@dataset` directive from an io.Reader (draft §3.4.4 "Streaming consumption"). Use it for datasets too large to materialize via Parse / UnmarshalFull.
A DatasetReader is positioned at the first row after NewDatasetReader returns. Call DatasetReader.Next in a loop until it returns io.EOF; the table's row sequence is exhausted at that point.
For documents containing multiple `@dataset` directives, call NewDatasetReader again on the same underlying io.Reader to read the next table — the previous reader leaves the underlying reader positioned just past its last row.
A DatasetReader is NOT safe for concurrent use.
func NewDatasetReader ¶ added in v1.0.0
func NewDatasetReader(r io.Reader) (*DatasetReader, error)
NewDatasetReader consumes any leading directives (`@type`, `@<name>`, etc.) and the `@dataset TYPE ( cols )` header, returning a reader positioned at the first row.
Returns ErrNoDataset if the input ends before any `@dataset` directive is seen. Returns a wrapped parse/IO error otherwise.
The header (everything from the start of the input up through and including the `)` of the column list) must fit in 64 KiB. This is a fail-fast bound — real headers are tiny.
func (*DatasetReader) Columns ¶ added in v1.0.0
func (tr *DatasetReader) Columns() []string
Columns returns the column field names declared by the @dataset header, in source order.
func (*DatasetReader) Directives ¶ added in v1.0.0
func (tr *DatasetReader) Directives() []Directive
Directives returns the side-channel directives (`@<name>` / `@entry` / etc., NOT `@type` or `@dataset`) that appeared before the `@dataset` header. The slice is stable for the lifetime of the reader. Useful for consumers that attach per-table metadata via a preceding directive.
func (*DatasetReader) Next ¶ added in v1.0.0
func (tr *DatasetReader) Next() (DatasetRow, error)
Next reads the next row. Returns io.EOF when the table's row sequence is exhausted. After EOF (or any other error), all subsequent calls return the same error.
The returned DatasetRow's Cells slice is freshly allocated and owned by the caller; reading the next row does not invalidate it.
func (*DatasetReader) Scan ¶ added in v1.0.0
func (tr *DatasetReader) Scan(msg proto.Message) error
Scan reads the next row and binds its cells to the matching fields of msg by column name. Returns io.EOF when the row sequence is exhausted; returns the same sticky error as DatasetReader.Next on any read or parse failure.
msg's descriptor MUST resolve the field names this reader's Columns() list refers to. Type compatibility against the @dataset header's declared type is the caller's responsibility — a row whose columns don't match msg's fields surfaces as a per-field "field not found" or type-mismatch error from the underlying Unmarshal call.
Cell-state semantics (mirrors draft §3.4.4):
- nil Value (empty cell) — field absent. (pxf.default) is applied if declared on the field; (pxf.required) errors if neither default nor value is present.
- *NullVal — field cleared, per §3.9 (clears optional / wrapper / oneof; rejects on non-nullable scalars).
- any other Value — field set to that value.
func (*DatasetReader) Tail ¶ added in v1.0.0
func (tr *DatasetReader) Tail() io.Reader
Tail returns an io.Reader that yields the bytes the DatasetReader has buffered but not consumed, followed by any remaining bytes from the underlying source. Use it to chain a second NewDatasetReader call for documents containing multiple `@dataset` directives:
tr1, err := pxf.NewDatasetReader(src) // ... iterate tr1.Next() to io.EOF ... tr2, err := pxf.NewDatasetReader(tr1.Tail())
Tail MUST only be called after Next has returned io.EOF. Calling it earlier returns bytes the current reader still intends to consume, which will desync the next reader. The returned io.Reader is unbuffered; consumers needing bufio semantics should wrap it themselves.
func (*DatasetReader) Type ¶ added in v1.0.0
func (tr *DatasetReader) Type() string
Type returns the row message type declared by the @dataset header (e.g. "trades.v1.Trade").
type DatasetRow ¶ added in v1.0.0
type DatasetRow struct {
Pos Position
Cells []Value // nil entries denote absent fields; len == len(dataset.Columns)
}
DatasetRow is one parenthesized cell tuple in a @dataset directive. Cells is the same length as the containing DatasetDirective.Columns. A nil Value in Cells denotes an absent field (the "empty cell" between two commas); a *NullVal denotes a present-but-null field; any other Value denotes a present field with that value.
type Directive ¶ added in v0.72.0
type Directive struct {
Pos Position
Name string // e.g. "header"; never "type" (those go to Document.TypeURL)
Prefixes []string // identifiers between @<name> and the optional `{ ... }`, in source order
// Type is preserved for v0.72.0-era consumers: when exactly one
// prefix identifier was supplied, Type holds it (matching the
// previous single-Type field's behavior). For zero or two-plus
// prefixes, Type is empty and callers MUST read Prefixes directly.
// New code should use Prefixes; Type is retained to avoid churning
// downstream consumers that haven't migrated.
Type string
Body []byte // raw inner bytes of the block; nil if the directive has no `{ ... }`
LeadingComments []Comment
}
Directive is a top-of-document `@<name> *(<prefix-id>) [{ ... }]` entry. The canonical use is side-channel metadata that sits alongside the schema-typed body — e.g. chameleon's `@header chameleon.v1.LayerHeader { id = "x" }` — but the grammar is open-ended: any name except `type` is accepted, followed by zero-or-more prefix identifiers and an optional inline block.
Prefix identifiers are positional and per-directive. The two registrations defined by the protowire spec:
- One prefix identifier (v0.72.0 conventional shape) — the identifier names the inner block's message type, dotted. Used by `@header` and similar.
- `@entry` (draft §3.4.3) — zero, one, or two prefix identifiers (label, type); a single prefix is disambiguated by the presence of a `.` (dotted ⇒ type; bare ⇒ label).
Body holds the RAW bytes between the opening `{` and matching `}` (both exclusive), suitable for handing back to UnmarshalFull / Unmarshal against the consumer's chosen message. Body is nil when the directive has no inline block.
type Document ¶
type Document struct {
TypeURL string // from @type directive, may be empty
Directives []Directive // @<name> *(prefix) [{ ... }] entries before the body, in source order; excludes spec-defined directives
Datasets []DatasetDirective // @dataset directives in source order; per draft §3.4.4 a document with any @dataset MUST NOT have @type or body entries
Protos []ProtoDirective // @proto directives in source order (draft §3.4.5)
BodyOffset int // byte offset in the input where the schema-typed body begins (after all leading directives)
Entries []Entry
LeadingComments []Comment // comments before the first entry (or after @type)
}
Document is the root AST node of a PXF file.
type DurationVal ¶
DurationVal is a Go-style duration literal (e.g. 30s, 1h30m).
type Entry ¶
type Entry interface {
// contains filtered or unexported methods
}
Entry is a node that can appear in a message or map body.
type MapEntry ¶
type MapEntry struct {
Pos Position
Key string
Value Value
LeadingComments []Comment
TrailingComment string
}
MapEntry represents "key: value" (entry in map context).
type MarshalOptions ¶
type MarshalOptions struct {
Indent string // indentation per level, default " "
EmitDefaults bool // emit fields with zero values
TypeURL string // emit @type directive if non-empty
TypeResolver TypeResolver // resolve Any type URLs for sugar encoding
NullFields *Result // emit null fields from a Result (for messages without null_mask)
}
MarshalOptions configures PXF encoding.
type Position ¶
Position represents a location in source text.
Offset is the byte index into the input where the token starts. It is populated by the lexer and used by callers that need to slice the original byte stream (e.g. directive body extraction).
type ProtoDirective ¶ added in v1.0.0
type ProtoDirective struct {
Pos Position
Shape ProtoShape
TypeName string // dotted message type name; non-empty only when Shape == ProtoNamed
Body []byte
LeadingComments []Comment
}
ProtoDirective is a `@proto <body>` entry at document root (draft §3.4.5). It carries an embedded protobuf schema, making the PXF document self-describing.
The Shape field distinguishes the four lexically-determined body forms (anonymous, named, source, descriptor). Body holds the raw bytes of the body, interpreted per Shape:
- ProtoAnonymous, ProtoNamed: the bytes between the opening `{` and matching `}` (both exclusive). The bytes are protobuf message-body source (field declarations and nested types) and must be compiled by a downstream consumer.
- ProtoSource: the contents of the triple-quoted string (with leading-LF stripping and common-prefix dedent already applied). The bytes are a complete .proto source file.
- ProtoDescriptor: the base64-decoded bytes of the bytes literal. The bytes are a serialised google.protobuf.FileDescriptorSet.
type ProtoShape ¶ added in v1.0.0
type ProtoShape int
ProtoShape distinguishes the four body shapes of a @proto directive (draft §3.4.5).
const ( // ProtoAnonymous is `@proto { <message-body> }` — defines an // unnamed message used by the next typed directive in document // order that does not carry an explicit type name. ProtoAnonymous ProtoShape = iota // ProtoNamed is `@proto <dotted-name> { <message-body> }` — sugar // for a single named message; TypeName carries the dotted name. ProtoNamed // ProtoSource is `@proto """<proto-source>"""` — a complete // Protocol Buffers source file. ProtoSource // ProtoDescriptor is `@proto b"<base64-FileDescriptorSet>"` — // a base64-encoded google.protobuf.FileDescriptorSet. ProtoDescriptor )
func (ProtoShape) String ¶ added in v1.0.0
func (s ProtoShape) String() string
type Result ¶
type Result struct {
// contains filtered or unexported fields
}
Result captures field-level presence metadata from PXF decoding. It tracks which fields were explicitly set, which were set to null, and which were absent from the input. Fields are identified by dotted paths (e.g., "name", "nested.value").
func UnmarshalFull ¶
UnmarshalFull decodes PXF data into msg and returns field presence metadata. Unlike Unmarshal, it tracks which fields are set, null, or absent, validates required fields, and applies default values.
func UnmarshalFullDescriptor ¶
func UnmarshalFullDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, *Result, error)
UnmarshalFullDescriptor parses PXF data using the given message descriptor and returns field presence metadata. It validates required fields and applies defaults.
func (*Result) Datasets ¶ added in v1.0.0
func (r *Result) Datasets() []DatasetDirective
Datasets returns the `@dataset` directives the decoder saw at the document root, in source order. Each DatasetDirective carries a row message type, a column list, and a sequence of row tuples. See draft §3.4.4 for cell-state semantics.
A document that uses `@dataset` will have an empty body — the rows are the document's payload, not the bound message. Callers walk each DatasetDirective.Rows and bind each row's cells to a fresh instance of DatasetDirective.Type via the consumer-supplied schema.
func (*Result) Directives ¶ added in v0.72.0
Directives returns the `@<name> *(prefix) [{ ... }]` blocks the decoder saw at the document root, in source order. Excludes the spec-defined directives (`@type`, `@dataset`, `@proto`, `@entry`), which have their own accessors. Callers typically iterate and call UnmarshalFull on each Directive.Body against their chosen message.
func (*Result) IsAbsent ¶
IsAbsent reports whether the field at the given path was not mentioned in the input.
func (*Result) IsNull ¶
IsNull reports whether the field at the given path was explicitly set to null. Use dotted paths for nested fields: "nested.value".
func (*Result) IsSet ¶
IsSet reports whether the field at the given path was set to a concrete (non-null) value.
func (*Result) NullFields ¶
NullFields returns the paths of all fields explicitly set to null.
func (*Result) PresentFields ¶ added in v0.71.0
PresentFields returns the paths of all fields encountered during parsing — both fields set to a concrete value and fields set to null. Equivalent to the union of Result.IsSet and Result.IsNull paths.
Useful for layered-config systems (chameleon) that union per-layer presence into a merged-result presence set, then run defaults / required-validation against that union.
func (*Result) Protos ¶ added in v1.0.0
func (r *Result) Protos() []ProtoDirective
Protos returns the `@proto` directives the decoder saw at the document root, in source order. Each ProtoDirective carries one of four body shapes (anonymous, named, source, descriptor) per draft §3.4.5; callers inspect Shape and decode Body accordingly.
type TimestampVal ¶
TimestampVal is an RFC 3339 timestamp literal.
type TokenKind ¶
type TokenKind int
TokenKind represents the type of a lexical token.
const ( EOF TokenKind = iota ILLEGAL // invalid token NEWLINE // \n COMMENT // # or // or /* */ IDENT // field_name, EnumValue, package.Name STRING // "hello" or """multi-line""" INT // 123, -456 FLOAT // 1.23, -4.5 BOOL // true, false NULL // null BYTES // b"base64..." TIMESTAMP // 2024-01-15T10:30:00Z DURATION // 30s, 1h30m LBRACE // { RBRACE // } LBRACKET // [ RBRACKET // ] LPAREN // ( used by @dataset column list and row tuples RPAREN // ) EQUALS // = COLON // : COMMA // , AT_TYPE // @type — body's message type, no inline block AT_DATASET // @dataset — row-oriented bulk-data directive (draft §3.4.4) AT_PROTO // @proto — embedded protobuf schema (draft §3.4.5) AT_DIRECTIVE // @<name> for any non-reserved name — Value holds the name (without @) )
type TypeResolver ¶
type TypeResolver interface {
FindMessageByURL(url string) (protoreflect.MessageDescriptor, error)
}
TypeResolver resolves protobuf type URLs to message descriptors. Required for encoding/decoding google.protobuf.Any fields with sugar syntax.
type UnmarshalOptions ¶
type UnmarshalOptions struct {
// TypeResolver resolves type URLs for google.protobuf.Any fields.
// When set, Any fields use sugar syntax: @type = "..." + inline fields.
// When nil, Any fields decode as regular messages (type_url + value).
TypeResolver TypeResolver
// DiscardUnknown silently skips fields not found in the schema
// instead of returning an error.
DiscardUnknown bool
// SkipPostDecode disables the per-parse pass that applies
// (pxf.default) values to absent fields and validates
// (pxf.required) fields. Layered configuration systems (e.g.
// chameleon) need defaults + required to apply on the MERGED
// result, not per-layer — a base layer may legitimately omit a
// required field that a higher layer provides, and per-layer
// defaults silently get clobbered by merge's "absent → fall
// through" rule. With SkipPostDecode = true, callers get raw
// presence tracking and run their own post-merge passes via
// [IsRequired] and [Default].
SkipPostDecode bool
// SkipValidate disables the per-call schema reserved-name check
// (draft §3.13). The default behavior — running the check on every
// decode call — is the safe one because the check catches schemas
// that would silently produce unreachable enum values or fields.
// Callers that have already validated their descriptors out-of-band
// (e.g. a registry-load step that pre-screens schemas before
// caching their descriptors) may set this to bypass the per-call
// recheck. Validate explicitly via [ValidateDescriptor] when
// pre-screening.
SkipValidate bool
// OnSecretField, if non-nil, is called for each pxf.Secret-typed
// field whose value is supplied via scalar shorthand (the common
// form: `pw = "x"`, list element `["a", "b"]`, map value
// `{ "acme": "k" }`). The hook receives the dotted field path and
// the value string. When the hook returns nil, the decoder skips
// the standard assignment to the inner `value` field on the Secret
// message — the caller is responsible for routing the value to
// whatever destination honors its own memory-management contract
// (e.g. a memguard Enclave). Presence tracking on `value` is still
// updated so Result.IsSet reports the field as set.
//
// Path scheme:
//
// pw = "x" → "pw"
// db { password = "x" } → "db.password"
// backup_keys = ["a", "b"] → "backup_keys[0]", "backup_keys[1]"
// tenant_keys = { "acme": "k" } → "tenant_keys[acme]"
//
// Block-form Secrets — `pw { value = "x", hint = "h" }` — are NOT
// routed through this hook in this release; their value still lands
// on Secret.Value via the standard string-field path. Callers that
// need a closed memory window for block-form secrets should
// post-process the message (e.g. chameleon's parse.Move walker) or
// normalize their PXF to scalar shorthand. Hint and fingerprint
// metadata are always assigned to the proto message; they are
// diagnostic, not sensitive.
//
// Errors from the hook abort the decode and propagate.
OnSecretField func(path, value string) error
}
UnmarshalOptions configures PXF decoding.
func (UnmarshalOptions) Unmarshal ¶
func (o UnmarshalOptions) Unmarshal(data []byte, msg proto.Message) error
Unmarshal parses PXF data into msg.
func (UnmarshalOptions) UnmarshalDescriptor ¶
func (o UnmarshalOptions) UnmarshalDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, error)
UnmarshalDescriptor parses PXF data using the given message descriptor.
func (UnmarshalOptions) UnmarshalFull ¶
UnmarshalFull decodes PXF data into msg and returns field presence metadata.
func (UnmarshalOptions) UnmarshalFullDescriptor ¶
func (o UnmarshalOptions) UnmarshalFullDescriptor(data []byte, desc protoreflect.MessageDescriptor) (*dynamicpb.Message, *Result, error)
UnmarshalFullDescriptor parses PXF data using the given message descriptor and returns field presence metadata.
type Value ¶
type Value interface {
// contains filtered or unexported methods
}
Value is an expression on the right side of = or :.
type Violation ¶ added in v0.75.0
type Violation struct {
// File is the .proto file path the offending element is declared in.
File string
// Element is the fully-qualified protobuf name of the element
// (e.g. "trades.v1.Side.null").
Element string
// Name is the bare reserved identifier ("null" / "true" / "false").
Name string
// Kind is the kind of element that collided.
Kind ViolationKind
}
Violation describes one schema element whose name collides with a reserved PXF keyword. Returned by ValidateDescriptor.
func ValidateDescriptor ¶ added in v0.75.0
func ValidateDescriptor(desc protoreflect.MessageDescriptor) []Violation
ValidateDescriptor walks the file containing desc and returns every reserved-name collision among messages, oneofs, and enum values reachable from that file. The returned slice is sorted by element fully-qualified name for stable output. A nil/empty slice means the schema is conformant.
The check is case-sensitive: identifiers such as "NULL" or "True" lex as ordinary identifiers and are accepted.
func ValidateFile ¶ added in v0.75.0
func ValidateFile(fd protoreflect.FileDescriptor) []Violation
ValidateFile walks fd and returns every reserved-name collision in the file. See ValidateDescriptor for the rule and semantics.
type ViolationKind ¶ added in v0.75.0
type ViolationKind int
ViolationKind identifies which kind of schema element collides with a reserved PXF value keyword.
const ( // ViolationField is a message field whose name is reserved. ViolationField ViolationKind = iota + 1 // ViolationOneof is a oneof declaration whose name is reserved. ViolationOneof // ViolationEnumValue is an enum value whose name is reserved. ViolationEnumValue )
func (ViolationKind) String ¶ added in v0.75.0
func (k ViolationKind) String() string