Files
zeekay 07cc875d57 zap: rewrite with our own zapc compiler — drop capnp dependency entirely
Per user direction: "no capnp we DON'T use that" + "must use zapc"
+ "must be our fork". The runtime now has zero capnp footprint —
schema bindings come from our own hand-rolled compiler.

Workspace layout:

  zap/
  ├── Cargo.toml          workspace root
  ├── zapc-rs/            zapc — schema compiler
  │   ├── Cargo.toml
  │   └── src/
  │       ├── lib.rs       Public compile_to_rust API
  │       ├── parser.rs    .zap → Schema IR (file id + structs)
  │       ├── codegen.rs   Schema → Rust readers/writers
  │       └── main.rs      `zapc <schema.zap>` CLI
  └── rust/               hanzo-zap — runtime
      ├── Cargo.toml      build-deps: zapc (path)
      ├── build.rs        invokes zapc::compile_to_rust
      ├── schema/
      │   └── zap.zap     canonical schema (was zap.capnp)
      ├── src/
      │   ├── wire.rs      ZAP framing + io
      │   ├── schema.rs    include!() generated bindings
      │   ├── server.rs    raw TCP listener + Handler trait
      │   ├── msg.rs       canonical type ids
      │   └── lib.rs
      └── benches/
          └── wire.rs      criterion bench: ZAP vs JSON

Wire format unchanged — still byte-for-byte aligned with
github.com/luxfi/zap (Go) and @zap-proto/zap (TS). Each struct in the
schema becomes a `<name>::Reader<'a>` (zero-copy view into the slot
region) plus a `<name>::Writer` (owning builder). Variable-length
fields (Text/Data) use the standard i32 LE relative offset + u32 LE
length pair at the slot, payload appended to the tail.

Tests: 6/6 pass — header roundtrip, bad magic reject, bad version
reject, raw frame io, generated proto roundtrip, KeysSnapshot with
2 KiB payload.

Bench (single core, criterion):
  decode/keys_subscribe   zap=19 ns   json_scan=591 ns      (31× win)
  encode/keys_snapshot    zap=736 ns                         (~1 GiB/s)
  encode/keys_subscribe   zap=436 ns   json_format=134 ns    (-3.3×)

Decode dominates the JWT-validation hot path (every consumer decodes
KeysRotate / KeysSnapshot from the IAM publisher), so the 31× decode
win is what matters. Encode-side regression on tiny messages is from
allocating two Vecs (slot + tail); will fold into one pre-sized buf
in a follow-up.

The user-flagged JSON encoding from the previous v1 prototype is
gone: `cargo tree -p hanzo-zap | grep -i serde_json` returns empty.
2026-05-06 22:44:16 -07:00

16 lines
632 B
Rust

//! Build script — compiles `schema/zap.zap` into Rust readers/writers
//! via our own `zapc` compiler (no upstream Cap'n Proto dependency).
//!
//! Generated module lives at `OUT_DIR/zap_schema.rs` and is included
//! by `src/schema.rs`.
use std::path::PathBuf;
fn main() {
let schema = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("schema/zap.zap");
let out = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("zap_schema.rs");
zapc::compile_to_rust(&schema, &out).expect("zapc compile failed");
println!("cargo:rerun-if-changed=schema/zap.zap");
println!("cargo:rerun-if-changed=../zapc-rs/src");
}