Skip to content

Repository files navigation

vinary-tree-interop

One ABI, zero algorithms. vinary-tree-interop is the stable C ABI the vinary-tree family uses to hand live resources — dictionaries and weighted finite-state transducers — between independently built libraries and language bindings. The Rust crate is #![no_std], dependency-free, and contains layouts and constants only: no functions, allocator, or I/O. The native distribution also includes an optional header-only C++20 facade; it implements ownership and provider adaptation without adding a linked runtime. Every function at the binary boundary remains a pointer inside a provider-supplied vtable. Project crates own concrete algorithms, while this repository owns the bytes they agree on and the language-neutral adapters for those bytes.

That inversion is what makes the family modular: a consumer that reads only include/vinary_tree_interop.h (or the bit-identical Rust definitions in src/lib.rs) can consume resources from any provider — another family repo, another version of a family repo, or a third party — without linking against it and without touching Rust's unstable dynamic-library ABI.

The two-word resource

A resource is exactly two machine words:

typedef struct VtResource {
    void* context;                          /* provider-defined state  */
    const struct VtResourceVTable* vtable;  /* provider-owned, immutable */
} VtResource;

Handing one across the boundary is $\mathcal{O}(1)$ — sixteen bytes on a 64-bit target, never a serialization. The base vtable carries a reference-counting pair (retain / release) and versioned capability discovery (query_interface), the portable core of COM's IUnknown. Three laws do the heavy lifting (stated precisely, with their proofs and pins, in the ABI reference):

  • Two-word lawsizeof(VtResource) is exactly two pointers; asserted at compile time in Rust and C++ and at runtime on the JVM.
  • Copy-is-not-retain — copying the two words is free and confers no ownership; each owned copy is paid for with one retain and settled with exactly one release.
  • Snapshot capture is $\mathcal{O}(1)$ — mutable dictionaries hand consumers an immutable, structurally shared revision at operation start; copying the dictionary or holding a long-lived read lock violates the interface contract. Batched paging (node_edges / state_arcs, 256 entries recommended) keeps boundary crossings to $\lceil \deg(v) / 256 \rceil$ per node expansion.

Class model of the published ABI: the two-word VtResource, its base VtResourceVTable, the dictionary and scalar-WFST interface vtables discovered through query_interface, the caller-owned page payload types, and the shared status/domain enums.

Interface catalog

Interfaces are named by 16-byte identifiers compared byte-for-byte and negotiated through query_interface with a consumer-supplied minimum version:

Interface ID Version Payloads What it is
vt.dictionary.v1 1 (VT_DICTIONARY_INTERFACE_VERSION) VtDictionaryEdge, VtOptionalU64 Immutable dictionary snapshots: root/final/transition queries plus batched edge paging, over byte, Unicode-scalar, or u64 label domains, with optional u64 values.
vt.dict.visit.v1 1 (VT_DICTIONARY_VISIT_INTERFACE_VERSION) VtDictionaryEdge Optional fused finality and edge-page inspection for callback-based dictionary traversal.
vt.dict.graph.v1 1 (VT_DICTIONARY_GRAPH_INTERFACE_VERSION) VtDictionaryGraphNode, VtDictionaryGraphEdge, VtDictionaryGraphView Optional compact immutable snapshot graph. A consumer validates the complete borrowed view once, retains its owner, and thereafter traverses dense node/edge arrays without provider callbacks or consumer cache publication.
vt.dict.entry.v1 1 (VT_DICTIONARY_ENTRIES_INTERFACE_VERSION) VtDictionaryEntry, VtDictionaryEntryBatchLimits, VtDictionaryEntryBatchView, VtDictionaryEntriesInfo, VtDictionaryEntriesCursor Optional finite lexicographic entry stream over one immutable revision. Cursor-owned arena batches use an explicit generation lease; reduce provides the same bounded stream through a callback.
vt.snapshot.id.1 1 (VT_SNAPSHOT_IDENTITY_INTERFACE_VERSION) VtSnapshotIdentity Optional process-local immutable producer/revision identity for safely sharing derived state across separately retained views of the same snapshot.
vt.scalar-wfst.1 1 (VT_WFST_INTERFACE_VERSION) VtWfstArc Immutable scalar-weighted FSTs: start/finality/arc paging with f64 weights in one of seven declared semirings, epsilon labels encoded by flag (never by magic value), lazy and acyclic capability claims.
vt.lattice.val.1 1 (VT_LATTICE_INTERFACE_VERSION) VtResource operands and results Immutable lattice values: join, meet, equality, canonical bytes, diagnostics, and bounded batch folds with explicit runtime-thread and reentrancy capabilities.
vt.semiring.val1 1 (VT_SEMIRING_INTERFACE_VERSION) VtSemiringValue Host-defined semiring operation contexts with compact provider-scoped values, explicit clone/release, identities, addition, multiplication, equality, natural order, canonical bytes, diagnostics, and bounded folds.
vt.semiring.div1 · vt.semiring.str1 1 each VtSemiringValue Independently negotiated division/left-division and Kleene-closure capabilities; an undefined mathematical result is VT_STATUS_END, not a sentinel value.
vt.semiring.num1 · vt.semiring.prp1 1 each Scalars and law flags Optional numerical projections/quantization/probability plus declared algebraic laws and uniform closure bounds. Consumers validate every claimed law before selecting a specialized algorithm.

