capnp-janet architecture#
1 Layers#
capnpc-janet (schema -> typed Janet helpers)
|
janet_mod (native module + register for embeds)
|
capnp_builder (multi-segment arena + far/double-far)
|
capnp_message (segment arena view, resolve, readers)
|
capnp_kinds / capnp_pointer (constants + word codecs)
2 Design choices#
2.1 Native C core, Janet on top#
Janet embeds as a C amalgamation. The wire runtime is C so:
a C application can link Cap’n readers without the Janet VM for host-side framing, and
the same readers register into the sealed Janet pack environment for zero-copy field access on the Cap’n message the host already built.
This mirrors capnp-fortran (native language runtime, not a thin FFI over
C++) more than pycapnp (C++ wrapper). The official Cap’n Proto CLI and live
C++ peers provide compatibility checks without becoming runtime dependencies.
2.2 Zero-copy contract#
capnp_message_view_flat aliases the caller’s stream-framed buffer. Janet
message-view-buffer keeps the Janet buffer GC-marked for the message
abstract lifetime. message-from-buffer copies so the buffer may be reused.
2.3 What packs see#
Packs can open a message through capnp/* without a parallel C DTO table.
Named readers may live in hand-written Janet code or an importable module
emitted by capnpc-janet from the schema.
2.4 Compiled images (.jimage)#
make-image / janet -c freeze top-level PEGs and functions (Janet for
Mortals ch. 2). Native capnp/* CFUNS cannot sit inside the image; the host
re-registers them then unmarshals with janet_env_lookup /
capnp_janet_lookup_into so bytecode calls resolve. Pure law libs (no
Cap’n) unmarshal with core lookup only. The optional capnp.so module is
for the Janet CLI compile path: (import capnp) then janet -c.
3 Embed sketch#
C host:
build an application schema with c-capnproto or this builder
serialize or pass segment pointer
janet_init; capnp_janet_register(env); load pack
pack reads Cap'n; returns decision (Janet values or Cap'n builder)
Janet pack:
(defn check-shell [msg]
(def root (capnp/root msg))
... read argv / pathProbes via getp + get-text ...
@{:action :deny :reason "..."})
4 Testing surface (Janet)#
C wire tests (meson test) cover every scalar width, typed primitive lists,
arena ownership, packed/canonical transforms, and live C++ interoperability.
test/test_codegen.sh generates modules from multiple schemas, checks their
typed surface, then runs test/generated_builder_smoke.janet through the
native module. The executable test covers scalar defaults, exact 64-bit
values, unions, groups, nested structs, and primitive/struct lists.
5 List upgrade and bit/void lists#
Supported schema-evolution list views match capnp-fortran parity tests
(t_list_upgrade_views / t_list_downgrade_views):
Upgrade: prim (byte/two/four/eight) and pointer lists via
capnp_list_get_struct(synthetic struct;data_bitslimited; bit/void refuseCAPNP_ERR_KIND).Downgrade: composite
List(Struct)asList(u*)field @0 viacapnp_list_get_u*; composite asList(Text)viacapnp_list_get_text.
List(Bool): capnp_list_get_bool / capnp_builder_set_list_bool (LSB-first bits).
List(Void): capnp_builder_set_list_void + capnp_list_len only.
Other esize×esize combinations return CAPNP_ERR_KIND; see README.
6 Builder segment policy#
See capnp_builder.h: default first segment 1024 words; spill when full
(max(need, 2*prev_cap)); far landing pads grow the target segment; double-far
when the target segment is at max_seg_words. force_single grows in place
(canonicalize).