Files
zeekay 592493a51d v1/codegen: emit variable-length LIST fields (zero-copy, typed)
Completes the variable-length codegen (strings/bytes already shipped; lists now
join them). A list field of a fixed-size element schema generates: a per-element
value-input struct, a typed constructor param []Elem, an inline WriteList build
(bridged onto the hand-rolled ObjectBuilder by the new zapv1.SetterFrom, one
zapv1.Write per element field), and a zero-copy ListAt read accessor returning
zapv1.List[E] (range-over-func ready) — mechanically reproducing examples/
batch_tx.go.

Adds: Schema.Element (flat list-element slots carry no kind byte — fields may
start at offset 0; Wrap skips the kind check); runtime helpers SetterFrom /
WriteString / WriteBytes bridging the hand-rolled fast path to the typed writers.

Proven end-to-end: testpkg/listwire round-trips a BatchTx{scalar + []Item}
through build -> wrap -> ListAt.All() with every element read zero-copy
(TestRoundTrip_List), plus generator-output tests (valid Go via go/parser +
construct assertions). Existing golden tests unchanged.
2026-06-23 15:46:50 -07:00

66 lines
1.7 KiB
Go

// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package listwire
import (
"testing"
zapv1 "github.com/luxfi/zap/v1"
)
// TestRoundTrip_List proves the generated list code works on the wire:
// build a BatchTx with a scalar + a list of items, wrap the bytes back,
// and read every element zero-copy via the generated ListAt accessor.
func TestRoundTrip_List(t *testing.T) {
t.Parallel()
items := []Item{
{ID: 10, Value: 100},
{ID: 20, Value: 200},
{ID: 30, Value: 300},
}
view, buf := NewBatchTx(0xCAFE, items)
_ = view
got, err := WrapBatchTx(buf)
if err != nil {
t.Fatalf("WrapBatchTx: %v", err)
}
// Scalar field round-trips.
if id := zapv1.Read(got, BatchSchemaFields.ID); id != 0xCAFE {
t.Errorf("ID = %#x, want 0xCAFE", id)
}
// List length + every element, via the generated zero-copy accessor.
list := BatchTxItems(got)
if list.Len() != len(items) {
t.Fatalf("list len = %d, want %d", list.Len(), len(items))
}
i := 0
for it := range list.All() {
wantID, wantVal := items[i].ID, items[i].Value
if gotID := zapv1.Read(it, ItemSchemaFields.ID); gotID != wantID {
t.Errorf("item[%d].ID = %d, want %d", i, gotID, wantID)
}
if gotVal := zapv1.Read(it, ItemSchemaFields.Value); gotVal != wantVal {
t.Errorf("item[%d].Value = %d, want %d", i, gotVal, wantVal)
}
i++
}
if i != len(items) {
t.Errorf("iterated %d elements, want %d", i, len(items))
}
// Empty list round-trips to a zero-length list (null pointer).
_, emptyBuf := NewBatchTx(1, nil)
empty, err := WrapBatchTx(emptyBuf)
if err != nil {
t.Fatalf("WrapBatchTx(empty): %v", err)
}
if n := BatchTxItems(empty).Len(); n != 0 {
t.Errorf("empty list len = %d, want 0", n)
}
}