Documentation
¶
Overview ¶
Package examples contains worked examples that demonstrate how to express a schema with the v2 generic ZAP API. The canary schema is AdvanceTimeTx — the same one that the v1 [zap_native] package uses as its C-port-shape canary. Comparing the two side-by-side shows exactly what generics buy you.
v1 shape (one file per tx, ~80 lines of hand-rolled boilerplate):
const OffsetAdvanceTimeTx_Time = 1
type AdvanceTimeTx struct { msg *zap.Message; obj zap.Object }
func WrapAdvanceTimeTx(b []byte) (AdvanceTimeTx, error) { ... }
func (t AdvanceTimeTx) Time() uint64 {
return t.obj.Uint64(OffsetAdvanceTimeTx_Time)
}
// ... and so on for every field, every type
v2 shape (declarations only; the generic API does the rest):
type AdvanceTimeSchema struct{}
func (AdvanceTimeSchema) Kind() zapv2.KindByte { return 0x14 }
func (AdvanceTimeSchema) Size() int { return 9 }
func (AdvanceTimeSchema) Name() string { return "AdvanceTimeTx" }
var AdvanceTimeFields = struct {
Time zapv2.Field[AdvanceTimeSchema, uint64]
}{
Time: zapv2.At[AdvanceTimeSchema, uint64](1),
}
That's it. Wrap, Build, Read, Write are all expressed through the generic API.
Index ¶
- Constants
- Variables
- func Items(v zapv2.View[BatchSchema]) zapv2.List[ItemSchema]
- func NewAdvanceTime(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte)
- func NewAdvanceTimeClosure(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte)
- func NewBatch(id uint64, items []Item) (zapv2.View[BatchSchema], []byte)
- func Time(v zapv2.View[AdvanceTimeSchema]) uint64
- func WrapAdvanceTime(b []byte) (zapv2.View[AdvanceTimeSchema], error)
- type AdvanceTimeSchema
- type BatchSchema
- type Item
- type ItemSchema
Constants ¶
const KindAdvanceTime zapv2.KindByte = 1
KindAdvanceTime is the wire discriminator for AdvanceTimeTx. It matches the value in luxfi/node/vms/platformvm/txs/zap_native/ (TxKindAdvanceTime = 1). The byte-equality test in advance_time_tx_test.go pins this so the v2 generic builder produces the exact same bytes as the v1 hand-rolled NewAdvanceTimeTx.
const KindBatch zapv2.KindByte = 0x21
KindBatch is the wire discriminator for BatchTx. Distinct from KindAdvanceTime so Registry dispatch can tell them apart.
const KindItem zapv2.KindByte = 0x22
KindItem identifies ItemSchema. Items live inside BatchTx lists; an Item is never a top-level message, but it has a Kind anyway so the generic List[Item] code can use the same machinery.
const OffsetBatchItems uint32 = 9
OffsetBatchItems is the byte offset of the list pointer for Items within the BatchSchema fixed payload. Items is a variable-length list, so it lives outside the [zapv2.Field] generic vocabulary; it is read via [zapv2.ListAt] instead.
Variables ¶
var AdvanceTimeFields = struct { Time zapv2.Field[AdvanceTimeSchema, uint64] }{ Time: zapv2.At[AdvanceTimeSchema, uint64](1), }
AdvanceTimeFields is the namespace of every field accessor for AdvanceTimeSchema. There is exactly ONE place where offsets are declared; everywhere else uses these typed handles.
Reading: zapv2.Read(view, AdvanceTimeFields.Time) → uint64 Writing: zapv2.Write(setter, AdvanceTimeFields.Time, ts)
A compile error guards against using these handles with any view other than View[AdvanceTimeSchema] — see _compile_fail_test/cross_schema_field.go for the demonstration.
var BatchFields = struct { ID zapv2.Field[BatchSchema, uint64] }{ ID: zapv2.At[BatchSchema, uint64](1), }
BatchFields declares the offsets for BatchSchema.
var ItemFields = struct { ID zapv2.Field[ItemSchema, uint64] Value zapv2.Field[ItemSchema, uint64] }{ ID: zapv2.At[ItemSchema, uint64](0), Value: zapv2.At[ItemSchema, uint64](8), }
ItemFields declares the offsets for ItemSchema.
Functions ¶
func Items ¶
func Items(v zapv2.View[BatchSchema]) zapv2.List[ItemSchema]
Items returns the list of items in the batch as an iter.Seq-ready [zapv2.List]ItemSchema. Range-over-func:
for item := range examples.Items(batchView).All() {
id := zapv2.Read(item, examples.ItemFields.ID)
value := zapv2.Read(item, examples.ItemFields.Value)
// ...
}
func NewAdvanceTime ¶
func NewAdvanceTime(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte)
NewAdvanceTime builds a fresh AdvanceTimeTx with the given timestamp. Returns the typed view and the underlying buffer (they alias the same memory).
Per-schema hand-rolled fast path: calls v1's [zap.NewBuilder] and [zap.StartObject] directly so their inlineable bodies fold into the call site (escape analysis then stack-allocates the transient *Builder and *ObjectBuilder — the only heap alloc is the buffer itself). Result: matches v1's hand-rolled 1-alloc / 48-B profile.
This pattern is what a codegen tool would emit per schema. The generic [zapv2.NewBuilderFor] / [zapv2.Build] paths are equivalent in wire semantics but incur extra allocations because Go generics hide the inlineable v1 primitives behind a non-inlineable shape function — see the BENCH_RESULTS table for the measured cost breakdown.
func NewAdvanceTimeClosure ¶
func NewAdvanceTimeClosure(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte)
NewAdvanceTimeClosure is the closure-style equivalent of NewAdvanceTime. Kept as a documented alternative: it reads more like English at the call site, at the cost of ~3 extra allocations per Build. Use it for cold paths (CLI tools, test fixtures) and reach for the imperative form on hot paths (per-block tx assembly).
func NewBatch ¶
func NewBatch(id uint64, items []Item) (zapv2.View[BatchSchema], []byte)
NewBatch builds a BatchTx with the given ID and items.
func Time ¶
func Time(v zapv2.View[AdvanceTimeSchema]) uint64
Time returns the timestamp the proposer is suggesting the network advance to. Zero copy, zero allocation.
This is the value-side accessor — a thin one-line wrapper around zapv2.Read for callers who prefer method syntax. It is NOT what you'd write in a fresh project; just use zapv2.Read(view, Fields.X) directly. Kept here so the example covers both forms.
func WrapAdvanceTime ¶
func WrapAdvanceTime(b []byte) (zapv2.View[AdvanceTimeSchema], error)
WrapAdvanceTime is the typed accessor over an existing buffer.
Per-schema hand-rolled fast path: parses the wire frame inline, validates the kind discriminator, and composes a typed [zapv2.View[AdvanceTimeSchema]]. Result: matches v1 hand-rolled performance to within compiler noise. Zero heap allocs on the happy path.
Defense-in-depth: the explicit payload bounds check is folded into the per-Read bounds check that lives in [zapv2.Read] — wrapping a short buffer succeeds, but any out-of-range Read returns the zero value (matches v1 graceful-degradation semantics, see [zap.Object.Uint64]).
This pattern is what a codegen tool emits per schema. For cold paths where ergonomics matter more than the last few ns, use the generic [zapv2.Wrap[AdvanceTimeSchema]] instead.
Types ¶
type AdvanceTimeSchema ¶
type AdvanceTimeSchema struct{}
AdvanceTimeSchema is the v2 schema marker for AdvanceTimeTx. The type is the schema's identity; the methods describe its wire shape.
func (AdvanceTimeSchema) Kind ¶
func (AdvanceTimeSchema) Kind() zapv2.KindByte
Kind returns the discriminator byte at object offset 0.
func (AdvanceTimeSchema) Name ¶
func (AdvanceTimeSchema) Name() string
Name returns the human-readable schema name.
func (AdvanceTimeSchema) Size ¶
func (AdvanceTimeSchema) Size() int
Size returns the fixed object payload (1 byte kind + 8 byte time).
type BatchSchema ¶
type BatchSchema struct{}
BatchSchema is a small, multi-element schema used to exercise the generic [zapv2.List] iter.Seq path in tests. Object layout:
@0: KindBatch (uint8) @1: BatchID (uint64) @9: Items (list pointer: relOffset uint32 + length uint32)
Each list element is an ItemSchema (16 bytes: id uint64 + value uint64).
func (BatchSchema) Kind ¶
func (BatchSchema) Kind() zapv2.KindByte
func (BatchSchema) Name ¶
func (BatchSchema) Name() string
func (BatchSchema) Size ¶
func (BatchSchema) Size() int
type ItemSchema ¶
type ItemSchema struct{}
ItemSchema is the per-element schema for BatchTx.Items.
func (ItemSchema) Kind ¶
func (ItemSchema) Kind() zapv2.KindByte
func (ItemSchema) Name ¶
func (ItemSchema) Name() string
func (ItemSchema) Size ¶
func (ItemSchema) Size() int