Files
zeekay 7cc9e8fdc8 A list element keeps the width it was declared with
A field of type [N]byte lays out as bytes_fixed[N] and the schema states
N. The same type as a LIST element stated bytes_fixed[0]: sliceElemOf
copied the element's kind and its nested layout but not its length, and
LayoutOf then spelled the element with a literal zero. Nothing failed —
the layout was accepted and the schema was published — so what a peer
read was a contract to take no bytes per element, and a codec generated
from it would have done exactly that.

This is the shape every chain reply is full of: a list of ids. It is
seven ops on a Lux node alone.

The refusal in that position was wrong too. Reflection does not carry
bytes_fixed anywhere, on purpose — an id is the case that should make a
type declare its own wire — and a field says so, naming MarshalZAP. An
element instead reported that a kind had no wire form, which is true of
nothing and tells the reader nothing. It now gives the same answer a
field does.
2026-08-29 14:27:41 -07:00

47 lines
1.4 KiB
Go

package zapenc
import (
"reflect"
"strings"
"testing"
)
// A list of ids is the shape every chain reply is full of, and it is exactly
// the shape bytes_fixed exists for. The element has to keep its WIDTH — the
// schema is the contract a generated codec is built from, and bytes_fixed[0]
// is a contract to read nothing — and the refusal has to be the one that says
// what to do about it, not the one that says a kind has no wire form.
type fixedList struct {
Nodes [][20]byte
Chains [][32]byte
}
func TestFixedListElementKeepsItsWidth(t *testing.T) {
sh, err := LayoutOf(reflect.TypeOf(fixedList{}))
if err != nil {
t.Fatalf("LayoutOf: %v", err)
}
want := map[string]string{
"Nodes": "list<bytes_fixed[20]>",
"Chains": "list<bytes_fixed[32]>",
}
for _, s := range sh.Slots {
if s.Type != want[s.Name] {
t.Errorf("%s: schema says %s, want %s", s.Name, s.Type, want[s.Name])
}
if s.Elem != strings.TrimSuffix(strings.TrimPrefix(want[s.Name], "list<"), ">") {
t.Errorf("%s: element says %q", s.Name, s.Elem)
}
}
}
func TestFixedListRefusalNamesTheFix(t *testing.T) {
_, err := Marshal(&fixedList{Nodes: [][20]byte{{1}}})
if err == nil {
t.Fatal("the reflective codec must refuse bytes_fixed, in a list as in a field")
}
if !strings.Contains(err.Error(), "MarshalZAP") {
t.Fatalf("the refusal has to name the fix, got: %v", err)
}
}