v0.75.0 — per-row binding, streaming TableReader, @table / @entry, schema reserved-name check
Per-row binding release. Implements protowire v0.74.0 on the Go port. First tagged release after v0.72.0 — collapses the un-tagged v0.73.0 and v0.74.0 CHANGELOG sections together with the v0.75.0 binding sugar into a single release that consumers can go get. Wire format unchanged across all three releases' worth of changes.
What's new since v0.72.0
v0.75.0 (this release's headline content)
pxf.TableReader.Scan(proto.Message)+pxf.BindRowhelper — the per-row binding sugar that turns the streaming row API into a one-liner loop:Same cell-state semantics as the materializing path: empty = absent (tr, err := pxf.NewTableReader(r) for { msg := dynamicpb.NewMessage(desc) if err := tr.Scan(msg); errors.Is(err, io.EOF) { break } process(msg) }
pxf.defaultapplied,pxf.requirederrors),null= clear (wrappers / optional / oneof), value = set. WKT timestamps and durations, enum-by-name resolution, and proto3 wrappers all bind correctly because the implementation reuses the existing Unmarshal pipeline (rather than growing a parallel ~50-arm Value-to-FieldDescriptor switch that would drift).BindRowis also exported standalone for callers iteratingResult.Tables()[i].Rowsfrom the materializing path.
v0.74.0 (rolled in)
pxf.TableReader— streaming@tableconsumption. Reads rows one at a time from anio.Readerwith working-set memory bounded by the size of the largest single row — not by the size of the row sequence. The shape consumers asked for the moment they saw the v0.73 materializing-only API. Multi-table documents chain viatr.Tail(). Per-row arity and v1 cell-grammar errors surface as the offending row is consumed (not deferred to end-of-input), per draft §3.4.4 "Streaming consumption". New API:NewTableReader,Type(),Columns(),Directives(),Tail(),Next(), plusErrNoTable.
v0.73.0 (rolled in)
- Schema reserved-name check.
pxf.ValidateFile/pxf.ValidateDescriptorwalk a protobuf FileDescriptor and report every message-field, oneof, or enum-value name that case-sensitively collides withnull,true, orfalse— names that lex as PXF value keywords and produce silently-unreachable bindings. Runs by default at the top of everyUnmarshal*call;UnmarshalOptions.SkipValidateopts out for pre-validated descriptors. @entrydirective + zero-or-more prefix list.named_directiveaccepts*( IDENT )between@<name>and the optional{ ... }block (was[ IDENT ]). The parser uses one-token lookahead to keep a body field key from being eaten as a directive prefix.pxf.Directivegrows aPrefixes []stringfield; the legacyTypefield is preserved (populated whenlen(Prefixes) == 1) so v0.72.0-era consumers (chameleon's@headerreader) keep working unchanged.@tabledirective. New top-level form for bulk-row datasets — the protowire-native CSV replacement:Three cell states (empty /@table <type> ( col1, col2, ... ) ( val1, val2, ... ) ( val1, val2, ... )null/ value) map onto the existingpxf.required/pxf.defaultsemantics with zero new annotations. v1 restrictions: scalar cells only (no[...]/{...}), unqualified column names only, strict row arity, standalone document (no@type, no top-level body entries). Tables flow throughUnmarshalFullviaResult.Tables(). Per-row binding viaTableReader.Scan(new in this release) closes the loop.
Backward compatibility
- Schema reserved-name check rejects schemas declaring
enum Choice { null = 0; }and similar. These bindings were already silently broken; rejecting them at decode time surfaces a pre-existing bug rather than introducing one. Callers that need to keep accepting them can setUnmarshalOptions.SkipValidate = true(not recommended). Directive.Typesemantics shift slightly: today it's "the optional second identifier after@<name>"; now it's "the single identifier, if there was exactly one." Practical impact is zero — v0.72.0 only emitted directives with zero-or-one identifier, and the back-compat rule preserves that case. Two-prefix directives (new in@entry) leaveTypeempty by design; new code readsPrefixesdirectly.- Wire format unchanged across all three rolled-in releases.
Conformance
Ports that don't already have these features must:
- Add a descriptor-bind reserved-name check (~30 LoC).
- Relax
named_directiveto accept zero-or-more prefix identifiers. - Implement
@table(new lexer keyword, new parser path, consumer-API surface). - Optionally expose a streaming row API (
MAYper draft §3.4.4 — not required for spec conformance, but recommended for the CSV-replacement workload).
See CHANGELOG.md for the per-version-section breakdown.