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).
118 lines
4.1 KiB
Go
118 lines
4.1 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: Parent (kind=0x61, size=17).
|
|
|
|
package repeatwire
|
|
|
|
import (
|
|
"github.com/luxfi/zap"
|
|
zapv1 "github.com/luxfi/zap/v1"
|
|
)
|
|
|
|
// KindParent is the wire discriminator for Parent.
|
|
const KindParent zapv1.KindByte = 0x61
|
|
|
|
// SizeParent is the fixed object payload size in bytes.
|
|
const SizeParent = 17
|
|
|
|
// ParentSchema is the v1 schema marker for Parent. Methods are constant-
|
|
// returning so concrete-typed [zapv1.Wrap[ParentSchema]] calls fold to
|
|
// literals at the call site.
|
|
type ParentSchema struct{}
|
|
|
|
func (ParentSchema) Kind() zapv1.KindByte { return KindParent }
|
|
func (ParentSchema) Size() int { return SizeParent }
|
|
func (ParentSchema) Name() string { return "Parent" }
|
|
|
|
// OffsetParent_Count is the byte offset of the Count field.
|
|
const OffsetParent_Count = 1
|
|
|
|
// OffsetParent_Children is the byte offset of the Children field.
|
|
const OffsetParent_Children = 9
|
|
|
|
// ParentSchemaFields is the namespace of every scalar field accessor for Parent.
|
|
// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.
|
|
// Byte-array fields are emitted as standalone functions, see below.
|
|
var ParentSchemaFields = struct {
|
|
Count zapv1.Field[ParentSchema, uint64]
|
|
}{
|
|
Count: zapv1.At[ParentSchema, uint64](1),
|
|
}
|
|
|
|
// NewParent builds a fresh Parent 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 NewParent(count uint64, children []Child) (zapv1.View[ParentSchema], []byte) {
|
|
b := zap.NewBuilder(zap.HeaderSize + SizeParent)
|
|
ob := b.StartObject(SizeParent)
|
|
ob.SetUint8(0, uint8(KindParent))
|
|
ob.SetUint64(OffsetParent_Count, count)
|
|
ls := zapv1.SetterFrom[ParentSchema](ob, b)
|
|
zapv1.WriteListNested[ParentSchema, ChildSchema](ls, OffsetParent_Children, func(es *zapv1.NestedElemSetter[ChildSchema]) {
|
|
for _, it := range children {
|
|
es.Append(func(e zapv1.Setter[ChildSchema]) {
|
|
zapv1.Write(e, ChildSchemaFields.ID, it.ID)
|
|
zapv1.WriteString(e, OffsetChild_Name, it.Name)
|
|
})
|
|
}
|
|
})
|
|
rootOff := ob.FinishAsRoot()
|
|
buf := b.Finish()
|
|
end := rootOff + SizeParent
|
|
return zapv1.AsView[ParentSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
|
|
}
|
|
|
|
// WrapParent parses a ZAP buffer into a typed
|
|
// [zapv1.View[Parent]]. 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 WrapParent(b []byte) (zapv1.View[ParentSchema], error) {
|
|
msg, err := zap.Parse(b)
|
|
if err != nil {
|
|
return zapv1.View[ParentSchema]{}, err
|
|
}
|
|
root := msg.Root()
|
|
if got := root.Uint8(0); got != uint8(KindParent) {
|
|
return zapv1.View[ParentSchema]{}, zapv1.NewSchemaError(
|
|
KindParent, zapv1.KindByte(got), "Parent")
|
|
}
|
|
data := msg.Bytes()
|
|
rootOff := root.Offset()
|
|
end := rootOff + SizeParent
|
|
if end > len(data) {
|
|
end = len(data) // Read returns zero on OOB; v1 graceful degradation
|
|
}
|
|
return zapv1.AsView[ParentSchema](zapv1.RawFromSlices(data, rootOff, end)), nil
|
|
}
|
|
|
|
// Child is the per-element input for the Parent.Children list.
|
|
type Child struct {
|
|
ID uint64
|
|
Name string
|
|
}
|
|
|
|
// ParentChildren returns the variable-length Children list of Parent as a
|
|
// range-over-func-ready [zapv1.ListNested][ChildSchema]. Zero-copy: each element view
|
|
// indexes straight into the underlying buffer.
|
|
//
|
|
// for it := range ParentChildren(view).All() {
|
|
// // zapv1.Read(it, ChildSchemaFields.X)
|
|
// }
|
|
func ParentChildren(v zapv1.View[ParentSchema]) zapv1.ListNested[ChildSchema] {
|
|
return zapv1.ListNestedAt[ParentSchema, ChildSchema](v, OffsetParent_Children)
|
|
}
|
|
|
|
func init() {
|
|
zapv1.Register[ParentSchema](zapv1.DefaultRegistry)
|
|
}
|