mirror of
https://github.com/luxfi/zap.git
synced 2026-10-30 15:04:16 +00:00
The repeated-message wire shape: a list whose elements carry their own
variable-length tails (string/bytes/nested), which the fixed-stride inline
List cannot hold. Completes proto field-shape coverage in the runtime —
map<k,v> reduces to a repeated {key,value} entry, so this is its keystone too.
Composition, not a new wire concept: ListNested = List ∘ NestedAt. The list
slots are a contiguous stride-4 object-pointer array; each pointer is
followed exactly as a singular nested pointer to an out-of-line tailed View.
Runtime:
- builder.go: ListBuilder.AddObjectPtr(targetPos) — appends a signed 4-byte
relative object pointer (the repeated-message element kind).
- v1/list_nested.go: ListNested[N] (Len/At/All/IsZero), ListNestedAt[S,N]
(read), WriteListNested[S,N] + NestedElemSetter[N] (write). Same audited
bounds discipline as Object.Object / ListStride (RED-HIGH-1/2 inherited).
Codegen:
- elemIsTailed: a list element with a string/bytes/nested/list sub-field
auto-routes to ListNested/WriteListNested/ListNestedAt; scalar-only
elements stay in the tighter inline List/WriteList/ListAt. One Elem
declaration, the generator picks the correct encoding.
Proven end-to-end: runtime roundtrip (3 elements each with its OWN string
tail, via At and All, + empty), emit routing test (tailed->ListNested,
scalar-only->List), and a generated-code wire roundtrip (testpkg/repeatwire).
Root zap + full v1+codegen suite green; scalar listwire unchanged (no regression).
64 lines
1.7 KiB
Go
64 lines
1.7 KiB
Go
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package repeatwire
|
|
|
|
import (
|
|
"testing"
|
|
|
|
zapv1 "github.com/luxfi/zap/v1"
|
|
)
|
|
|
|
// TestRoundTrip_Repeated proves the GENERATED repeated-message code works
|
|
// on the wire: a Parent with a repeated Child where every Child carries its
|
|
// own string tail — the case the codegen routes to ListNested. Build, wrap,
|
|
// read each element's scalar + string zero-copy via the generated accessor.
|
|
func TestRoundTrip_Repeated(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
children := []Child{
|
|
{ID: 11, Name: "one"},
|
|
{ID: 22, Name: "two"},
|
|
{ID: 33, Name: "three-is-a-longer-string"},
|
|
}
|
|
_, buf := NewParent(0x7, children)
|
|
|
|
got, err := WrapParent(buf)
|
|
if err != nil {
|
|
t.Fatalf("WrapParent: %v", err)
|
|
}
|
|
if c := zapv1.Read(got, ParentSchemaFields.Count); c != 0x7 {
|
|
t.Errorf("Count = %d, want 7", c)
|
|
}
|
|
|
|
list := ParentChildren(got)
|
|
if list.Len() != len(children) {
|
|
t.Fatalf("len = %d, want %d", list.Len(), len(children))
|
|
}
|
|
for i, want := range children {
|
|
ch := list.At(i)
|
|
if ch.IsZero() {
|
|
t.Fatalf("child[%d] zero", i)
|
|
}
|
|
if id := zapv1.Read(ch, ChildSchemaFields.ID); id != want.ID {
|
|
t.Errorf("child[%d].ID = %d, want %d", i, id, want.ID)
|
|
}
|
|
if nm := ChildName(ch); nm != want.Name {
|
|
t.Errorf("child[%d].Name = %q, want %q", i, nm, want.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestRoundTrip_RepeatedEmpty proves the empty repeated field round-trips.
|
|
func TestRoundTrip_RepeatedEmpty(t *testing.T) {
|
|
t.Parallel()
|
|
_, buf := NewParent(0, nil)
|
|
got, err := WrapParent(buf)
|
|
if err != nil {
|
|
t.Fatalf("WrapParent: %v", err)
|
|
}
|
|
if n := ParentChildren(got).Len(); n != 0 {
|
|
t.Errorf("empty len = %d, want 0", n)
|
|
}
|
|
}
|