mirror of
https://github.com/luxfi/zap.git
synced 2026-10-30 15:04:16 +00:00
Completes the variable-length codegen (strings/bytes/lists/nested) — the last shape needed before protoc-gen-zap can map every proto message field mechanically. Runtime (v1/nested.go): - NestedAt[S,N]: read an out-of-line 4-byte object pointer as a typed View[N]; null/OOB -> zero View (proto3 unset). - WriteNested[S,N]: build a flat nested object into the parent tail and patch the pointer; the singular peer of WriteList. Composes recursively (nested may carry scalars, strings, bytes, lists, further nesting). Codegen (schema.go, emit.go): - Field.Nested *NestedMsg (4-byte object pointer, distinct from the 8-byte list/tail pointer); IsNested(). - Constructor takes *Value (nil => null), nil-guarded WriteNested build. - emitNestedSupport: value struct + NestedAt read accessor. - emitElemWrites: shared scalar/string/bytes element-write body, so list elements now also support string/bytes sub-fields (repeated-of-message). - ListElem/NestedMsg carry Wire (element WireName) for Offset<Wire>_<F>. Proven end-to-end: runtime roundtrip (nested w/ own string tail + null case), generator-output tests (go/parser-valid), and a generated-code wire roundtrip (testpkg/nestwire). Full v1+codegen suite green, no regression.
112 lines
3.8 KiB
Go
112 lines
3.8 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: Outer (kind=0x51, size=13).
|
|
|
|
package nestwire
|
|
|
|
import (
|
|
"github.com/luxfi/zap"
|
|
zapv1 "github.com/luxfi/zap/v1"
|
|
)
|
|
|
|
// KindOuter is the wire discriminator for Outer.
|
|
const KindOuter zapv1.KindByte = 0x51
|
|
|
|
// SizeOuter is the fixed object payload size in bytes.
|
|
const SizeOuter = 13
|
|
|
|
// OuterSchema is the v1 schema marker for Outer. Methods are constant-
|
|
// returning so concrete-typed [zapv1.Wrap[OuterSchema]] calls fold to
|
|
// literals at the call site.
|
|
type OuterSchema struct{}
|
|
|
|
func (OuterSchema) Kind() zapv1.KindByte { return KindOuter }
|
|
func (OuterSchema) Size() int { return SizeOuter }
|
|
func (OuterSchema) Name() string { return "Outer" }
|
|
|
|
// OffsetOuter_Seq is the byte offset of the Seq field.
|
|
const OffsetOuter_Seq = 1
|
|
|
|
// OffsetOuter_Inner is the byte offset of the Inner field.
|
|
const OffsetOuter_Inner = 9
|
|
|
|
// OuterSchemaFields is the namespace of every scalar field accessor for Outer.
|
|
// Use with [zapv1.Read] / [zapv1.Write] for type-safe access.
|
|
// Byte-array fields are emitted as standalone functions, see below.
|
|
var OuterSchemaFields = struct {
|
|
Seq zapv1.Field[OuterSchema, uint64]
|
|
}{
|
|
Seq: zapv1.At[OuterSchema, uint64](1),
|
|
}
|
|
|
|
// NewOuter builds a fresh Outer 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 NewOuter(seq uint64, inner *Inner) (zapv1.View[OuterSchema], []byte) {
|
|
b := zap.NewBuilder(zap.HeaderSize + SizeOuter)
|
|
ob := b.StartObject(SizeOuter)
|
|
ob.SetUint8(0, uint8(KindOuter))
|
|
ob.SetUint64(OffsetOuter_Seq, seq)
|
|
ls := zapv1.SetterFrom[OuterSchema](ob, b)
|
|
if inner != nil {
|
|
zapv1.WriteNested[OuterSchema, InnerSchema](ls, OffsetOuter_Inner, func(e zapv1.Setter[InnerSchema]) {
|
|
zapv1.Write(e, InnerSchemaFields.ID, inner.ID)
|
|
zapv1.WriteString(e, OffsetInner_Label, inner.Label)
|
|
})
|
|
}
|
|
rootOff := ob.FinishAsRoot()
|
|
buf := b.Finish()
|
|
end := rootOff + SizeOuter
|
|
return zapv1.AsView[OuterSchema](zapv1.RawFromSlices(buf, rootOff, end)), buf
|
|
}
|
|
|
|
// WrapOuter parses a ZAP buffer into a typed
|
|
// [zapv1.View[Outer]]. 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 WrapOuter(b []byte) (zapv1.View[OuterSchema], error) {
|
|
msg, err := zap.Parse(b)
|
|
if err != nil {
|
|
return zapv1.View[OuterSchema]{}, err
|
|
}
|
|
root := msg.Root()
|
|
if got := root.Uint8(0); got != uint8(KindOuter) {
|
|
return zapv1.View[OuterSchema]{}, zapv1.NewSchemaError(
|
|
KindOuter, zapv1.KindByte(got), "Outer")
|
|
}
|
|
data := msg.Bytes()
|
|
rootOff := root.Offset()
|
|
end := rootOff + SizeOuter
|
|
if end > len(data) {
|
|
end = len(data) // Read returns zero on OOB; v1 graceful degradation
|
|
}
|
|
return zapv1.AsView[OuterSchema](zapv1.RawFromSlices(data, rootOff, end)), nil
|
|
}
|
|
|
|
// Inner is the value input for the singular Outer.Inner nested object.
|
|
type Inner struct {
|
|
ID uint64
|
|
Label string
|
|
}
|
|
|
|
// OuterInner returns the singular Inner nested object of Outer as a
|
|
// zero-copy [zapv1.View][InnerSchema]. An unset (null) nested field yields the zero
|
|
// View — test it with [zapv1.View.IsZero].
|
|
func OuterInner(v zapv1.View[OuterSchema]) zapv1.View[InnerSchema] {
|
|
return zapv1.NestedAt[OuterSchema, InnerSchema](v, OffsetOuter_Inner)
|
|
}
|
|
|
|
func init() {
|
|
zapv1.Register[OuterSchema](zapv1.DefaultRegistry)
|
|
}
|