Dynamic semiring ownership from a target-language implementation through the stable capability vtables to a validated Rust adapter, with provider-scoped compact tokens and the unchanged native fast path shown separately.

Base protocol version: VT_ABI_VERSION = 1. The full change rules — what may be added, what forks an identity, and the four distinct version counters — are the ABI evolution policy.

Who produces and consumes what

Repository Dictionary + optional graph Scalar WFST Lattice value Dynamic semiring Notes
llattice defines source trait; host packages produce The Rust leaf stays dependency-free; target runtimes use this ABI capability.
libdictenstein produces consumes for values Dictionary resources publish the base interface; immutable DynamicDawg snapshots additionally publish compact graphs in all three unit domains.
liblevenshtein consumes Validates compact graphs at snapshot acquisition and routes every applicable automaton through the shared captured-graph traversal seam.
duallity consumes base dictionary produces consumes consumes where product weights require it Builds and combines fuzzy and product automata.
lling-llang produces + consumes produces + consumes produces + consumes Publishes dynamic adapters without changing native monomorphized paths.
shared JavaScript runtime hosts hosts hosts hosts The sanctioned all-of-family surface for Node, WASI, and browsers.

Documentation

Document Contents
docs/abi-reference.md The annotated, literate walk of the entire header: every declaration quoted and explained, the refcount/paging/two-word/snapshot laws in display math, the seven semirings defined, and a complete minimal C provider that compiles under -std=c17 -Wall -Wextra -Werror.
docs/abi-evolution.md The four version counters and their jurisdictions, additive-versus-breaking rules per construct, worked examples (add an op, add a weight domain, retire a flag), the decision table, and the current family compatibility matrix.
docs/security-model.md The family trust model: zones, the panic/exception containment law with file:line evidence, threading-by-claim, the input-validation duty table grounded in confirmed findings, exhaustion vectors, WASI capability policy, and explicit non-goals.
docs/npm-coordinate-migration.md The RC5 canonical npm identity, immutable RC4 compatibility policy, fail-closed publication sequence, and consumer migration.
bindings/cpp/README.md C++20 RAII consumption and mutex-free host-provider adapters for scalar WFSTs, lattice values, and generic semirings, with complete examples and failure/threading contracts.
bindings/dotnet/README.md C# and F# collection usage plus lock-free managed host providers for scalar WFSTs, lattice values, and generic semirings, including optional algebraic capabilities and executable examples.
docs/language-bindings/go-host-providers.md Go consumers and cgo-backed customer providers for lattice values, immutable scalar WFSTs, and dynamic semirings, including exact ownership, non-blocking callback gates, bounded pages, and executable examples.
docs/language-bindings/javascript-host-providers.md JavaScript and TypeScript lattice, semiring, and scalar-WFST contracts, including current native/browser/WASI execution support, bounded operations, rooted lifetimes, generational handles, and hostile-callback containment.

Language packages

Twelve language-native mirrors of the interop structs and constants live under bindings/, so non-C ecosystems consume the ABI idiomatically:

