Files
zeekay 9d9e477978 v1/codegen: emit REPEATED nested objects (repeated message, zero-copy)
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).
2026-06-23 16:38:05 -07:00

98 lines
3.3 KiB
Go

// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//
// Code generated by github.com/luxfi/zap/v1/codegen — DO NOT EDIT.
// Source schema: Child (kind=0x62, size=16).
package repeatwire
import (
"github.com/luxfi/zap"
zapv1 "github.com/luxfi/zap/v1"
)
// KindChild is the wire discriminator for Child.
const KindChild zapv1.KindByte = 0x62
// SizeChild is the fixed object payload size in bytes.
const SizeChild = 16
// ChildSchema is the v1 schema marker for Child. Methods are constant-
// returning so concrete-typed [zapv1.Wrap[ChildSchema]] calls fold to
// literals at the call site.
type ChildSchema struct{}
func (ChildSchema) Kind() zapv1.KindByte { return KindChild }
func (ChildSchema) Size() int { return SizeChild }
func (ChildSchema) Name() string { return "Child" }
// OffsetChild_ID is the byte offset of the ID field.
const OffsetChild_ID = 0
// OffsetChild_Name is the byte offset of the Name field.
const OffsetChild_Name = 8
// ChildSchemaFields is the namespace of every scalar field accessor for Child.
// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.
// Byte-array fields are emitted as standalone functions, see below.
var ChildSchemaFields = struct {
ID zapv1.Field[ChildSchema, uint64]
}{
ID: zapv1.At[ChildSchema, uint64](0),
}
// NewChild builds a fresh Child in a ZAP buffer.
//
// Hand-rolled fast path: inlines v1 primitives ([zap.NewBuilder],
// [*Builder.StartObject], [*ObjectBuilder.Set*], [*Builder.Finish])
// 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 NewChild(iD uint64, name string) (zapv1.View[ChildSchema], []byte) {
b := zap.NewBuilder(zap.HeaderSize + SizeChild + len(name))
ob := b.StartObject(SizeChild)
ob.SetUint64(OffsetChild_ID, iD)
ob.SetText(OffsetChild_Name, name)
rootOff := ob.FinishAsRoot()
buf := b.Finish()
end := rootOff + SizeChild
return zapv1.AsView[ChildSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
}
// WrapChild parses a ZAP buffer into a typed
// [zapv1.View[Child]]. 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 WrapChild(b []byte) (zapv1.View[ChildSchema], error) {
msg, err := zap.Parse(b)
if err != nil {
return zapv1.View[ChildSchema]{}, err
}
root := msg.Root()
data := msg.Bytes()
rootOff := root.Offset()
end := rootOff + SizeChild
if end > len(data) {
end = len(data) // Read returns zero on OOB; v1 graceful degradation
}
return zapv1.AsView[ChildSchema](zapv1.RawFromSlices(data, rootOff, end)), nil
}
// ChildName reads the variable-length Name string field of Child.
//
// 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 ChildName(v zapv1.View[ChildSchema]) string {
msg := zap.WrapBuffer(v.Bytes())
obj := msg.RootObjectAt(int(zapv1.RootOff(v)))
return obj.Text(OffsetChild_Name)
}
func init() {
zapv1.Register[ChildSchema](zapv1.DefaultRegistry)
}