rename v2 -> v1: the typed-view API + codegen is the canonical 1.0 (no v2, ever)

There is one perfected typed ZAP layer and it lives at github.com/luxfi/zap/v1 —
forwards-only, no backwards-compat baggage, never a breaking major. Mechanical,
behavior-preserving: v2/ -> v1/ (git mv), package zapv2 -> zapv1, import path
.../zap/v2 -> .../zap/v1 (incl. the codegen's emitted banner + import so
generated files reference /v1). Codegen golden tests pass; typed layer vets
clean. (Pre-existing CGO 'resolv' link failures in the root package are
unrelated env noise.)
This commit is contained in:
zeekay
2026-06-23 15:05:15 -07:00
parent 634ed2379a
commit e457893743
44 changed files with 405 additions and 405 deletions
+1 -1
View File
@@ -282,7 +282,7 @@ func (ob *ObjectBuilder) ensureField(endOffset int) {
// backwards).
//
// This is the exported counterpart to the internal ensureField helper.
// It is used by zapv2.WriteList to keep the parent's payload reserved
// It is used by zapv1.WriteList to keep the parent's payload reserved
// before list elements are appended.
func (ob *ObjectBuilder) ReserveFixed(dataSize int) {
ob.ensureField(dataSize)
+1 -1
View File
@@ -7,7 +7,7 @@
// which emits v1-equivalent fast paths from a declarative .zap source.
//
// Consumer dispatch for ad-hoc / dynamic schemas goes through the v2
// generic API (github.com/luxfi/zap/v2).
// generic API (github.com/luxfi/zap/v1).
//
// The v1 hand-rolled code in this package remains for in-flight
// migration of legacy callers (luxfi/node/vms/platformvm/txs/zap_native,
View File
@@ -13,8 +13,8 @@
// Expected output (Go 1.23+):
//
// ./cross_schema_field.go:NN:NN: cannot use AlphaFields.X (variable
// of type zapv2.Field[AlphaSchema, uint64]) as
// zapv2.Field[BetaSchema, uint64] value in argument to zapv2.Read
// of type zapv1.Field[AlphaSchema, uint64]) as
// zapv1.Field[BetaSchema, uint64] value in argument to zapv1.Read
//
// The directory name begins with an underscore so `go build ./...`
// at the v2 root skips it; only an explicit build path includes it,
@@ -23,44 +23,44 @@
package compile_fail_demo
import (
"github.com/luxfi/zap/v2"
"github.com/luxfi/zap/v1"
)
// AlphaSchema is one schema...
type AlphaSchema struct{}
func (AlphaSchema) Kind() zapv2.KindByte { return 0xA1 }
func (AlphaSchema) Kind() zapv1.KindByte { return 0xA1 }
func (AlphaSchema) Size() int { return 16 }
func (AlphaSchema) Name() string { return "Alpha" }
// BetaSchema is a different schema...
type BetaSchema struct{}
func (BetaSchema) Kind() zapv2.KindByte { return 0xB1 }
func (BetaSchema) Kind() zapv1.KindByte { return 0xB1 }
func (BetaSchema) Size() int { return 16 }
func (BetaSchema) Name() string { return "Beta" }
var (
AlphaFields = struct {
X zapv2.Field[AlphaSchema, uint64]
}{X: zapv2.At[AlphaSchema, uint64](1)}
X zapv1.Field[AlphaSchema, uint64]
}{X: zapv1.At[AlphaSchema, uint64](1)}
BetaFields = struct {
Y zapv2.Field[BetaSchema, uint64]
}{Y: zapv2.At[BetaSchema, uint64](1)}
Y zapv1.Field[BetaSchema, uint64]
}{Y: zapv1.At[BetaSchema, uint64](1)}
)
// crossSchemaRead is the load-bearing compile-time-safety
// demonstration. The compiler MUST reject this because
// AlphaFields.X is a Field[AlphaSchema, uint64] but the View is
// View[BetaSchema] — the type parameters do not unify.
func crossSchemaRead(beta zapv2.View[BetaSchema]) uint64 {
return zapv2.Read(beta, AlphaFields.X) // COMPILE ERROR
func crossSchemaRead(beta zapv1.View[BetaSchema]) uint64 {
return zapv1.Read(beta, AlphaFields.X) // COMPILE ERROR
}
// crossTypeWrite tries to write an int64 into a Field declared for
// uint64. The compiler MUST reject this because the value type does
// not match the field's T parameter.
func crossTypeWrite(s zapv2.Setter[AlphaSchema]) {
zapv2.Write(s, AlphaFields.X, int64(42)) // COMPILE ERROR
func crossTypeWrite(s zapv1.Setter[AlphaSchema]) {
zapv1.Write(s, AlphaFields.X, int64(42)) // COMPILE ERROR
}
+10 -10
View File
@@ -1,14 +1,14 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2_test
package zapv1_test
import (
"testing"
"github.com/luxfi/zap"
"github.com/luxfi/zap/v2"
"github.com/luxfi/zap/v2/examples"
"github.com/luxfi/zap/v1"
"github.com/luxfi/zap/v1/examples"
)
// Benchmark baseline reference:
@@ -34,8 +34,8 @@ import (
// changing the v2 API.
// BenchmarkGeneric_Build_AdvanceTime builds the canary AdvanceTimeTx
// via the imperative-style v2 generic API ([zapv2.NewBuilderFor] +
// [zapv2.WriteB] + Finish). Targets matching v1's 1-alloc profile.
// via the imperative-style v2 generic API ([zapv1.NewBuilderFor] +
// [zapv1.WriteB] + Finish). Targets matching v1's 1-alloc profile.
func BenchmarkGeneric_Build_AdvanceTime(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
@@ -76,7 +76,7 @@ func BenchmarkGeneric_Read_AdvanceTime(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
v, _ := examples.WrapAdvanceTime(buf)
_ = zapv2.Read(v, examples.AdvanceTimeFields.Time)
_ = zapv1.Read(v, examples.AdvanceTimeFields.Time)
}
}
@@ -109,7 +109,7 @@ func BenchmarkGeneric_Read_NoParse(b *testing.B) {
b.ReportAllocs()
var sink uint64
for i := 0; i < b.N; i++ {
sink = zapv2.Read(view, examples.AdvanceTimeFields.Time)
sink = zapv1.Read(view, examples.AdvanceTimeFields.Time)
}
_ = sink
}
@@ -152,7 +152,7 @@ func BenchmarkGeneric_List_Range(b *testing.B) {
for i := 0; i < b.N; i++ {
var sum uint64
for v := range list.All() {
sum += zapv2.Read(v, examples.ItemFields.Value)
sum += zapv1.Read(v, examples.ItemFields.Value)
}
_ = sum
}
@@ -175,7 +175,7 @@ func BenchmarkGeneric_List_Range_Payloads(b *testing.B) {
for i := 0; i < b.N; i++ {
var sum uint64
for p := range list.Payloads() {
sum += zapv2.ReadPayload(p, examples.ItemFields.Value)
sum += zapv1.ReadPayload(p, examples.ItemFields.Value)
}
_ = sum
}
@@ -216,7 +216,7 @@ func BenchmarkHandRolled_List_Range(b *testing.B) {
// have zero allocations per Get/Put pair once it's warm.
func BenchmarkPool_GetPut(b *testing.B) {
type Box struct{ N uint64 }
pool := zapv2.NewPool(func() *Box { return &Box{} })
pool := zapv1.NewPool(func() *Box { return &Box{} })
// Warm up the pool.
for i := 0; i < 100; i++ {
pool.Put(pool.Get())
+3 -3
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import (
"github.com/luxfi/zap"
@@ -16,8 +16,8 @@ import (
//
// Usage:
//
// bb := zapv2.NewBuilderFor[AdvanceTimeSchema]()
// zapv2.WriteB(bb, examples.AdvanceTimeFields.Time, ts)
// bb := zapv1.NewBuilderFor[AdvanceTimeSchema]()
// zapv1.WriteB(bb, examples.AdvanceTimeFields.Time, ts)
// view, buf := bb.Finish()
//
// WriteB is the explicit-receiver counterpart to [Write] — both take
@@ -53,7 +53,7 @@ import (
"strconv"
"strings"
"github.com/luxfi/zap/v2/codegen"
"github.com/luxfi/zap/v1/codegen"
)
// schemaSpec is the JSON wire shape for a single schema. It is the
@@ -22,7 +22,7 @@ import (
"strconv"
"strings"
"github.com/luxfi/zap/v2/codegen"
"github.com/luxfi/zap/v1/codegen"
)
type fieldFlag struct {
+5 -5
View File
@@ -12,7 +12,7 @@
// into its caller, so the call site pays a function-call cost (~5-7
// ns on modern hardware). The work performed by a "Wrap" function
// (parse the ZAP wire frame, validate the kind discriminator, build
// a typed view) exceeds that budget. The generic [zapv2.Wrap[S]]
// a typed view) exceeds that budget. The generic [zapv1.Wrap[S]]
// function therefore costs one function call per Wrap, even when
// every other primitive in its body would inline.
//
@@ -32,7 +32,7 @@
// For a schema declared as:
//
// type AdvanceTimeSchema struct{}
// func (AdvanceTimeSchema) Kind() zapv2.KindByte { return 1 }
// func (AdvanceTimeSchema) Kind() zapv1.KindByte { return 1 }
// func (AdvanceTimeSchema) Size() int { return 9 }
// func (AdvanceTimeSchema) Name() string { return "AdvanceTimeTx" }
//
@@ -44,7 +44,7 @@
// const kindAdvanceTimeTx uint8 = 1
// const offsetAdvanceTimeTx_Time = 1
//
// func WrapAdvanceTime(b []byte) (zapv2.View[AdvanceTimeSchema], error) {
// func WrapAdvanceTime(b []byte) (zapv1.View[AdvanceTimeSchema], error) {
// msg, err := zap.Parse(b)
// ...
// }
@@ -61,8 +61,8 @@
// file, a Cap'n-Proto-style schema file, struct tags) and want
// ZAP v2 accessors emitted automatically.
//
// For cold paths and ad-hoc schemas, the generic [zapv2.Wrap[S]] /
// [zapv2.Build[S]] are equally correct and one extra function call
// For cold paths and ad-hoc schemas, the generic [zapv1.Wrap[S]] /
// [zapv1.Build[S]] are equally correct and one extra function call
// slower — which is rarely the bottleneck.
//
// # Status
+30 -30
View File
@@ -9,7 +9,7 @@ import (
"strings"
)
// typeToSize maps a [zapv2.FieldKind] Go type name to its byte width.
// typeToSize maps a [zapv1.FieldKind] Go type name to its byte width.
// Used by the field-write code to pick the right ObjectBuilder.Set*
// method.
var typeToSize = map[string]int{
@@ -68,12 +68,12 @@ func fieldByteSize(f Field) (int, bool) {
// v1 hand-rolled performance to within compiler noise — verified by
// the bench suite.
//
// Scalar fields go through the [zapv2.Field][S, T] generic handle
// Scalar fields go through the [zapv1.Field][S, T] generic handle
// (declared in the per-schema <GoName>Fields var). Fixed-width
// byte-array fields ("bytes<N>") are emitted as standalone typed
// accessor functions that call v1's SetBytesFixed / BytesFixedSlice
// — they do NOT appear in the Fields struct because [N]byte is not a
// [zapv2.FieldKind] member. Both forms produce the same wire layout.
// [zapv1.FieldKind] member. Both forms produce the same wire layout.
func Emit(w io.Writer, s Schema) error {
// Validate field types + offsets.
for _, f := range s.Fields {
@@ -109,21 +109,21 @@ func Emit(w io.Writer, s Schema) error {
fmt.Fprintf(w, `// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//
// Code generated by github.com/luxfi/zap/v2/codegen — DO NOT EDIT.
// Code generated by github.com/luxfi/zap/v1/codegen — DO NOT EDIT.
// Source schema: %s (kind=0x%02x, size=%d).
package %s
import (
"github.com/luxfi/zap"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
`, s.WireName, s.Kind, s.Size, s.Package)
// Constants.
fmt.Fprintf(w, `// Kind%s is the wire discriminator for %s.
const Kind%s zapv2.KindByte = 0x%02x
const Kind%s zapv1.KindByte = 0x%02x
// Size%s is the fixed object payload size in bytes.
const Size%s = %d
@@ -133,11 +133,11 @@ const Size%s = %d
// Schema marker type.
fmt.Fprintf(w, `// %s is the v2 schema marker for %s. Methods are constant-
// returning so concrete-typed [zapv2.Wrap[%s]] calls fold to
// returning so concrete-typed [zapv1.Wrap[%s]] calls fold to
// literals at the call site.
type %s struct{}
func (%s) Kind() zapv2.KindByte { return Kind%s }
func (%s) Kind() zapv1.KindByte { return Kind%s }
func (%s) Size() int { return Size%s }
func (%s) Name() string { return %q }
@@ -157,10 +157,10 @@ func (%s) Name() string { return %q }
// Byte-array fields are handled by standalone accessor functions
// (emitted after the constructor) because [N]byte is not a
// FieldKind union member.
// Scalar fields go in the Fields struct (zapv2.Field handles).
// Scalar fields go in the Fields struct (zapv1.Field handles).
// Fixed byte-arrays and variable-length tails (string/bytes) get
// standalone typed accessors instead — neither [N]byte nor string/
// []byte is a zapv2.FieldKind member.
// []byte is a zapv1.FieldKind member.
var scalarFields []Field
var accessorFields []Field
for _, f := range s.Fields {
@@ -174,15 +174,15 @@ func (%s) Name() string { return %q }
if len(scalarFields) > 0 {
fmt.Fprintf(w, "// %sFields is the namespace of every scalar field accessor for %s.\n",
s.GoName, s.WireName)
fmt.Fprintf(w, "// Use with [zapv2.Read] / [zapv2.Write] for type-safe access.\n")
fmt.Fprintf(w, "// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.\n")
fmt.Fprintf(w, "// Byte-array fields are emitted as standalone functions, see below.\nvar %sFields = struct {\n",
s.GoName)
for _, f := range scalarFields {
fmt.Fprintf(w, "\t%s zapv2.Field[%s, %s]\n", f.Name, s.GoName, f.Type)
fmt.Fprintf(w, "\t%s zapv1.Field[%s, %s]\n", f.Name, s.GoName, f.Type)
}
fmt.Fprintf(w, "}{\n")
for _, f := range scalarFields {
fmt.Fprintf(w, "\t%s: zapv2.At[%s, %s](%d),\n",
fmt.Fprintf(w, "\t%s: zapv1.At[%s, %s](%d),\n",
f.Name, s.GoName, f.Type, f.Offset)
}
fmt.Fprintf(w, "}\n\n")
@@ -244,7 +244,7 @@ func emitNewConstructor(w io.Writer, s Schema, scalar, accessor []Field) {
// so the entire build expands at the call site. Scalars and fixed byte
// arrays live in the fixed payload; variable-length string/bytes go in
// the object tail (the fixed payload holds their 8-byte pointers).
func New%s(%s) (zapv2.View[%s], []byte) {
func New%s(%s) (zapv1.View[%s], []byte) {
b := zap.NewBuilder(%s)
ob := b.StartObject(Size%s)
ob.SetUint8(0, uint8(Kind%s))
@@ -273,7 +273,7 @@ func New%s(%s) (zapv2.View[%s], []byte) {
fmt.Fprintf(w, ` rootOff := ob.FinishAsRoot()
buf := b.Finish()
end := rootOff + Size%s
return zapv2.AsView[%s](zapv2.RawFromSlices(buf, rootOff, end)), buf
return zapv1.AsView[%s](zapv1.RawFromSlices(buf, rootOff, end)), buf
}
`, s.WireName, s.GoName)
@@ -283,22 +283,22 @@ func New%s(%s) (zapv2.View[%s], []byte) {
// type-checks a buffer. The body uses v1 primitives so it inlines.
func emitWrapFunction(w io.Writer, s Schema) {
fmt.Fprintf(w, `// Wrap%s parses a ZAP buffer into a typed
// [zapv2.View[%s]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv2.SchemaError] on kind
// [zapv1.View[%s]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv1.SchemaError] on kind
// mismatch.
//
// Hand-rolled fast path: inlines [zap.Parse] (which is itself
// inlineable). Zero heap allocs on the happy path; matches v1
// hand-rolled performance.
func Wrap%s(b []byte) (zapv2.View[%s], error) {
func Wrap%s(b []byte) (zapv1.View[%s], error) {
msg, err := zap.Parse(b)
if err != nil {
return zapv2.View[%s]{}, err
return zapv1.View[%s]{}, err
}
root := msg.Root()
if got := root.Uint8(0); got != uint8(Kind%s) {
return zapv2.View[%s]{}, zapv2.NewSchemaError(
Kind%s, zapv2.KindByte(got), %q)
return zapv1.View[%s]{}, zapv1.NewSchemaError(
Kind%s, zapv1.KindByte(got), %q)
}
data := msg.Bytes()
rootOff := root.Offset()
@@ -306,7 +306,7 @@ func Wrap%s(b []byte) (zapv2.View[%s], error) {
if end > len(data) {
end = len(data) // Read returns zero on OOB; v1 graceful degradation
}
return zapv2.AsView[%s](zapv2.RawFromSlices(data, rootOff, end)), nil
return zapv1.AsView[%s](zapv1.RawFromSlices(data, rootOff, end)), nil
}
`, s.WireName, s.WireName,
@@ -335,9 +335,9 @@ func emitAccessorFields(w io.Writer, s Schema, fields []Field) {
//
// Zero-copy: v1's Object.Text returns a string over a sub-slice of the
// underlying buffer. Valid only while the View's buffer is alive.
func %s%s(v zapv2.View[%s]) string {
func %s%s(v zapv1.View[%s]) string {
msg := zap.WrapBuffer(v.Bytes())
obj := msg.RootObjectAt(int(zapv2.RootOff(v)))
obj := msg.RootObjectAt(int(zapv1.RootOff(v)))
return obj.Text(Offset%s_%s)
}
@@ -349,9 +349,9 @@ func %s%s(v zapv2.View[%s]) string {
//
// Zero-copy: v1's Object.Bytes returns a sub-slice of the underlying
// buffer. Valid only while the View's buffer is alive; copy to retain.
func %s%s(v zapv2.View[%s]) []byte {
func %s%s(v zapv1.View[%s]) []byte {
msg := zap.WrapBuffer(v.Bytes())
obj := msg.RootObjectAt(int(zapv2.RootOff(v)))
obj := msg.RootObjectAt(int(zapv1.RootOff(v)))
return obj.Bytes(Offset%s_%s)
}
@@ -366,9 +366,9 @@ func %s%s(v zapv2.View[%s]) []byte {
// a sub-slice of the underlying buffer); the returned [%d]byte is a
// value copy so the caller's slot owns the bytes after the View's
// buffer is freed.
func %s%s(v zapv2.View[%s]) [%d]byte {
func %s%s(v zapv1.View[%s]) [%d]byte {
msg := zap.WrapBuffer(v.Bytes())
obj := msg.RootObjectAt(int(zapv2.RootOff(v)))
obj := msg.RootObjectAt(int(zapv1.RootOff(v)))
slice := obj.BytesFixedSlice(Offset%s_%s, %d)
var out [%d]byte
if len(slice) == %d {
@@ -388,7 +388,7 @@ func %s%s(v zapv2.View[%s]) [%d]byte {
}
// emitRegisterInit writes an init function that registers the schema
// with the [zapv2.DefaultRegistry]. Skipped when [Schema.SkipRegistry]
// with the [zapv1.DefaultRegistry]. Skipped when [Schema.SkipRegistry]
// is true, used for schemas whose Kind byte is local to a per-package
// (private) registry rather than globally unique.
func emitRegisterInit(w io.Writer, s Schema) {
@@ -396,7 +396,7 @@ func emitRegisterInit(w io.Writer, s Schema) {
return
}
fmt.Fprintf(w, `func init() {
zapv2.Register[%s](zapv2.DefaultRegistry)
zapv1.Register[%s](zapv1.DefaultRegistry)
}
`, s.GoName)
}
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"github.com/luxfi/zap/v2/codegen"
"github.com/luxfi/zap/v1/codegen"
)
// TestEmit_AdvanceTime: the canary schema emits source that compiles
@@ -40,12 +40,12 @@ func TestEmit_AdvanceTime(t *testing.T) {
// Load-bearing markers — the things downstream code uses.
wants := []string{
"package examples",
"KindAdvanceTimeTx zapv2.KindByte = 0x01",
"KindAdvanceTimeTx zapv1.KindByte = 0x01",
"SizeAdvanceTimeTx = 9",
"type AdvanceTimeSchema struct{}",
"OffsetAdvanceTimeTx_Time = 1",
"AdvanceTimeSchemaFields",
"Time zapv2.Field[AdvanceTimeSchema, uint64]",
"Time zapv1.Field[AdvanceTimeSchema, uint64]",
"func NewAdvanceTimeTx(time uint64)",
"func WrapAdvanceTimeTx(b []byte)",
"zap.NewBuilder(zap.HeaderSize + SizeAdvanceTimeTx)",
@@ -54,9 +54,9 @@ func TestEmit_AdvanceTime(t *testing.T) {
"zap.Parse(b)",
"msg.Root()",
"root.Uint8(0)",
"zapv2.AsView[AdvanceTimeSchema]",
"zapv2.RawFromSlices",
"zapv2.Register[AdvanceTimeSchema](zapv2.DefaultRegistry)",
"zapv1.AsView[AdvanceTimeSchema]",
"zapv1.RawFromSlices",
"zapv1.Register[AdvanceTimeSchema](zapv1.DefaultRegistry)",
}
for _, want := range wants {
if !strings.Contains(out, want) {
@@ -117,9 +117,9 @@ func TestEmit_VarLength(t *testing.T) {
"zap.HeaderSize + SizeVarTx + len(name) + len(data)", // buffer estimate
"ob.SetText(OffsetVarTx_Name, name)",
"ob.SetBytes(OffsetVarTx_Data, data)",
"func VarTxName(v zapv2.View[VarSchema]) string",
"func VarTxName(v zapv1.View[VarSchema]) string",
"return obj.Text(OffsetVarTx_Name)",
"func VarTxData(v zapv2.View[VarSchema]) []byte",
"func VarTxData(v zapv1.View[VarSchema]) []byte",
"return obj.Bytes(OffsetVarTx_Data)",
}
for _, want := range wants {
@@ -128,7 +128,7 @@ func TestEmit_VarLength(t *testing.T) {
}
}
// Variable fields must NOT appear in the scalar Fields struct.
if strings.Contains(out, "Name zapv2.Field[") || strings.Contains(out, "Data zapv2.Field[") {
if strings.Contains(out, "Name zapv1.Field[") || strings.Contains(out, "Data zapv1.Field[") {
t.Errorf("variable fields must not be in the scalar Fields struct")
}
}
@@ -155,14 +155,14 @@ func TestEmit_BytesField(t *testing.T) {
}
out := buf.String()
wants := []string{
"KindBlockRequest zapv2.KindByte = 0x53",
"KindBlockRequest zapv1.KindByte = 0x53",
"SizeBlockRequest = 34",
"OffsetBlockRequest_Version = 1",
"OffsetBlockRequest_BlockID = 2",
// Scalar field in Fields struct
"Version zapv2.Field[BlockReqSchema, uint8]",
"Version zapv1.Field[BlockReqSchema, uint8]",
// Byte-array field NOT in Fields struct, instead its own function:
"func BlockRequestBlockID(v zapv2.View[BlockReqSchema]) [32]byte",
"func BlockRequestBlockID(v zapv1.View[BlockReqSchema]) [32]byte",
// Constructor takes both scalar and byte-array args
"func NewBlockRequest(version uint8, blockID [32]byte)",
// Constructor body writes both
@@ -246,9 +246,9 @@ func TestEmit_MultiField(t *testing.T) {
}
out := buf.String()
wants := []string{
"KindBatchTx zapv2.KindByte = 0x21",
"Flag zapv2.Field[BatchSchema, bool]",
"ID zapv2.Field[BatchSchema, uint64]",
"KindBatchTx zapv1.KindByte = 0x21",
"Flag zapv1.Field[BatchSchema, bool]",
"ID zapv1.Field[BatchSchema, uint64]",
"OffsetBatchTx_Flag = 1",
"OffsetBatchTx_ID = 9",
"ob.SetBool(OffsetBatchTx_Flag, flag)",
+12 -12
View File
@@ -27,10 +27,10 @@ type Schema struct {
// ("bytes<N>"), and variable-length tails ("string"/"bytes"). Each
// occupies a slot in the fixed payload (variable-length fields hold
// an 8-byte tail pointer there). List and nested-object tails are
// not declared here; they use the generic [zapv2.ListAt] machinery.
// not declared here; they use the generic [zapv1.ListAt] machinery.
Fields []Field
// SkipRegistry suppresses the emit of `init() { zapv2.Register[S]
// (zapv2.DefaultRegistry) }`. Use for schema families that have a
// SkipRegistry suppresses the emit of `init() { zapv1.Register[S]
// (zapv1.DefaultRegistry) }`. Use for schema families that have a
// PRIVATE Kind namespace (the discriminator byte is unique only
// within a per-package registry, not globally). Examples:
//
@@ -40,7 +40,7 @@ type Schema struct {
// would panic on duplicate kind byte at init time.
// - LP-182 consensus wire: the 0x01..0x0D kind bytes are local to
// the consensus-wire registry (`pkg/wire/zap/schemas.go`), not
// the global zapv2.DefaultRegistry shared with P2P/light-client
// the global zapv1.DefaultRegistry shared with P2P/light-client
// schemas at 0xD0+/0xF0+.
//
// Default is false — schemas with globally-unique Kind bytes
@@ -52,18 +52,18 @@ type Schema struct {
//
// Two field kinds are supported:
//
// 1. Scalar fields. Type is one of the [zapv2.FieldKind] members
// 1. Scalar fields. Type is one of the [zapv1.FieldKind] members
// (bool, int8/16/32/64, uint8/16/32/64, float32/64). The emitted
// code uses a [zapv2.Field][S, T] handle and the standard
// zapv2.Read/Write generic functions.
// code uses a [zapv1.Field][S, T] handle and the standard
// zapv1.Read/Write generic functions.
//
// 2. Fixed-width byte-array fields. Type is "bytes<N>" where N is a
// positive integer (e.g., "bytes20" for NodeID, "bytes32" for
// hashes, "bytes16" for session IDs). The emitted code uses the
// v1 ObjectBuilder.SetBytesFixed / Object.BytesFixedSlice
// accessors and returns the value as a [N]byte. Byte-array fields
// do NOT use the zapv2.Field generic handle because [N]byte is
// not a [zapv2.FieldKind] member; instead they get a typed
// do NOT use the zapv1.Field generic handle because [N]byte is
// not a [zapv1.FieldKind] member; instead they get a typed
// accessor function emitted alongside the schema.
//
// 3. Variable-length tail fields. Type is "string" or "bytes" (no
@@ -73,11 +73,11 @@ type Schema struct {
// ObjectBuilder.SetText / SetBytes; reads go through a standalone
// accessor over v1's Object.Text / Object.Bytes (zero-copy
// sub-slice of the buffer). Like byte-array fields, they do NOT use
// the zapv2.Field generic handle (string/[]byte are not FieldKind
// the zapv1.Field generic handle (string/[]byte are not FieldKind
// members).
//
// List and nested-object tail fields are still hand-written (the
// generic [zapv2.ListAt] / out-of-line pointer machinery).
// generic [zapv1.ListAt] / out-of-line pointer machinery).
type Field struct {
// Name is the Go-visible field name (e.g. "Time"). Emitted into
// the schema's Fields struct as `<SchemaGoName>Fields.Name`.
@@ -129,5 +129,5 @@ func (f Field) IsVarBytes() bool { return f.Type == "bytes" }
// IsVariable reports whether the field is any variable-length tail field
// (string or bytes). Variable fields are emitted as standalone accessor
// functions (like fixed byte arrays) rather than in the Fields struct,
// because string/[]byte are not zapv2.FieldKind members.
// because string/[]byte are not zapv1.FieldKind members.
func (f Field) IsVariable() bool { return f.IsVarString() || f.IsVarBytes() }
@@ -1,28 +1,28 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//
// Code generated by github.com/luxfi/zap/v2/codegen — DO NOT EDIT.
// Code generated by github.com/luxfi/zap/v1/codegen — DO NOT EDIT.
// Source schema: LightClientBlockHeaderRequest (kind=0x50, size=51).
package lcwire
import (
"github.com/luxfi/zap"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// KindLightClientBlockHeaderRequest is the wire discriminator for LightClientBlockHeaderRequest.
const KindLightClientBlockHeaderRequest zapv2.KindByte = 0x50
const KindLightClientBlockHeaderRequest zapv1.KindByte = 0x50
// SizeLightClientBlockHeaderRequest is the fixed object payload size in bytes.
const SizeLightClientBlockHeaderRequest = 51
// LCBlockHeaderReqSchema is the v2 schema marker for LightClientBlockHeaderRequest. Methods are constant-
// returning so concrete-typed [zapv2.Wrap[LCBlockHeaderReqSchema]] calls fold to
// returning so concrete-typed [zapv1.Wrap[LCBlockHeaderReqSchema]] calls fold to
// literals at the call site.
type LCBlockHeaderReqSchema struct{}
func (LCBlockHeaderReqSchema) Kind() zapv2.KindByte { return KindLightClientBlockHeaderRequest }
func (LCBlockHeaderReqSchema) Kind() zapv1.KindByte { return KindLightClientBlockHeaderRequest }
func (LCBlockHeaderReqSchema) Size() int { return SizeLightClientBlockHeaderRequest }
func (LCBlockHeaderReqSchema) Name() string { return "LightClientBlockHeaderRequest" }
@@ -45,20 +45,20 @@ const OffsetLightClientBlockHeaderRequest_CertMinTier = 46
const OffsetLightClientBlockHeaderRequest_RequestID = 47
// LCBlockHeaderReqSchemaFields is the namespace of every scalar field accessor for LightClientBlockHeaderRequest.
// Use with [zapv2.Read] / [zapv2.Write] for type-safe access.
// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.
// Byte-array fields are emitted as standalone functions, see below.
var LCBlockHeaderReqSchemaFields = struct {
Version zapv2.Field[LCBlockHeaderReqSchema, uint8]
ChainID zapv2.Field[LCBlockHeaderReqSchema, uint32]
BlockHeight zapv2.Field[LCBlockHeaderReqSchema, uint64]
CertMinTier zapv2.Field[LCBlockHeaderReqSchema, uint8]
RequestID zapv2.Field[LCBlockHeaderReqSchema, uint32]
Version zapv1.Field[LCBlockHeaderReqSchema, uint8]
ChainID zapv1.Field[LCBlockHeaderReqSchema, uint32]
BlockHeight zapv1.Field[LCBlockHeaderReqSchema, uint64]
CertMinTier zapv1.Field[LCBlockHeaderReqSchema, uint8]
RequestID zapv1.Field[LCBlockHeaderReqSchema, uint32]
}{
Version: zapv2.At[LCBlockHeaderReqSchema, uint8](1),
ChainID: zapv2.At[LCBlockHeaderReqSchema, uint32](2),
BlockHeight: zapv2.At[LCBlockHeaderReqSchema, uint64](6),
CertMinTier: zapv2.At[LCBlockHeaderReqSchema, uint8](46),
RequestID: zapv2.At[LCBlockHeaderReqSchema, uint32](47),
Version: zapv1.At[LCBlockHeaderReqSchema, uint8](1),
ChainID: zapv1.At[LCBlockHeaderReqSchema, uint32](2),
BlockHeight: zapv1.At[LCBlockHeaderReqSchema, uint64](6),
CertMinTier: zapv1.At[LCBlockHeaderReqSchema, uint8](46),
RequestID: zapv1.At[LCBlockHeaderReqSchema, uint32](47),
}
// NewLightClientBlockHeaderRequest builds a fresh LightClientBlockHeaderRequest in a ZAP buffer.
@@ -67,7 +67,7 @@ var LCBlockHeaderReqSchemaFields = struct {
// [*Builder.StartObject], [*ObjectBuilder.Set*], [*Builder.Finish])
// so the entire build expands at the call site. Result: 1 heap
// alloc (the buffer), zero overhead vs v1.
func NewLightClientBlockHeaderRequest(version uint8, chainID uint32, blockHeight uint64, certMinTier uint8, requestID uint32, blockContentHash [32]byte) (zapv2.View[LCBlockHeaderReqSchema], []byte) {
func NewLightClientBlockHeaderRequest(version uint8, chainID uint32, blockHeight uint64, certMinTier uint8, requestID uint32, blockContentHash [32]byte) (zapv1.View[LCBlockHeaderReqSchema], []byte) {
b := zap.NewBuilder(zap.HeaderSize + SizeLightClientBlockHeaderRequest)
ob := b.StartObject(SizeLightClientBlockHeaderRequest)
ob.SetUint8(0, uint8(KindLightClientBlockHeaderRequest))
@@ -80,26 +80,26 @@ func NewLightClientBlockHeaderRequest(version uint8, chainID uint32, blockHeight
rootOff := ob.FinishAsRoot()
buf := b.Finish()
end := rootOff + SizeLightClientBlockHeaderRequest
return zapv2.AsView[LCBlockHeaderReqSchema](zapv2.RawFromSlices(buf, rootOff, end)), buf
return zapv1.AsView[LCBlockHeaderReqSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
}
// WrapLightClientBlockHeaderRequest parses a ZAP buffer into a typed
// [zapv2.View[LightClientBlockHeaderRequest]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv2.SchemaError] on kind
// [zapv1.View[LightClientBlockHeaderRequest]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv1.SchemaError] on kind
// mismatch.
//
// Hand-rolled fast path: inlines [zap.Parse] (which is itself
// inlineable). Zero heap allocs on the happy path; matches v1
// hand-rolled performance.
func WrapLightClientBlockHeaderRequest(b []byte) (zapv2.View[LCBlockHeaderReqSchema], error) {
func WrapLightClientBlockHeaderRequest(b []byte) (zapv1.View[LCBlockHeaderReqSchema], error) {
msg, err := zap.Parse(b)
if err != nil {
return zapv2.View[LCBlockHeaderReqSchema]{}, err
return zapv1.View[LCBlockHeaderReqSchema]{}, err
}
root := msg.Root()
if got := root.Uint8(0); got != uint8(KindLightClientBlockHeaderRequest) {
return zapv2.View[LCBlockHeaderReqSchema]{}, zapv2.NewSchemaError(
KindLightClientBlockHeaderRequest, zapv2.KindByte(got), "LightClientBlockHeaderRequest")
return zapv1.View[LCBlockHeaderReqSchema]{}, zapv1.NewSchemaError(
KindLightClientBlockHeaderRequest, zapv1.KindByte(got), "LightClientBlockHeaderRequest")
}
data := msg.Bytes()
rootOff := root.Offset()
@@ -107,7 +107,7 @@ func WrapLightClientBlockHeaderRequest(b []byte) (zapv2.View[LCBlockHeaderReqSch
if end > len(data) {
end = len(data) // Read returns zero on OOB; v1 graceful degradation
}
return zapv2.AsView[LCBlockHeaderReqSchema](zapv2.RawFromSlices(data, rootOff, end)), nil
return zapv1.AsView[LCBlockHeaderReqSchema](zapv1.RawFromSlices(data, rootOff, end)), nil
}
// LightClientBlockHeaderRequestBlockContentHash reads the 32-byte inline BlockContentHash field of LightClientBlockHeaderRequest.
@@ -116,9 +116,9 @@ func WrapLightClientBlockHeaderRequest(b []byte) (zapv2.View[LCBlockHeaderReqSch
// a sub-slice of the underlying buffer); the returned [32]byte is a
// value copy so the caller's slot owns the bytes after the View's
// buffer is freed.
func LightClientBlockHeaderRequestBlockContentHash(v zapv2.View[LCBlockHeaderReqSchema]) [32]byte {
func LightClientBlockHeaderRequestBlockContentHash(v zapv1.View[LCBlockHeaderReqSchema]) [32]byte {
msg := zap.WrapBuffer(v.Bytes())
obj := msg.RootObjectAt(int(zapv2.RootOff(v)))
obj := msg.RootObjectAt(int(zapv1.RootOff(v)))
slice := obj.BytesFixedSlice(OffsetLightClientBlockHeaderRequest_BlockContentHash, 32)
var out [32]byte
if len(slice) == 32 {
@@ -128,5 +128,5 @@ func LightClientBlockHeaderRequestBlockContentHash(v zapv2.View[LCBlockHeaderReq
}
func init() {
zapv2.Register[LCBlockHeaderReqSchema](zapv2.DefaultRegistry)
zapv1.Register[LCBlockHeaderReqSchema](zapv1.DefaultRegistry)
}
@@ -6,7 +6,7 @@ package consensuswire
import (
"testing"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// BenchmarkQuasarCert_Build measures the codegen-emitted NewQuasarCert
@@ -61,7 +61,7 @@ func BenchmarkQuasarCert_RoundTrip(b *testing.B) {
if err != nil {
b.Fatalf("Wrap: %v", err)
}
_ = zapv2.Read(view, QuasarCertSchemaFields.Epoch)
_ = zapv1.Read(view, QuasarCertSchemaFields.Epoch)
}
}
@@ -81,6 +81,6 @@ func BenchmarkQuasarCert_Read(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = zapv2.Read(view, QuasarCertSchemaFields.Epoch)
_ = zapv1.Read(view, QuasarCertSchemaFields.Epoch)
}
}
@@ -1,28 +1,28 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//
// Code generated by github.com/luxfi/zap/v2/codegen — DO NOT EDIT.
// Code generated by github.com/luxfi/zap/v1/codegen — DO NOT EDIT.
// Source schema: QuasarCert (kind=0x01, size=72).
package consensuswire
import (
"github.com/luxfi/zap"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// KindQuasarCert is the wire discriminator for QuasarCert.
const KindQuasarCert zapv2.KindByte = 0x01
const KindQuasarCert zapv1.KindByte = 0x01
// SizeQuasarCert is the fixed object payload size in bytes.
const SizeQuasarCert = 72
// QuasarCertSchema is the v2 schema marker for QuasarCert. Methods are constant-
// returning so concrete-typed [zapv2.Wrap[QuasarCertSchema]] calls fold to
// returning so concrete-typed [zapv1.Wrap[QuasarCertSchema]] calls fold to
// literals at the call site.
type QuasarCertSchema struct{}
func (QuasarCertSchema) Kind() zapv2.KindByte { return KindQuasarCert }
func (QuasarCertSchema) Kind() zapv1.KindByte { return KindQuasarCert }
func (QuasarCertSchema) Size() int { return SizeQuasarCert }
func (QuasarCertSchema) Name() string { return "QuasarCert" }
@@ -66,36 +66,36 @@ const OffsetQuasarCert_MLDSARollupOff = 64
const OffsetQuasarCert_MLDSARollupLen = 68
// QuasarCertSchemaFields is the namespace of every scalar field accessor for QuasarCert.
// Use with [zapv2.Read] / [zapv2.Write] for type-safe access.
// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.
// Byte-array fields are emitted as standalone functions, see below.
var QuasarCertSchemaFields = struct {
Epoch zapv2.Field[QuasarCertSchema, uint64]
FinalityUnixNano zapv2.Field[QuasarCertSchema, int64]
Validators zapv2.Field[QuasarCertSchema, uint32]
BLSOff zapv2.Field[QuasarCertSchema, uint32]
BLSLen zapv2.Field[QuasarCertSchema, uint32]
CoronaOff zapv2.Field[QuasarCertSchema, uint32]
CoronaLen zapv2.Field[QuasarCertSchema, uint32]
PulsarOff zapv2.Field[QuasarCertSchema, uint32]
PulsarLen zapv2.Field[QuasarCertSchema, uint32]
MagnetarOff zapv2.Field[QuasarCertSchema, uint32]
MagnetarLen zapv2.Field[QuasarCertSchema, uint32]
MLDSARollupOff zapv2.Field[QuasarCertSchema, uint32]
MLDSARollupLen zapv2.Field[QuasarCertSchema, uint32]
Epoch zapv1.Field[QuasarCertSchema, uint64]
FinalityUnixNano zapv1.Field[QuasarCertSchema, int64]
Validators zapv1.Field[QuasarCertSchema, uint32]
BLSOff zapv1.Field[QuasarCertSchema, uint32]
BLSLen zapv1.Field[QuasarCertSchema, uint32]
CoronaOff zapv1.Field[QuasarCertSchema, uint32]
CoronaLen zapv1.Field[QuasarCertSchema, uint32]
PulsarOff zapv1.Field[QuasarCertSchema, uint32]
PulsarLen zapv1.Field[QuasarCertSchema, uint32]
MagnetarOff zapv1.Field[QuasarCertSchema, uint32]
MagnetarLen zapv1.Field[QuasarCertSchema, uint32]
MLDSARollupOff zapv1.Field[QuasarCertSchema, uint32]
MLDSARollupLen zapv1.Field[QuasarCertSchema, uint32]
}{
Epoch: zapv2.At[QuasarCertSchema, uint64](8),
FinalityUnixNano: zapv2.At[QuasarCertSchema, int64](16),
Validators: zapv2.At[QuasarCertSchema, uint32](24),
BLSOff: zapv2.At[QuasarCertSchema, uint32](32),
BLSLen: zapv2.At[QuasarCertSchema, uint32](36),
CoronaOff: zapv2.At[QuasarCertSchema, uint32](40),
CoronaLen: zapv2.At[QuasarCertSchema, uint32](44),
PulsarOff: zapv2.At[QuasarCertSchema, uint32](48),
PulsarLen: zapv2.At[QuasarCertSchema, uint32](52),
MagnetarOff: zapv2.At[QuasarCertSchema, uint32](56),
MagnetarLen: zapv2.At[QuasarCertSchema, uint32](60),
MLDSARollupOff: zapv2.At[QuasarCertSchema, uint32](64),
MLDSARollupLen: zapv2.At[QuasarCertSchema, uint32](68),
Epoch: zapv1.At[QuasarCertSchema, uint64](8),
FinalityUnixNano: zapv1.At[QuasarCertSchema, int64](16),
Validators: zapv1.At[QuasarCertSchema, uint32](24),
BLSOff: zapv1.At[QuasarCertSchema, uint32](32),
BLSLen: zapv1.At[QuasarCertSchema, uint32](36),
CoronaOff: zapv1.At[QuasarCertSchema, uint32](40),
CoronaLen: zapv1.At[QuasarCertSchema, uint32](44),
PulsarOff: zapv1.At[QuasarCertSchema, uint32](48),
PulsarLen: zapv1.At[QuasarCertSchema, uint32](52),
MagnetarOff: zapv1.At[QuasarCertSchema, uint32](56),
MagnetarLen: zapv1.At[QuasarCertSchema, uint32](60),
MLDSARollupOff: zapv1.At[QuasarCertSchema, uint32](64),
MLDSARollupLen: zapv1.At[QuasarCertSchema, uint32](68),
}
// NewQuasarCert builds a fresh QuasarCert in a ZAP buffer.
@@ -104,7 +104,7 @@ var QuasarCertSchemaFields = struct {
// [*Builder.StartObject], [*ObjectBuilder.Set*], [*Builder.Finish])
// so the entire build expands at the call site. Result: 1 heap
// alloc (the buffer), zero overhead vs v1.
func NewQuasarCert(epoch uint64, finalityUnixNano int64, validators uint32, bLSOff uint32, bLSLen uint32, coronaOff uint32, coronaLen uint32, pulsarOff uint32, pulsarLen uint32, magnetarOff uint32, magnetarLen uint32, mLDSARollupOff uint32, mLDSARollupLen uint32) (zapv2.View[QuasarCertSchema], []byte) {
func NewQuasarCert(epoch uint64, finalityUnixNano int64, validators uint32, bLSOff uint32, bLSLen uint32, coronaOff uint32, coronaLen uint32, pulsarOff uint32, pulsarLen uint32, magnetarOff uint32, magnetarLen uint32, mLDSARollupOff uint32, mLDSARollupLen uint32) (zapv1.View[QuasarCertSchema], []byte) {
b := zap.NewBuilder(zap.HeaderSize + SizeQuasarCert)
ob := b.StartObject(SizeQuasarCert)
ob.SetUint8(0, uint8(KindQuasarCert))
@@ -124,26 +124,26 @@ func NewQuasarCert(epoch uint64, finalityUnixNano int64, validators uint32, bLSO
rootOff := ob.FinishAsRoot()
buf := b.Finish()
end := rootOff + SizeQuasarCert
return zapv2.AsView[QuasarCertSchema](zapv2.RawFromSlices(buf, rootOff, end)), buf
return zapv1.AsView[QuasarCertSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
}
// WrapQuasarCert parses a ZAP buffer into a typed
// [zapv2.View[QuasarCert]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv2.SchemaError] on kind
// [zapv1.View[QuasarCert]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv1.SchemaError] on kind
// mismatch.
//
// Hand-rolled fast path: inlines [zap.Parse] (which is itself
// inlineable). Zero heap allocs on the happy path; matches v1
// hand-rolled performance.
func WrapQuasarCert(b []byte) (zapv2.View[QuasarCertSchema], error) {
func WrapQuasarCert(b []byte) (zapv1.View[QuasarCertSchema], error) {
msg, err := zap.Parse(b)
if err != nil {
return zapv2.View[QuasarCertSchema]{}, err
return zapv1.View[QuasarCertSchema]{}, err
}
root := msg.Root()
if got := root.Uint8(0); got != uint8(KindQuasarCert) {
return zapv2.View[QuasarCertSchema]{}, zapv2.NewSchemaError(
KindQuasarCert, zapv2.KindByte(got), "QuasarCert")
return zapv1.View[QuasarCertSchema]{}, zapv1.NewSchemaError(
KindQuasarCert, zapv1.KindByte(got), "QuasarCert")
}
data := msg.Bytes()
rootOff := root.Offset()
@@ -151,6 +151,6 @@ func WrapQuasarCert(b []byte) (zapv2.View[QuasarCertSchema], error) {
if end > len(data) {
end = len(data) // Read returns zero on OOB; v1 graceful degradation
}
return zapv2.AsView[QuasarCertSchema](zapv2.RawFromSlices(data, rootOff, end)), nil
return zapv1.AsView[QuasarCertSchema](zapv1.RawFromSlices(data, rootOff, end)), nil
}
@@ -21,7 +21,7 @@ import (
"encoding/binary"
"testing"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// TestQuasarCert_RoundTrip: build with distinctive values for every
@@ -72,25 +72,25 @@ func TestQuasarCert_RoundTrip(t *testing.T) {
t.Fatalf("WrapQuasarCert: %v", err)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.Epoch); got != want.Epoch {
if got := zapv1.Read(view2, QuasarCertSchemaFields.Epoch); got != want.Epoch {
t.Errorf("Epoch = %#x; want %#x", got, want.Epoch)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.FinalityUnixNano); got != want.FinalityUnixNano {
if got := zapv1.Read(view2, QuasarCertSchemaFields.FinalityUnixNano); got != want.FinalityUnixNano {
t.Errorf("FinalityUnixNano = %d; want %d", got, want.FinalityUnixNano)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.Validators); got != want.Validators {
if got := zapv1.Read(view2, QuasarCertSchemaFields.Validators); got != want.Validators {
t.Errorf("Validators = %d; want %d", got, want.Validators)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.BLSOff); got != want.BLSOff {
if got := zapv1.Read(view2, QuasarCertSchemaFields.BLSOff); got != want.BLSOff {
t.Errorf("BLSOff = %#x; want %#x", got, want.BLSOff)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.BLSLen); got != want.BLSLen {
if got := zapv1.Read(view2, QuasarCertSchemaFields.BLSLen); got != want.BLSLen {
t.Errorf("BLSLen = %d; want %d", got, want.BLSLen)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.PulsarLen); got != want.PulsarLen {
if got := zapv1.Read(view2, QuasarCertSchemaFields.PulsarLen); got != want.PulsarLen {
t.Errorf("PulsarLen = %d; want %d", got, want.PulsarLen)
}
if got := zapv2.Read(view2, QuasarCertSchemaFields.MLDSARollupOff); got != want.MLDSARollupOff {
if got := zapv1.Read(view2, QuasarCertSchemaFields.MLDSARollupOff); got != want.MLDSARollupOff {
t.Errorf("MLDSARollupOff = %#x; want %#x", got, want.MLDSARollupOff)
}
}
@@ -114,8 +114,8 @@ func TestQuasarCert_KindMismatch(t *testing.T) {
if err == nil {
t.Fatal("expected SchemaError on kind mismatch")
}
if _, ok := err.(*zapv2.SchemaError); !ok {
t.Errorf("expected *zapv2.SchemaError, got %T: %v", err, err)
if _, ok := err.(*zapv1.SchemaError); !ok {
t.Errorf("expected *zapv1.SchemaError, got %T: %v", err, err)
}
}
@@ -141,11 +141,11 @@ func TestQuasarCert_Metadata(t *testing.T) {
// TestQuasarCert_NotRegistered: the LP-182 consensus-wire schemas
// explicitly skip global registration because their 0x01..0x0D kind
// bytes are LOCAL to the consensus wire registry, not the global
// zapv2.DefaultRegistry that hosts LP-201 (0xD0+) and LP-214 (0xF0+).
// zapv1.DefaultRegistry that hosts LP-201 (0xD0+) and LP-214 (0xF0+).
// Verify init() did NOT register QuasarCert globally.
func TestQuasarCert_NotRegistered(t *testing.T) {
t.Parallel()
if entry, ok := zapv2.DefaultRegistry.Lookup(KindQuasarCert); ok {
if entry, ok := zapv1.DefaultRegistry.Lookup(KindQuasarCert); ok {
// 0x01 might be claimed by some unrelated schema in the same test
// binary. Only fail if the entry's name is ours — that would mean
// the codegen ignored skip_registry.
@@ -6,7 +6,7 @@ package zkvmwire
import (
"testing"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
var benchTxID = [32]byte{
@@ -66,7 +66,7 @@ func BenchmarkZKVMUTXO_RoundTrip(b *testing.B) {
if err != nil {
b.Fatalf("Wrap: %v", err)
}
_ = zapv2.Read(view, ZKVMUTXOSchemaFields.Height)
_ = zapv1.Read(view, ZKVMUTXOSchemaFields.Height)
}
}
@@ -85,7 +85,7 @@ func BenchmarkZKVMUTXO_Read(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = zapv2.Read(view, ZKVMUTXOSchemaFields.Height)
_ = zapv1.Read(view, ZKVMUTXOSchemaFields.Height)
}
}
@@ -21,7 +21,7 @@ import (
"encoding/binary"
"testing"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// TestZKVMUTXO_RoundTrip: build with distinctive values for every
@@ -71,22 +71,22 @@ func TestZKVMUTXO_RoundTrip(t *testing.T) {
t.Fatalf("WrapZKVMUTXO: %v", err)
}
if got := zapv2.Read(view2, ZKVMUTXOSchemaFields.OutputIndex); got != want.OutputIndex {
if got := zapv1.Read(view2, ZKVMUTXOSchemaFields.OutputIndex); got != want.OutputIndex {
t.Errorf("OutputIndex = %#x; want %#x", got, want.OutputIndex)
}
if got := zapv2.Read(view2, ZKVMUTXOSchemaFields.Height); got != want.Height {
if got := zapv1.Read(view2, ZKVMUTXOSchemaFields.Height); got != want.Height {
t.Errorf("Height = %#x; want %#x", got, want.Height)
}
if got := zapv2.Read(view2, ZKVMUTXOSchemaFields.CommitmentOff); got != want.CommitmentOff {
if got := zapv1.Read(view2, ZKVMUTXOSchemaFields.CommitmentOff); got != want.CommitmentOff {
t.Errorf("CommitmentOff = %#x; want %#x", got, want.CommitmentOff)
}
if got := zapv2.Read(view2, ZKVMUTXOSchemaFields.CommitmentLen); got != want.CommitmentLen {
if got := zapv1.Read(view2, ZKVMUTXOSchemaFields.CommitmentLen); got != want.CommitmentLen {
t.Errorf("CommitmentLen = %d; want %d", got, want.CommitmentLen)
}
if got := zapv2.Read(view2, ZKVMUTXOSchemaFields.CiphertextLen); got != want.CiphertextLen {
if got := zapv1.Read(view2, ZKVMUTXOSchemaFields.CiphertextLen); got != want.CiphertextLen {
t.Errorf("CiphertextLen = %d; want %d", got, want.CiphertextLen)
}
if got := zapv2.Read(view2, ZKVMUTXOSchemaFields.EphemeralPKOff); got != want.EphemeralPKOff {
if got := zapv1.Read(view2, ZKVMUTXOSchemaFields.EphemeralPKOff); got != want.EphemeralPKOff {
t.Errorf("EphemeralPKOff = %#x; want %#x", got, want.EphemeralPKOff)
}
@@ -116,8 +116,8 @@ func TestZKVMUTXO_KindMismatch(t *testing.T) {
if err == nil {
t.Fatal("expected SchemaError on kind mismatch")
}
if _, ok := err.(*zapv2.SchemaError); !ok {
t.Errorf("expected *zapv2.SchemaError, got %T: %v", err, err)
if _, ok := err.(*zapv1.SchemaError); !ok {
t.Errorf("expected *zapv1.SchemaError, got %T: %v", err, err)
}
}
@@ -147,7 +147,7 @@ func TestZKVMUTXO_Metadata(t *testing.T) {
// NOT register ZKVMUTXO globally.
func TestZKVMUTXO_NotRegistered(t *testing.T) {
t.Parallel()
if entry, ok := zapv2.DefaultRegistry.Lookup(KindZKVMUTXO); ok {
if entry, ok := zapv1.DefaultRegistry.Lookup(KindZKVMUTXO); ok {
if entry.Name == "ZKVMUTXO" {
t.Fatalf("ZKVMUTXOSchema was registered in DefaultRegistry "+
"despite skip_registry=true; entry=%+v", entry)
@@ -1,28 +1,28 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//
// Code generated by github.com/luxfi/zap/v2/codegen — DO NOT EDIT.
// Code generated by github.com/luxfi/zap/v1/codegen — DO NOT EDIT.
// Source schema: ZKVMUTXO (kind=0x03, size=72).
package zkvmwire
import (
"github.com/luxfi/zap"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// KindZKVMUTXO is the wire discriminator for ZKVMUTXO.
const KindZKVMUTXO zapv2.KindByte = 0x03
const KindZKVMUTXO zapv1.KindByte = 0x03
// SizeZKVMUTXO is the fixed object payload size in bytes.
const SizeZKVMUTXO = 72
// ZKVMUTXOSchema is the v2 schema marker for ZKVMUTXO. Methods are constant-
// returning so concrete-typed [zapv2.Wrap[ZKVMUTXOSchema]] calls fold to
// returning so concrete-typed [zapv1.Wrap[ZKVMUTXOSchema]] calls fold to
// literals at the call site.
type ZKVMUTXOSchema struct{}
func (ZKVMUTXOSchema) Kind() zapv2.KindByte { return KindZKVMUTXO }
func (ZKVMUTXOSchema) Kind() zapv1.KindByte { return KindZKVMUTXO }
func (ZKVMUTXOSchema) Size() int { return SizeZKVMUTXO }
func (ZKVMUTXOSchema) Name() string { return "ZKVMUTXO" }
@@ -54,26 +54,26 @@ const OffsetZKVMUTXO_EphemeralPKOff = 64
const OffsetZKVMUTXO_EphemeralPKLen = 68
// ZKVMUTXOSchemaFields is the namespace of every scalar field accessor for ZKVMUTXO.
// Use with [zapv2.Read] / [zapv2.Write] for type-safe access.
// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.
// Byte-array fields are emitted as standalone functions, see below.
var ZKVMUTXOSchemaFields = struct {
OutputIndex zapv2.Field[ZKVMUTXOSchema, uint32]
Height zapv2.Field[ZKVMUTXOSchema, uint64]
CommitmentOff zapv2.Field[ZKVMUTXOSchema, uint32]
CommitmentLen zapv2.Field[ZKVMUTXOSchema, uint32]
CiphertextOff zapv2.Field[ZKVMUTXOSchema, uint32]
CiphertextLen zapv2.Field[ZKVMUTXOSchema, uint32]
EphemeralPKOff zapv2.Field[ZKVMUTXOSchema, uint32]
EphemeralPKLen zapv2.Field[ZKVMUTXOSchema, uint32]
OutputIndex zapv1.Field[ZKVMUTXOSchema, uint32]
Height zapv1.Field[ZKVMUTXOSchema, uint64]
CommitmentOff zapv1.Field[ZKVMUTXOSchema, uint32]
CommitmentLen zapv1.Field[ZKVMUTXOSchema, uint32]
CiphertextOff zapv1.Field[ZKVMUTXOSchema, uint32]
CiphertextLen zapv1.Field[ZKVMUTXOSchema, uint32]
EphemeralPKOff zapv1.Field[ZKVMUTXOSchema, uint32]
EphemeralPKLen zapv1.Field[ZKVMUTXOSchema, uint32]
}{
OutputIndex: zapv2.At[ZKVMUTXOSchema, uint32](4),
Height: zapv2.At[ZKVMUTXOSchema, uint64](8),
CommitmentOff: zapv2.At[ZKVMUTXOSchema, uint32](48),
CommitmentLen: zapv2.At[ZKVMUTXOSchema, uint32](52),
CiphertextOff: zapv2.At[ZKVMUTXOSchema, uint32](56),
CiphertextLen: zapv2.At[ZKVMUTXOSchema, uint32](60),
EphemeralPKOff: zapv2.At[ZKVMUTXOSchema, uint32](64),
EphemeralPKLen: zapv2.At[ZKVMUTXOSchema, uint32](68),
OutputIndex: zapv1.At[ZKVMUTXOSchema, uint32](4),
Height: zapv1.At[ZKVMUTXOSchema, uint64](8),
CommitmentOff: zapv1.At[ZKVMUTXOSchema, uint32](48),
CommitmentLen: zapv1.At[ZKVMUTXOSchema, uint32](52),
CiphertextOff: zapv1.At[ZKVMUTXOSchema, uint32](56),
CiphertextLen: zapv1.At[ZKVMUTXOSchema, uint32](60),
EphemeralPKOff: zapv1.At[ZKVMUTXOSchema, uint32](64),
EphemeralPKLen: zapv1.At[ZKVMUTXOSchema, uint32](68),
}
// NewZKVMUTXO builds a fresh ZKVMUTXO in a ZAP buffer.
@@ -82,7 +82,7 @@ var ZKVMUTXOSchemaFields = struct {
// [*Builder.StartObject], [*ObjectBuilder.Set*], [*Builder.Finish])
// so the entire build expands at the call site. Result: 1 heap
// alloc (the buffer), zero overhead vs v1.
func NewZKVMUTXO(outputIndex uint32, height uint64, commitmentOff uint32, commitmentLen uint32, ciphertextOff uint32, ciphertextLen uint32, ephemeralPKOff uint32, ephemeralPKLen uint32, txID [32]byte) (zapv2.View[ZKVMUTXOSchema], []byte) {
func NewZKVMUTXO(outputIndex uint32, height uint64, commitmentOff uint32, commitmentLen uint32, ciphertextOff uint32, ciphertextLen uint32, ephemeralPKOff uint32, ephemeralPKLen uint32, txID [32]byte) (zapv1.View[ZKVMUTXOSchema], []byte) {
b := zap.NewBuilder(zap.HeaderSize + SizeZKVMUTXO)
ob := b.StartObject(SizeZKVMUTXO)
ob.SetUint8(0, uint8(KindZKVMUTXO))
@@ -98,26 +98,26 @@ func NewZKVMUTXO(outputIndex uint32, height uint64, commitmentOff uint32, commit
rootOff := ob.FinishAsRoot()
buf := b.Finish()
end := rootOff + SizeZKVMUTXO
return zapv2.AsView[ZKVMUTXOSchema](zapv2.RawFromSlices(buf, rootOff, end)), buf
return zapv1.AsView[ZKVMUTXOSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
}
// WrapZKVMUTXO parses a ZAP buffer into a typed
// [zapv2.View[ZKVMUTXO]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv2.SchemaError] on kind
// [zapv1.View[ZKVMUTXO]]. Validates the wire frame and the kind
// discriminator at offset 0; returns [*zapv1.SchemaError] on kind
// mismatch.
//
// Hand-rolled fast path: inlines [zap.Parse] (which is itself
// inlineable). Zero heap allocs on the happy path; matches v1
// hand-rolled performance.
func WrapZKVMUTXO(b []byte) (zapv2.View[ZKVMUTXOSchema], error) {
func WrapZKVMUTXO(b []byte) (zapv1.View[ZKVMUTXOSchema], error) {
msg, err := zap.Parse(b)
if err != nil {
return zapv2.View[ZKVMUTXOSchema]{}, err
return zapv1.View[ZKVMUTXOSchema]{}, err
}
root := msg.Root()
if got := root.Uint8(0); got != uint8(KindZKVMUTXO) {
return zapv2.View[ZKVMUTXOSchema]{}, zapv2.NewSchemaError(
KindZKVMUTXO, zapv2.KindByte(got), "ZKVMUTXO")
return zapv1.View[ZKVMUTXOSchema]{}, zapv1.NewSchemaError(
KindZKVMUTXO, zapv1.KindByte(got), "ZKVMUTXO")
}
data := msg.Bytes()
rootOff := root.Offset()
@@ -125,7 +125,7 @@ func WrapZKVMUTXO(b []byte) (zapv2.View[ZKVMUTXOSchema], error) {
if end > len(data) {
end = len(data) // Read returns zero on OOB; v1 graceful degradation
}
return zapv2.AsView[ZKVMUTXOSchema](zapv2.RawFromSlices(data, rootOff, end)), nil
return zapv1.AsView[ZKVMUTXOSchema](zapv1.RawFromSlices(data, rootOff, end)), nil
}
// ZKVMUTXOTxID reads the 32-byte inline TxID field of ZKVMUTXO.
@@ -134,9 +134,9 @@ func WrapZKVMUTXO(b []byte) (zapv2.View[ZKVMUTXOSchema], error) {
// a sub-slice of the underlying buffer); the returned [32]byte is a
// value copy so the caller's slot owns the bytes after the View's
// buffer is freed.
func ZKVMUTXOTxID(v zapv2.View[ZKVMUTXOSchema]) [32]byte {
func ZKVMUTXOTxID(v zapv1.View[ZKVMUTXOSchema]) [32]byte {
msg := zap.WrapBuffer(v.Bytes())
obj := msg.RootObjectAt(int(zapv2.RootOff(v)))
obj := msg.RootObjectAt(int(zapv1.RootOff(v)))
slice := obj.BytesFixedSlice(OffsetZKVMUTXO_TxID, 32)
var out [32]byte
if len(slice) == 32 {
@@ -13,7 +13,7 @@
// equality with what was set. This catches regressions in:
// - Constructor field-write order vs offsets
// - Wrap kind-discriminator check
// - Scalar field accessors via zapv2.Read
// - Scalar field accessors via zapv1.Read
// - Byte-array field accessor (zero-copy slice + value-copy)
//
// If this test passes, the codegen's emitted files are functionally
@@ -27,7 +27,7 @@ import (
"encoding/binary"
"testing"
zapv2 "github.com/luxfi/zap/v2"
zapv1 "github.com/luxfi/zap/v1"
)
// TestRoundTrip_ScalarsAndBytes: build with a set of distinctive
@@ -121,8 +121,8 @@ func TestWrap_KindMismatch(t *testing.T) {
t.Fatal("expected SchemaError on kind mismatch")
}
// Verify it's the typed error, not just any error.
if _, ok := err.(*zapv2.SchemaError); !ok {
t.Errorf("expected *zapv2.SchemaError, got %T: %v", err, err)
if _, ok := err.(*zapv1.SchemaError); !ok {
t.Errorf("expected *zapv1.SchemaError, got %T: %v", err, err)
}
}
@@ -146,7 +146,7 @@ func TestSchemaMetadata(t *testing.T) {
// registered the schema with the package-level Registry.
func TestSchemaRegistered(t *testing.T) {
t.Parallel()
entry, ok := zapv2.DefaultRegistry.Lookup(KindLightClientBlockHeaderRequest)
entry, ok := zapv1.DefaultRegistry.Lookup(KindLightClientBlockHeaderRequest)
if !ok {
t.Fatal("LCBlockHeaderReqSchema not registered in DefaultRegistry")
}
@@ -157,23 +157,23 @@ func TestSchemaRegistered(t *testing.T) {
}
// checkScalarFields is the shared assertion helper for TestRoundTrip_*.
func checkScalarFields(t *testing.T, v zapv2.View[LCBlockHeaderReqSchema],
func checkScalarFields(t *testing.T, v zapv1.View[LCBlockHeaderReqSchema],
wantVersion uint8, wantChainID uint32, wantBlockHeight uint64,
wantCertMinTier uint8, wantRequestID uint32) {
t.Helper()
if got := zapv2.Read(v, LCBlockHeaderReqSchemaFields.Version); got != wantVersion {
if got := zapv1.Read(v, LCBlockHeaderReqSchemaFields.Version); got != wantVersion {
t.Errorf("Version = %d; want %d", got, wantVersion)
}
if got := zapv2.Read(v, LCBlockHeaderReqSchemaFields.ChainID); got != wantChainID {
if got := zapv1.Read(v, LCBlockHeaderReqSchemaFields.ChainID); got != wantChainID {
t.Errorf("ChainID = %d; want %d", got, wantChainID)
}
if got := zapv2.Read(v, LCBlockHeaderReqSchemaFields.BlockHeight); got != wantBlockHeight {
if got := zapv1.Read(v, LCBlockHeaderReqSchemaFields.BlockHeight); got != wantBlockHeight {
t.Errorf("BlockHeight = 0x%x; want 0x%x", got, wantBlockHeight)
}
if got := zapv2.Read(v, LCBlockHeaderReqSchemaFields.CertMinTier); got != wantCertMinTier {
if got := zapv1.Read(v, LCBlockHeaderReqSchemaFields.CertMinTier); got != wantCertMinTier {
t.Errorf("CertMinTier = %d; want %d", got, wantCertMinTier)
}
if got := zapv2.Read(v, LCBlockHeaderReqSchemaFields.RequestID); got != wantRequestID {
if got := zapv1.Read(v, LCBlockHeaderReqSchemaFields.RequestID); got != wantRequestID {
t.Errorf("RequestID = %d; want %d", got, wantRequestID)
}
}
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2_test
package zapv1_test
import (
"os/exec"
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package zapv2 is the elegant, generic, idiomatic Go reference
// Package zapv1 is the elegant, generic, idiomatic Go reference
// implementation of the ZAP wire format.
//
// Where the v1 [github.com/luxfi/zap] package exposes a C-shaped API
@@ -46,4 +46,4 @@
//
// One and only one way to express any of these. No braiding of policy
// with primitive, no inheritance, no duplication.
package zapv2
package zapv1
@@ -20,14 +20,14 @@
// v2 shape (declarations only; the generic API does the rest):
//
// type AdvanceTimeSchema struct{}
// func (AdvanceTimeSchema) Kind() zapv2.KindByte { return 0x14 }
// func (AdvanceTimeSchema) Kind() zapv1.KindByte { return 0x14 }
// func (AdvanceTimeSchema) Size() int { return 9 }
// func (AdvanceTimeSchema) Name() string { return "AdvanceTimeTx" }
//
// var AdvanceTimeFields = struct {
// Time zapv2.Field[AdvanceTimeSchema, uint64]
// Time zapv1.Field[AdvanceTimeSchema, uint64]
// }{
// Time: zapv2.At[AdvanceTimeSchema, uint64](1),
// Time: zapv1.At[AdvanceTimeSchema, uint64](1),
// }
//
// That's it. Wrap, Build, Read, Write are all expressed through the
@@ -36,7 +36,7 @@ package examples
import (
"github.com/luxfi/zap"
"github.com/luxfi/zap/v2"
"github.com/luxfi/zap/v1"
)
// KindAdvanceTime is the wire discriminator for AdvanceTimeTx. It
@@ -45,14 +45,14 @@ import (
// advance_time_tx_test.go pins this so the v2 generic builder
// produces the exact same bytes as the v1 hand-rolled
// NewAdvanceTimeTx.
const KindAdvanceTime zapv2.KindByte = 1
const KindAdvanceTime zapv1.KindByte = 1
// AdvanceTimeSchema is the v2 schema marker for AdvanceTimeTx. The
// type is the schema's identity; the methods describe its wire shape.
type AdvanceTimeSchema struct{}
// Kind returns the discriminator byte at object offset 0.
func (AdvanceTimeSchema) Kind() zapv2.KindByte { return KindAdvanceTime }
func (AdvanceTimeSchema) Kind() zapv1.KindByte { return KindAdvanceTime }
// Size returns the fixed object payload (1 byte kind + 8 byte time).
func (AdvanceTimeSchema) Size() int { return 9 }
@@ -64,16 +64,16 @@ func (AdvanceTimeSchema) Name() string { return "AdvanceTimeTx" }
// 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)
// Reading: zapv1.Read(view, AdvanceTimeFields.Time) → uint64
// Writing: zapv1.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 AdvanceTimeFields = struct {
Time zapv2.Field[AdvanceTimeSchema, uint64]
Time zapv1.Field[AdvanceTimeSchema, uint64]
}{
Time: zapv2.At[AdvanceTimeSchema, uint64](1),
Time: zapv1.At[AdvanceTimeSchema, uint64](1),
}
// NewAdvanceTime builds a fresh AdvanceTimeTx with the given
@@ -87,12 +87,12 @@ var AdvanceTimeFields = struct {
// 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
// generic [zapv1.NewBuilderFor] / [zapv1.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 NewAdvanceTime(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte) {
func NewAdvanceTime(ts uint64) (zapv1.View[AdvanceTimeSchema], []byte) {
const size = 9 // AdvanceTimeSchema{}.Size()
b := zap.NewBuilder(zap.HeaderSize + size)
ob := b.StartObject(size)
@@ -101,7 +101,7 @@ func NewAdvanceTime(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte) {
rootOff := ob.FinishAsRoot()
buf := b.Finish()
end := rootOff + size
return zapv2.AsView[AdvanceTimeSchema](zapv2.RawFromSlices(buf, rootOff, end)), buf
return zapv1.AsView[AdvanceTimeSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
}
// NewAdvanceTimeClosure is the closure-style equivalent of
@@ -109,9 +109,9 @@ func NewAdvanceTime(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte) {
// 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 NewAdvanceTimeClosure(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte) {
return zapv2.Build[AdvanceTimeSchema](func(s zapv2.Setter[AdvanceTimeSchema]) {
zapv2.Write(s, AdvanceTimeFields.Time, ts)
func NewAdvanceTimeClosure(ts uint64) (zapv1.View[AdvanceTimeSchema], []byte) {
return zapv1.Build[AdvanceTimeSchema](func(s zapv1.Setter[AdvanceTimeSchema]) {
zapv1.Write(s, AdvanceTimeFields.Time, ts)
})
}
@@ -119,28 +119,28 @@ func NewAdvanceTimeClosure(ts uint64) (zapv2.View[AdvanceTimeSchema], []byte) {
//
// 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
// [zapv1.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
// the per-Read bounds check that lives in [zapv1.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.
func WrapAdvanceTime(b []byte) (zapv2.View[AdvanceTimeSchema], error) {
// generic [zapv1.Wrap[AdvanceTimeSchema]] instead.
func WrapAdvanceTime(b []byte) (zapv1.View[AdvanceTimeSchema], error) {
const size = 9 // AdvanceTimeSchema{}.Size()
msg, err := zap.Parse(b)
if err != nil {
return zapv2.View[AdvanceTimeSchema]{}, err
return zapv1.View[AdvanceTimeSchema]{}, err
}
root := msg.Root()
if got := root.Uint8(0); got != uint8(KindAdvanceTime) {
return zapv2.View[AdvanceTimeSchema]{},
return zapv1.View[AdvanceTimeSchema]{},
advanceTimeKindError(got)
}
data := msg.Bytes()
@@ -149,8 +149,8 @@ func WrapAdvanceTime(b []byte) (zapv2.View[AdvanceTimeSchema], error) {
if end > len(data) {
end = len(data)
}
return zapv2.AsView[AdvanceTimeSchema](
zapv2.RawFromSlices(data, rootOff, end)), nil
return zapv1.AsView[AdvanceTimeSchema](
zapv1.RawFromSlices(data, rootOff, end)), nil
}
// advanceTimeKindError builds the kind-mismatch error for
@@ -159,9 +159,9 @@ func WrapAdvanceTime(b []byte) (zapv2.View[AdvanceTimeSchema], error) {
// possible — when [WrapAdvanceTime] inlines into the caller, the
// error path stays an out-of-line tail call.
func advanceTimeKindError(got uint8) error {
return zapv2.NewSchemaError(
zapv2.KindByte(KindAdvanceTime),
zapv2.KindByte(got),
return zapv1.NewSchemaError(
zapv1.KindByte(KindAdvanceTime),
zapv1.KindByte(got),
"AdvanceTimeTx")
}
@@ -169,15 +169,15 @@ func advanceTimeKindError(got uint8) error {
// 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)
// zapv1.Read for callers who prefer method syntax. It is NOT what
// you'd write in a fresh project; just use zapv1.Read(view, Fields.X)
// directly. Kept here so the example covers both forms.
func Time(v zapv2.View[AdvanceTimeSchema]) uint64 {
return zapv2.Read(v, AdvanceTimeFields.Time)
func Time(v zapv1.View[AdvanceTimeSchema]) uint64 {
return zapv1.Read(v, AdvanceTimeFields.Time)
}
func init() {
// Register with the package-level Registry so generic dispatch
// (PeekKind → Registry.Lookup → WrapAs) finds this schema.
zapv2.Register[AdvanceTimeSchema](zapv2.DefaultRegistry)
zapv1.Register[AdvanceTimeSchema](zapv1.DefaultRegistry)
}
@@ -4,15 +4,15 @@
package examples
import (
"github.com/luxfi/zap/v2"
"github.com/luxfi/zap/v1"
)
// KindBatch is the wire discriminator for BatchTx. Distinct from
// KindAdvanceTime so Registry dispatch can tell them apart.
const KindBatch zapv2.KindByte = 0x21
const KindBatch zapv1.KindByte = 0x21
// BatchSchema is a small, multi-element schema used to exercise the
// generic [zapv2.List] iter.Seq path in tests. Object layout:
// generic [zapv1.List] iter.Seq path in tests. Object layout:
//
// @0: KindBatch (uint8)
// @1: BatchID (uint64)
@@ -22,54 +22,54 @@ const KindBatch zapv2.KindByte = 0x21
// uint64).
type BatchSchema struct{}
func (BatchSchema) Kind() zapv2.KindByte { return KindBatch }
func (BatchSchema) Kind() zapv1.KindByte { return KindBatch }
func (BatchSchema) Size() int { return 17 }
func (BatchSchema) Name() string { return "BatchTx" }
// 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 KindItem zapv2.KindByte = 0x22
const KindItem zapv1.KindByte = 0x22
// ItemSchema is the per-element schema for BatchTx.Items.
type ItemSchema struct{}
func (ItemSchema) Kind() zapv2.KindByte { return KindItem }
func (ItemSchema) Kind() zapv1.KindByte { return KindItem }
func (ItemSchema) Size() int { return 16 } // 8 + 8
func (ItemSchema) Name() string { return "BatchItem" }
// BatchFields declares the offsets for BatchSchema.
var BatchFields = struct {
ID zapv2.Field[BatchSchema, uint64]
ID zapv1.Field[BatchSchema, uint64]
}{
ID: zapv2.At[BatchSchema, uint64](1),
ID: zapv1.At[BatchSchema, uint64](1),
}
// ItemFields declares the offsets for ItemSchema.
var ItemFields = struct {
ID zapv2.Field[ItemSchema, uint64]
Value zapv2.Field[ItemSchema, uint64]
ID zapv1.Field[ItemSchema, uint64]
Value zapv1.Field[ItemSchema, uint64]
}{
ID: zapv2.At[ItemSchema, uint64](0),
Value: zapv2.At[ItemSchema, uint64](8),
ID: zapv1.At[ItemSchema, uint64](0),
Value: zapv1.At[ItemSchema, uint64](8),
}
// 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.
// list, so it lives outside the [zapv1.Field] generic vocabulary; it
// is read via [zapv1.ListAt] instead.
const OffsetBatchItems uint32 = 9
// Items returns the list of items in the batch as an [iter.Seq]-ready
// [zapv2.List][ItemSchema]. Range-over-func:
// [zapv1.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)
// id := zapv1.Read(item, examples.ItemFields.ID)
// value := zapv1.Read(item, examples.ItemFields.Value)
// // ...
// }
func Items(v zapv2.View[BatchSchema]) zapv2.List[ItemSchema] {
return zapv2.ListAt[BatchSchema, ItemSchema](v, OffsetBatchItems)
func Items(v zapv1.View[BatchSchema]) zapv1.List[ItemSchema] {
return zapv1.ListAt[BatchSchema, ItemSchema](v, OffsetBatchItems)
}
// Item is a value-shaped helper for batch-construction tests.
@@ -79,15 +79,15 @@ type Item struct {
}
// NewBatch builds a BatchTx with the given ID and items.
func NewBatch(id uint64, items []Item) (zapv2.View[BatchSchema], []byte) {
return zapv2.Build[BatchSchema](func(s zapv2.Setter[BatchSchema]) {
zapv2.Write(s, BatchFields.ID, id)
zapv2.WriteList[BatchSchema, ItemSchema](s, OffsetBatchItems,
func(es *zapv2.ElemSetter[ItemSchema]) {
func NewBatch(id uint64, items []Item) (zapv1.View[BatchSchema], []byte) {
return zapv1.Build[BatchSchema](func(s zapv1.Setter[BatchSchema]) {
zapv1.Write(s, BatchFields.ID, id)
zapv1.WriteList[BatchSchema, ItemSchema](s, OffsetBatchItems,
func(es *zapv1.ElemSetter[ItemSchema]) {
for _, it := range items {
es.Append(func(e zapv2.Setter[ItemSchema]) {
zapv2.Write(e, ItemFields.ID, it.ID)
zapv2.Write(e, ItemFields.Value, it.Value)
es.Append(func(e zapv1.Setter[ItemSchema]) {
zapv1.Write(e, ItemFields.ID, it.ID)
zapv1.Write(e, ItemFields.Value, it.Value)
})
}
})
@@ -95,6 +95,6 @@ func NewBatch(id uint64, items []Item) (zapv2.View[BatchSchema], []byte) {
}
func init() {
zapv2.Register[BatchSchema](zapv2.DefaultRegistry)
zapv2.Register[ItemSchema](zapv2.DefaultRegistry)
zapv1.Register[BatchSchema](zapv1.DefaultRegistry)
zapv1.Register[ItemSchema](zapv1.DefaultRegistry)
}
+7 -7
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import (
"unsafe"
@@ -32,7 +32,7 @@ import (
// methods of generic types ([View[S].Read[T] would be illegal]). v2
// therefore exposes Read and Write as top-level generic functions
// rather than methods on [View] / [Setter]. The call site is at least
// as terse as a method call: `zapv2.Read(view, F.Time)`.
// as terse as a method call: `zapv1.Read(view, F.Time)`.
type Field[S Schema, T FieldKind] struct {
Offset uint32
// _phantom keeps the nominal type identity tight: without it the
@@ -57,9 +57,9 @@ type phantomCarrier[S Schema, T FieldKind] struct {
// fixed-size payload. Construct fields once per schema:
//
// var AdvanceTimeFields = struct {
// Time zapv2.Field[AdvanceTimeSchema, uint64]
// Time zapv1.Field[AdvanceTimeSchema, uint64]
// }{
// Time: zapv2.At[AdvanceTimeSchema, uint64](1),
// Time: zapv1.At[AdvanceTimeSchema, uint64](1),
// }
//
// The offset is in bytes. The caller is responsible for keeping
@@ -148,7 +148,7 @@ func init() {
if *(*[2]byte)(unsafe.Pointer(&u)) != [2]byte{1, 0} {
// readBE path would need to be wired here. The package
// currently only targets little-endian platforms.
panic("zapv2: big-endian host detected; direct-load Read path " +
panic("zapv1: big-endian host detected; direct-load Read path " +
"requires per-T byteswap (see field.go).")
}
}
@@ -178,8 +178,8 @@ func Write[S Schema, T FieldKind](s Setter[S], f Field[S, T], val T) {
// WriteB is the [Builder]-receiver counterpart to [Write]. Used in
// the imperative-style build path:
//
// bb := zapv2.NewBuilderFor[Schema]()
// zapv2.WriteB(bb, Fields.Time, ts)
// bb := zapv1.NewBuilderFor[Schema]()
// zapv1.WriteB(bb, Fields.Time, ts)
// view, buf := bb.Finish()
//
// Identical wire semantics to Write — the difference is only that
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import "iter"
+10 -10
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import (
"iter"
@@ -62,7 +62,7 @@ func (l List[E]) At(i int) View[E] {
// range-over-func form:
//
// for view := range list.All() {
// t := zapv2.Read(view, EFields.Time)
// t := zapv1.Read(view, EFields.Time)
// // ...
// }
//
@@ -122,7 +122,7 @@ func (l List[E]) All() iter.Seq[View[E]] {
// Usage:
//
// for payload := range list.Payloads() {
// v := zapv2.ReadPayload[ItemSchema, uint64](payload, ItemFields.Value)
// v := zapv1.ReadPayload[ItemSchema, uint64](payload, ItemFields.Value)
// // ...
// }
func (l List[E]) Payloads() iter.Seq[[]byte] {
@@ -241,14 +241,14 @@ func rawListOffset(l zap.List) int {
//
// Example (BatchTx.Items, see examples/batch_tx.go):
//
// zapv2.Build[BatchSchema](func(s zapv2.Setter[BatchSchema]) {
// zapv2.Write(s, BatchFields.ID, batchID)
// zapv2.WriteList[BatchSchema, ItemSchema](s, OffsetBatchItems,
// func(items *zapv2.ElemSetter[ItemSchema]) {
// zapv1.Build[BatchSchema](func(s zapv1.Setter[BatchSchema]) {
// zapv1.Write(s, BatchFields.ID, batchID)
// zapv1.WriteList[BatchSchema, ItemSchema](s, OffsetBatchItems,
// func(items *zapv1.ElemSetter[ItemSchema]) {
// for _, it := range source {
// items.Append(func(e zapv2.Setter[ItemSchema]) {
// zapv2.Write(e, ItemFields.ID, it.id)
// zapv2.Write(e, ItemFields.Value, it.val)
// items.Append(func(e zapv1.Setter[ItemSchema]) {
// zapv1.Write(e, ItemFields.ID, it.id)
// zapv1.Write(e, ItemFields.Value, it.val)
// })
// }
// })
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import "sync"
@@ -9,7 +9,7 @@ import "sync"
// dedicated sync.Pool + Get + Put per type as v1 did, register a
// constructor once:
//
// var ViewPool = zapv2.NewPool(func() *View[AdvanceTimeSchema] {
// var ViewPool = zapv1.NewPool(func() *View[AdvanceTimeSchema] {
// return &View[AdvanceTimeSchema]{}
// })
//
+3 -3
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import (
"sync"
@@ -58,7 +58,7 @@ type Entry struct {
// goroutines, but the typical pattern is init():
//
// func init() {
// zapv2.Register[AdvanceTimeSchema](DefaultRegistry)
// zapv1.Register[AdvanceTimeSchema](DefaultRegistry)
// }
//
// Register panics if two schemas declare the same kind byte — that
@@ -72,7 +72,7 @@ func Register[S Schema](r *Registry) {
r.mu.Lock()
defer r.mu.Unlock()
if existing, ok := r.entries[kind]; ok && existing.Name != name {
panic("zapv2: duplicate kind byte " + hexByte(byte(kind)) +
panic("zapv1: duplicate kind byte " + hexByte(byte(kind)) +
" for schemas " + existing.Name + " and " + name)
}
r.entries[kind] = Entry{
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
// KindByte is the one-byte discriminator at offset 0 of every v2
// object payload. It identifies the schema concretely.
@@ -70,7 +70,7 @@ type SchemaError struct {
func (e *SchemaError) Error() string {
// Keep the message terse and machine-grep-friendly: the kind bytes
// are the load-bearing identity, the name is human help.
return "zapv2: schema mismatch: want " + e.Name +
return "zapv1: schema mismatch: want " + e.Name +
" (kind=" + hexByte(byte(e.Want)) +
"), got kind=" + hexByte(byte(e.Got))
}
+77 -77
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2_test
package zapv1_test
import (
"bytes"
@@ -9,8 +9,8 @@ import (
"testing"
"github.com/luxfi/zap"
"github.com/luxfi/zap/v2"
"github.com/luxfi/zap/v2/examples"
"github.com/luxfi/zap/v1"
"github.com/luxfi/zap/v1/examples"
)
// TestRoundTrip_AdvanceTime: Build → Wrap → Read returns the original
@@ -20,14 +20,14 @@ func TestRoundTrip_AdvanceTime(t *testing.T) {
cases := []uint64{0, 1, 0xdeadbeef, 1<<63 - 1, 1<<64 - 1}
for _, want := range cases {
view, buf := examples.NewAdvanceTime(want)
if got := zapv2.Read(view, examples.AdvanceTimeFields.Time); got != want {
if got := zapv1.Read(view, examples.AdvanceTimeFields.Time); got != want {
t.Fatalf("Build→Read: got %d, want %d", got, want)
}
view2, err := examples.WrapAdvanceTime(buf)
if err != nil {
t.Fatalf("Wrap: %v", err)
}
if got := zapv2.Read(view2, examples.AdvanceTimeFields.Time); got != want {
if got := zapv1.Read(view2, examples.AdvanceTimeFields.Time); got != want {
t.Fatalf("Build→Wrap→Read: got %d, want %d", got, want)
}
// Also exercise the method-style accessor.
@@ -45,74 +45,74 @@ func TestRoundTrip_8Shapes(t *testing.T) {
type s1 struct{}
// Shape 1: bool field
t.Run("Bool", func(t *testing.T) {
view, _ := zapv2.Build[boolSchema](func(set zapv2.Setter[boolSchema]) {
zapv2.Write(set, boolFields.Flag, true)
view, _ := zapv1.Build[boolSchema](func(set zapv1.Setter[boolSchema]) {
zapv1.Write(set, boolFields.Flag, true)
})
if !zapv2.Read(view, boolFields.Flag) {
if !zapv1.Read(view, boolFields.Flag) {
t.Fatal("bool round-trip lost the value")
}
})
// Shape 2..N: integer widths.
t.Run("Int8", func(t *testing.T) {
const want int8 = -42
view, _ := zapv2.Build[i8Schema](func(s zapv2.Setter[i8Schema]) {
zapv2.Write(s, i8Fields.V, want)
view, _ := zapv1.Build[i8Schema](func(s zapv1.Setter[i8Schema]) {
zapv1.Write(s, i8Fields.V, want)
})
if got := zapv2.Read(view, i8Fields.V); got != want {
if got := zapv1.Read(view, i8Fields.V); got != want {
t.Fatalf("int8: %d != %d", got, want)
}
})
t.Run("Int16", func(t *testing.T) {
const want int16 = -1234
view, _ := zapv2.Build[i16Schema](func(s zapv2.Setter[i16Schema]) {
zapv2.Write(s, i16Fields.V, want)
view, _ := zapv1.Build[i16Schema](func(s zapv1.Setter[i16Schema]) {
zapv1.Write(s, i16Fields.V, want)
})
if got := zapv2.Read(view, i16Fields.V); got != want {
if got := zapv1.Read(view, i16Fields.V); got != want {
t.Fatalf("int16: %d != %d", got, want)
}
})
t.Run("Int32", func(t *testing.T) {
const want int32 = -7777777
view, _ := zapv2.Build[i32Schema](func(s zapv2.Setter[i32Schema]) {
zapv2.Write(s, i32Fields.V, want)
view, _ := zapv1.Build[i32Schema](func(s zapv1.Setter[i32Schema]) {
zapv1.Write(s, i32Fields.V, want)
})
if got := zapv2.Read(view, i32Fields.V); got != want {
if got := zapv1.Read(view, i32Fields.V); got != want {
t.Fatalf("int32: %d != %d", got, want)
}
})
t.Run("Int64", func(t *testing.T) {
const want int64 = -(1 << 60)
view, _ := zapv2.Build[i64Schema](func(s zapv2.Setter[i64Schema]) {
zapv2.Write(s, i64Fields.V, want)
view, _ := zapv1.Build[i64Schema](func(s zapv1.Setter[i64Schema]) {
zapv1.Write(s, i64Fields.V, want)
})
if got := zapv2.Read(view, i64Fields.V); got != want {
if got := zapv1.Read(view, i64Fields.V); got != want {
t.Fatalf("int64: %d != %d", got, want)
}
})
t.Run("Uint32", func(t *testing.T) {
const want uint32 = 0xdeadbeef
view, _ := zapv2.Build[u32Schema](func(s zapv2.Setter[u32Schema]) {
zapv2.Write(s, u32Fields.V, want)
view, _ := zapv1.Build[u32Schema](func(s zapv1.Setter[u32Schema]) {
zapv1.Write(s, u32Fields.V, want)
})
if got := zapv2.Read(view, u32Fields.V); got != want {
if got := zapv1.Read(view, u32Fields.V); got != want {
t.Fatalf("uint32: %x != %x", got, want)
}
})
t.Run("Float32", func(t *testing.T) {
const want float32 = 3.14159
view, _ := zapv2.Build[f32Schema](func(s zapv2.Setter[f32Schema]) {
zapv2.Write(s, f32Fields.V, want)
view, _ := zapv1.Build[f32Schema](func(s zapv1.Setter[f32Schema]) {
zapv1.Write(s, f32Fields.V, want)
})
if got := zapv2.Read(view, f32Fields.V); got != want {
if got := zapv1.Read(view, f32Fields.V); got != want {
t.Fatalf("float32: %v != %v", got, want)
}
})
t.Run("Float64", func(t *testing.T) {
const want float64 = 2.718281828459045
view, _ := zapv2.Build[f64Schema](func(s zapv2.Setter[f64Schema]) {
zapv2.Write(s, f64Fields.V, want)
view, _ := zapv1.Build[f64Schema](func(s zapv1.Setter[f64Schema]) {
zapv1.Write(s, f64Fields.V, want)
})
if got := zapv2.Read(view, f64Fields.V); got != want {
if got := zapv1.Read(view, f64Fields.V); got != want {
t.Fatalf("float64: %v != %v", got, want)
}
})
@@ -152,8 +152,8 @@ func TestByteEqual_V1Canonical(t *testing.T) {
func TestWrap_WrongKind(t *testing.T) {
t.Parallel()
_, batchBuf := examples.NewAdvanceTime(7) // kind=1
_, err := zapv2.Wrap[examples.BatchSchema](batchBuf)
var sErr *zapv2.SchemaError
_, err := zapv1.Wrap[examples.BatchSchema](batchBuf)
var sErr *zapv1.SchemaError
if !errors.As(err, &sErr) {
t.Fatalf("expected SchemaError, got %T: %v", err, err)
}
@@ -170,14 +170,14 @@ func TestRegistry_Dispatch(t *testing.T) {
const want uint64 = 42
_, buf := examples.NewAdvanceTime(want)
kind, err := zapv2.PeekKind(buf)
kind, err := zapv1.PeekKind(buf)
if err != nil {
t.Fatalf("PeekKind: %v", err)
}
if kind != examples.KindAdvanceTime {
t.Fatalf("PeekKind: got %v, want %v", kind, examples.KindAdvanceTime)
}
entry, ok := zapv2.DefaultRegistry.Lookup(kind)
entry, ok := zapv1.DefaultRegistry.Lookup(kind)
if !ok {
t.Fatal("Registry: no entry for KindAdvanceTime")
}
@@ -188,11 +188,11 @@ func TestRegistry_Dispatch(t *testing.T) {
t.Fatalf("entry.Wrap: %v", err)
}
// Final typed step.
view, err := zapv2.WrapAs[examples.AdvanceTimeSchema](buf)
view, err := zapv1.WrapAs[examples.AdvanceTimeSchema](buf)
if err != nil {
t.Fatalf("WrapAs: %v", err)
}
if got := zapv2.Read(view, examples.AdvanceTimeFields.Time); got != want {
if got := zapv1.Read(view, examples.AdvanceTimeFields.Time); got != want {
t.Fatalf("WrapAs round-trip: got %d, want %d", got, want)
}
}
@@ -203,7 +203,7 @@ func TestPool_GenericGetPut(t *testing.T) {
t.Parallel()
type Box struct{ N int }
created := 0
pool := zapv2.NewPool(func() *Box {
pool := zapv1.NewPool(func() *Box {
created++
return &Box{}
})
@@ -241,7 +241,7 @@ func TestList_RangeOverFunc(t *testing.T) {
}
view, _ := examples.NewBatch(7777, want)
if id := zapv2.Read(view, examples.BatchFields.ID); id != 7777 {
if id := zapv1.Read(view, examples.BatchFields.ID); id != 7777 {
t.Fatalf("BatchID: %d", id)
}
@@ -254,8 +254,8 @@ func TestList_RangeOverFunc(t *testing.T) {
got := []examples.Item{}
for itemView := range list.All() {
got = append(got, examples.Item{
ID: zapv2.Read(itemView, examples.ItemFields.ID),
Value: zapv2.Read(itemView, examples.ItemFields.Value),
ID: zapv1.Read(itemView, examples.ItemFields.ID),
Value: zapv1.Read(itemView, examples.ItemFields.Value),
})
}
if len(got) != len(want) {
@@ -270,7 +270,7 @@ func TestList_RangeOverFunc(t *testing.T) {
// Indexed iteration.
seen := 0
for i, itemView := range list.Indexed() {
if got, w := zapv2.Read(itemView, examples.ItemFields.ID), want[i].ID; got != w {
if got, w := zapv1.Read(itemView, examples.ItemFields.ID), want[i].ID; got != w {
t.Fatalf("Indexed item[%d].ID: %d, want %d", i, got, w)
}
seen++
@@ -282,7 +282,7 @@ func TestList_RangeOverFunc(t *testing.T) {
// At(i) direct access.
for i, w := range want {
v := list.At(i)
if g := zapv2.Read(v, examples.ItemFields.ID); g != w.ID {
if g := zapv1.Read(v, examples.ItemFields.ID); g != w.ID {
t.Fatalf("At(%d).ID: %d, want %d", i, g, w.ID)
}
}
@@ -308,8 +308,8 @@ func TestList_LargeIteration(t *testing.T) {
sumID := uint64(0)
sumValue := uint64(0)
for itemView := range list.All() {
sumID += zapv2.Read(itemView, examples.ItemFields.ID)
sumValue += zapv2.Read(itemView, examples.ItemFields.Value)
sumID += zapv1.Read(itemView, examples.ItemFields.ID)
sumValue += zapv1.Read(itemView, examples.ItemFields.Value)
}
wantSumID := uint64(N) * uint64(N-1) / 2
wantSumValue := wantSumID * 3
@@ -336,23 +336,23 @@ func TestIter_Combinators(t *testing.T) {
list := examples.Items(view)
// Take 3.
first3 := zapv2.Collect(zapv2.Take(list.All(), 3))
first3 := zapv1.Collect(zapv1.Take(list.All(), 3))
if len(first3) != 3 {
t.Fatalf("Take(3): got %d", len(first3))
}
// Filter: only odd IDs.
odd := zapv2.Filter(list.All(), func(v zapv2.View[examples.ItemSchema]) bool {
return zapv2.Read(v, examples.ItemFields.ID)%2 == 1
odd := zapv1.Filter(list.All(), func(v zapv1.View[examples.ItemSchema]) bool {
return zapv1.Read(v, examples.ItemFields.ID)%2 == 1
})
if n := zapv2.Count(odd); n != 3 { // IDs 1, 3, 5
if n := zapv1.Count(odd); n != 3 { // IDs 1, 3, 5
t.Fatalf("Filter odd: %d, want 3", n)
}
// Map: extract ID.
ids := zapv2.Collect(zapv2.Map(list.All(),
func(v zapv2.View[examples.ItemSchema]) uint64 {
return zapv2.Read(v, examples.ItemFields.ID)
ids := zapv1.Collect(zapv1.Map(list.All(),
func(v zapv1.View[examples.ItemSchema]) uint64 {
return zapv1.Read(v, examples.ItemFields.ID)
}))
if len(ids) != 5 || ids[0] != 1 || ids[4] != 5 {
t.Fatalf("Map IDs: %v", ids)
@@ -363,14 +363,14 @@ func TestIter_Combinators(t *testing.T) {
// not panic on accessor calls.
func TestIsZero(t *testing.T) {
t.Parallel()
var v zapv2.View[examples.AdvanceTimeSchema]
var v zapv1.View[examples.AdvanceTimeSchema]
if !v.IsZero() {
t.Fatal("zero View should be IsZero")
}
if got := zapv2.Read(v, examples.AdvanceTimeFields.Time); got != 0 {
if got := zapv1.Read(v, examples.AdvanceTimeFields.Time); got != 0 {
t.Fatalf("zero View Read: got %d, want 0", got)
}
var l zapv2.List[examples.ItemSchema]
var l zapv1.List[examples.ItemSchema]
if !l.IsZero() {
t.Fatal("zero List should be IsZero")
}
@@ -383,80 +383,80 @@ func TestIsZero(t *testing.T) {
type boolSchema struct{}
func (boolSchema) Kind() zapv2.KindByte { return 0xC0 }
func (boolSchema) Kind() zapv1.KindByte { return 0xC0 }
func (boolSchema) Size() int { return 2 }
func (boolSchema) Name() string { return "boolSchema" }
var boolFields = struct {
Flag zapv2.Field[boolSchema, bool]
}{Flag: zapv2.At[boolSchema, bool](1)}
Flag zapv1.Field[boolSchema, bool]
}{Flag: zapv1.At[boolSchema, bool](1)}
type i8Schema struct{}
func (i8Schema) Kind() zapv2.KindByte { return 0xC1 }
func (i8Schema) Kind() zapv1.KindByte { return 0xC1 }
func (i8Schema) Size() int { return 2 }
func (i8Schema) Name() string { return "i8Schema" }
var i8Fields = struct {
V zapv2.Field[i8Schema, int8]
}{V: zapv2.At[i8Schema, int8](1)}
V zapv1.Field[i8Schema, int8]
}{V: zapv1.At[i8Schema, int8](1)}
type i16Schema struct{}
func (i16Schema) Kind() zapv2.KindByte { return 0xC2 }
func (i16Schema) Kind() zapv1.KindByte { return 0xC2 }
func (i16Schema) Size() int { return 4 }
func (i16Schema) Name() string { return "i16Schema" }
var i16Fields = struct {
V zapv2.Field[i16Schema, int16]
}{V: zapv2.At[i16Schema, int16](2)}
V zapv1.Field[i16Schema, int16]
}{V: zapv1.At[i16Schema, int16](2)}
type i32Schema struct{}
func (i32Schema) Kind() zapv2.KindByte { return 0xC3 }
func (i32Schema) Kind() zapv1.KindByte { return 0xC3 }
func (i32Schema) Size() int { return 8 }
func (i32Schema) Name() string { return "i32Schema" }
var i32Fields = struct {
V zapv2.Field[i32Schema, int32]
}{V: zapv2.At[i32Schema, int32](4)}
V zapv1.Field[i32Schema, int32]
}{V: zapv1.At[i32Schema, int32](4)}
type i64Schema struct{}
func (i64Schema) Kind() zapv2.KindByte { return 0xC4 }
func (i64Schema) Kind() zapv1.KindByte { return 0xC4 }
func (i64Schema) Size() int { return 16 }
func (i64Schema) Name() string { return "i64Schema" }
var i64Fields = struct {
V zapv2.Field[i64Schema, int64]
}{V: zapv2.At[i64Schema, int64](8)}
V zapv1.Field[i64Schema, int64]
}{V: zapv1.At[i64Schema, int64](8)}
type u32Schema struct{}
func (u32Schema) Kind() zapv2.KindByte { return 0xC5 }
func (u32Schema) Kind() zapv1.KindByte { return 0xC5 }
func (u32Schema) Size() int { return 8 }
func (u32Schema) Name() string { return "u32Schema" }
var u32Fields = struct {
V zapv2.Field[u32Schema, uint32]
}{V: zapv2.At[u32Schema, uint32](4)}
V zapv1.Field[u32Schema, uint32]
}{V: zapv1.At[u32Schema, uint32](4)}
type f32Schema struct{}
func (f32Schema) Kind() zapv2.KindByte { return 0xC6 }
func (f32Schema) Kind() zapv1.KindByte { return 0xC6 }
func (f32Schema) Size() int { return 8 }
func (f32Schema) Name() string { return "f32Schema" }
var f32Fields = struct {
V zapv2.Field[f32Schema, float32]
}{V: zapv2.At[f32Schema, float32](4)}
V zapv1.Field[f32Schema, float32]
}{V: zapv1.At[f32Schema, float32](4)}
type f64Schema struct{}
func (f64Schema) Kind() zapv2.KindByte { return 0xC7 }
func (f64Schema) Kind() zapv1.KindByte { return 0xC7 }
func (f64Schema) Size() int { return 16 }
func (f64Schema) Name() string { return "f64Schema" }
var f64Fields = struct {
V zapv2.Field[f64Schema, float64]
}{V: zapv2.At[f64Schema, float64](8)}
V zapv1.Field[f64Schema, float64]
}{V: zapv1.At[f64Schema, float64](8)}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zapv2
package zapv1
import (
"unsafe"
+5 -5
View File
@@ -153,7 +153,7 @@ func (m *Message) Version() uint16 {
// ParseHeader validates a ZAP wire frame and returns the (validated
// data slice, root offset) WITHOUT allocating a [*Message]. Same checks
// as [Parse] — magic, version, size — but the result is two values, not
// a pointer. Intended for generic wrappers (zapv2) that build their own
// a pointer. Intended for generic wrappers (zapv1) that build their own
// value-typed accessors and never need a *Message.
//
// Returns (data[:size], rootOff, nil) on success.
@@ -162,7 +162,7 @@ func (m *Message) Version() uint16 {
// size + bounds). The implementation is intentionally written as one
// linear sequence (no intermediate function calls) so the inliner
// folds the whole body into the caller. Combined with the value-
// typed [zapv2.View], this is what makes the v2 read path match v1's
// typed [zapv1.View], this is what makes the v2 read path match v1's
// 2 ns hand-rolled per-Read cost — zero function calls, zero heap.
func ParseHeader(data []byte) ([]byte, int, error) {
return parseHeaderImpl(data)
@@ -206,7 +206,7 @@ func WrapBuffer(data []byte) *Message {
}
// RootObjectAt returns a [zap.Object] anchored at absolute offset
// `off` within this message. Used by zapv2.Build to avoid a redundant
// `off` within this message. Used by zapv1.Build to avoid a redundant
// header-read after [Builder.FinishAsRoot] already returned the root
// position.
func (m *Message) RootObjectAt(off int) Object {
@@ -281,7 +281,7 @@ func (o Object) IsNull() bool {
}
// Offset returns the object's absolute byte offset within its
// underlying message. Exposed so external generic wrappers (zapv2)
// underlying message. Exposed so external generic wrappers (zapv1)
// can construct typed sub-views into the same buffer without
// re-walking the parent pointers.
//
@@ -294,7 +294,7 @@ func (o Object) Offset() int {
}
// Message returns the underlying [*Message] this Object is a view
// into. Used by zapv2 to alias the message's bytes for direct
// into. Used by zapv1 to alias the message's bytes for direct
// payload indexing.
func (o Object) Message() *Message {
return o.msg