.NET · Fortran · Go · Haskell · JavaScript · Julia · JVM · Lua · OCaml · Python · Raku · Swift

C++ additionally has a header-only vinary_tree::interop facade for RAII resource ownership and customer-implemented scalar WFST, lattice, and semiring providers. It is packaged beside the canonical C header and requires no linked runtime.

The C header is the stable authority. The Raku-based generator at scripts/generate-bindings.raku derives the Julia and Raku constants, enum declarations, interface identities, raw struct layouts, and typed callable adapters. It also emits the machine-readable bindings/generated/abi-capabilities.tsv inventory with both languages' names and signatures, interface relationships, parameter direction and ownership, and threading constraints. Its --check mode rejects generated drift without editing the worktree; --self-test proves the detector rejects synthetic Julia and Raku changes as well as a handwritten Julia ccall signature outside the generated region. Native fixture tests then compare every Julia and Raku raw layout to C sizeof and exercise the generated callable adapters; the other language packages retain their own compiler and host-language conformance gates.

The optional entries-v1 surface is canonical in the Rust crate, C header, and generator-owned bundled C-header mirrors. Its generated conformance fixture pins status, flag, operation-order, and LP64/ARM32 layout values. Higher-level language adapters that do not yet expose a typed entries cursor continue to negotiate only the interfaces they model; entries-v1 is never inferred from a partial hand-written definition.

The executable contract

Three test suites in tests/ are the normative documents' teeth; CI runs them on every push (cargo test --locked -p vinary-tree-interop):

  • tests/layout_contract.rs — exact sizes, alignments, and field offsets for every published type on the 64-bit and 32-bit ARM tiers; the two-word law; byte-exact interface identifiers; the Option<extern "C" fn> null niche that makes NULL-slot vtables one ABI.
  • tests/discriminant_pins.rs — every enum discriminant and flag bit pinned exactly and matched wildcard-free, so adding a variant fails compilation until the evolution policy is consulted; zeroed reserved-field defaults.
  • tests/vtable_evolution.rs — the query_interface negotiation surface against a hand-rolled provider, including the additive-evolution proof: a future, larger vtable remains consumable through its v1 prefix, discovered via struct_size.

Crate facts

Fact Value
Version 4.0.0-rc.6
Rust edition 2021, rust-version 1.95, #![no_std]
Dependencies none
License Apache-2.0

Language adapter documentation

Every published adapter uses the same retained-resource laws while mapping ownership and failures into its host language:

The generated dictionary_entries_v1.tsv fixture pins entries-v1 identifiers, statuses, flags, operation order, and LP64/ARM32 layouts for adapter conformance.

Language/runtime Distribution Guide
C Native header and CMake/pkg-config package This README and docs/abi-reference.md
C++20+ Header-only native facade and CMake/pkg-config package bindings/cpp/README.md
Python 3.10+ PyPI package vinary-tree-interop bindings/python/README.md
Java 22+, Kotlin, and Scala Maven coordinate io.vinarytree:vinary-tree-interop bindings/jvm/README.md
JavaScript, TypeScript, and ClojureScript on Node.js, browsers, or WASI npm package @vinary-tree/vinary-tree-interop bindings/javascript/README.md
Go 1.25+ with cgo Go module github.com/vinary-tree/vinary-tree-interop/bindings/go/v4 bindings/go/README.md
Swift 6+ through Swift Package Manager SwiftPM product VinaryTreeInterop bindings/swift/README.md
Fortran 2018 through fpm fpm package vinary-tree-interop (final-version candidate during RC) bindings/fortran/README.md
OCaml 5 through dune/opam opam package vinary-tree-interop bindings/ocaml/README.md
GHC through Cabal Hackage package vinary-tree-interop (final-version candidate during RC) bindings/haskell/README.md
Lua 5.4+ C adapter header bundled by dependent LuaRocks packages bindings/lua/README.md

The adapters are intentionally policy-free. Concrete dictionary and automaton APIs live in their project packages; these guides explain only resource representation, discovery, ownership, and safe handoff.

About

Shared ABI and resource contracts for the Vinary Tree language-binding family

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages