Liking cljdoc? Tell your friends :D

Bindings — the producer contract corpus

Navigation: ← Documentation index

libdictenstein is the producer half of the family's dictionary ABI: it owns the concrete dictionaries and their CRUD, exports a 41-function ldict_* C surface, and hands consumers a two-word, retained vt.dictionary.v1 resource whose snapshots they walk. The consumer half (cursor model, lease protocol, language-facade query APIs) lives in liblevenshtein — this corpus documents everything on the producing side of that boundary.

What lives where

ArtifactPathWhat it is
C ABI referencec-abi-reference.mdThe normative reference for all 41 ldict_* functions: exact signatures, preconditions, exact status sets, ownership, thread-safety, complexity; the status/kind/capability tables; the per-backend support matrix; persistence caveats; a compile-and-run-verified C example.
Resource-producer architectureresource-producer.mdHow the producer side works: the four backend bindings, OwnedDictionaryResource and the retain ledger, per-backend $\mathcal{O}(1)$ snapshot capture, lazy ABI-local node ids, the flag truth table, and the new-backend checklist.
Native Rust idiomsrust-api-idioms.mdConfirmed iterator/construction gaps in the pure Rust producer and the optimized, generic target for Iterator, IntoIterator, FromIterator, Extend, fallible bulk construction, folds, snapshots, and every automaton/unit domain.
FFI boundary analysis../security/ffi-boundary.mdThe producer-side trust analysis: what a misbehaving foreign caller can and cannot cause, and whose duty each defense is. Extends the threat model.
Findings ledgerFINDINGS_LEDGER.mdThe scientific ledger of binding-scrutiny findings: defects, pins, coverage gaps, and version-pin inconsistencies (LDICT-B<N> schema).
Machine-readable model../../bindings/api.jsonThe source of truth for the binding surface: symbols, enums, kinds, capabilities, marshalling and snapshot laws, facade layout, registry coordinates.
Contract gates../../scripts/check-bindings.py, ../../scripts/check-binding-docs.pyEnforce the ABI model and reject a declared facade whose guide, executable evidence, required operational topics, or local links are missing or stale. CI job binding-contract.
Diagrams../diagrams/abi-producer-component (layer map), snapshot-capture-sequence (the walk protocol), owned-resource-lifecycle-state (the retain ledger); sources under ../diagrams/src/.
Language facades../../bindings/Fourteen governed guides over the ldict_* surface, including the native C contract and grouped JVM/JavaScript language families.
Guide generator../../scripts/generate-binding-guides.pyOwns the uniform support, loading, ownership, error, concurrency, performance, security, compatibility, and maintainer sections while preserving each facade's handwritten tutorial.

Collection interfaces are shipped across the packages in the matrix. Six of the 41 C functions form the shared bounded-entry cursor and reducer substrate; the optimized pure Rust surface bypasses that ABI, and each foreign facade maps the same snapshot, ordering, value, and cancellation laws to its own familiar protocols. The family collection-protocol contract is the normative semantic reference. The public APIs deliberately are not a lowest-common-denominator transliteration of C.

Ordinary collection views own their host data and therefore remain usable after the dictionary changes or closes. Streaming views instead retain one immutable native revision and lease bounded batches; callers must use the language's deterministic lexical cleanup form when they may stop early. Membership operations remain direct dictionary lookups, never traversal scans.

Native collection quick reference

LanguageFamiliar materialized or standard surfaceBounded stream / reductionDeterministic lifetime
RustDictionaryEntries/Terms/Keys/Values, IntoIterator, FromIterator, Extend, lazy zipper collectionsfold_entries / try_fold_entries; iterators pin one revisionOwnership and Drop; fallible persistent builders are explicit try_* APIs
C17/C23Caller-owned arrays copied from LdictEntryBatchldict_entry_cursor_*; ldict_entry_cursor_reduce callback foldExact-generation release, then cancel on early exit and free
C++20/C++23dictionary::entries() is a standard move-only input range; collect into an ordinary container when retention is neededRange algorithms over borrowed entry_view valuesRAII closes after exhaustion, break, or exception
PythonDictionarySnapshot implements Mapping; dictionaries implement mapping protocols and expose snapshot, keys, items, and valuesstream_entries(...) returns an Iterator context managerwith for streams and dictionaries; close remains explicit and idempotent
JavaDictionary is Iterable<DictionaryEntry>; DictionarySnapshot is an immutable Collection with List, Set, Collection, and Map viewsEntryStream is Iterator + Spliterator; streamEntries returns a sequential Streamtry-with-resources for dictionaries and any stream that may stop early
KotlinJava collection views support ordinary iteration and snapshot().asSequence()openEntryStream(n).use { it.asSequence() }use scopes the AutoCloseable stream and dictionary
ScalaJava collection views adapt with snapshot().asScalaUsing.resource(openEntryStream(n))(_.asScala)Using scopes the AutoCloseable resource
ClojurePersistent-vector snapshots support seq/reduce/transduce; entry-eduction composes transducerswith-entry-stream, stream-seq, reduce-entries, transduce-entrieswith-open through with-entry-stream
JavaScriptIterable DictionarySnapshot, entries, keys, values, forEach, and toMapstreamEntries() is a closeable iterator with nextBatch and reduceBatchesiterator return, close, and Symbol.dispose where supported
TypeScriptThe JavaScript collection surface with declared key/value/snapshot typesTyped streamEntries() closeable iterable cursorusing/Symbol.dispose where available, otherwise try/finally + close
ClojureScriptPersistent-vector snapshot, seq entries, keys, and valueswith-entry-stream and reduce-entries over streamEntries()Facade helpers close in finally
C# / .NETDictionary is IEnumerable<KeyValuePair<…>>; DictionarySnapshot is IReadOnlyDictionary + IReadOnlyCollection; LINQ composes naturallyOpenEntryStream returns IEnumerator + IDisposableusing; foreach disposes its enumerator
GoSnapshotEntries/Entries return host-owned EntrySnapshot valuesOpenEntryStream, Next, and Go 1.23 iter.Seq/Seq2range helpers close on exhaustion, break, or panic; direct pulls use defer Close
Swiftentries() returns an EntrySnapshot : RandomAccessCollectionentryStream, next, and canceldefer { try? stream.close() }; deinit is fallback containment
RubyEvery dictionary includes Enumerable; entries, keys, and values materialize snapshotseach/Enumerator or manual entry_streamensure closes iteration; manual streams expose cancel and close
FortranOwned dictionary_entry_batch values are normally assignableopen_entries/next_batch; fold_entries callback procedureExplicit %close; finalization is fallback containment
OCamlwith_entries_seq supplies a native-ordered Seq.tfold_entries provides synchronous reductionFun.protect scopes and closes the cursor
HaskellmaterializeEntries returns a Foldable DictionarySnapshotwithEntryStream/nextEntry; foldEntriesBracketed with* APIs mask exceptions across release; ForeignPtr finalizer is fallback
Lua 5.4dictionary:entries() snapshot works with pairsentries_iter generic-for form or explicit entry_cursorto-be-closed values or explicit :close; __gc is fallback containment

Collection benchmark entrypoints

All profiles keep construction and warmup outside the timed drain and emit one libdictenstein.host-collection-traversal.v1 JSON object. Commands below select the representative streaming arm; replace it with materialized, stream-cancel, or reduce only when the linked guide lists that arm. C and C++ first compile the public example exactly as shown in their guides.

Runtime / packagePublic-package command
Rustcargo run --release --features bindings-core --example collection_traversal_profile -- --arm direct-owned --entries 4096
CLD_LIBRARY_PATH=target/release /tmp/libdictenstein-c-collection-profile --arm stream --entries 4096 --batch-size 256
C++LD_LIBRARY_PATH=target/release /tmp/libdictenstein-cpp-collection-profile --arm stream --entries 4096 --batch-size 256
PythonPYTHONPATH=bindings/python/src python -m libdictenstein._collection_profile --arm stream --entries 4096 --batch-size 256
JVM: Java, Kotlin, Scala./gradlew -p bindings/jvm collectionTraversalProfile -PjavaToolchain=22 -PvinaryTree.nativeDir=../../target/debug -PprofileArgs='--arm stream --entries 4096 --batch-size 256'
Clojurecd bindings/clojure && clojure -J-Djava.library.path=../../target/release -M:profile --arm stream --entries 4096 --batch-size 256
JavaScript, TypeScript, ClojureScriptnode bindings/javascript/bin/libdictenstein-collection-profile.mjs --runtime native --arm stream --entries 4096 --batch-size 256
.NET / C#dotnet run --project bindings/dotnet/benchmarks/VinaryTree.Libdictenstein.CollectionTraversalProfile/VinaryTree.Libdictenstein.CollectionTraversalProfile.csproj -c Release -f net10.0 -- --arm stream --entries 4096 --batch-size 256
Gogo run ./bindings/go/cmd/collection-traversal-profile --arm stream --entries 4096 --batch-size 256
Swiftswift run --package-path bindings/swift/libdictenstein -c release libdictenstein-collection-profile --arm stream --entries 4096 --batch-size 256
Rubyruby bindings/ruby/bin/libdictenstein-collection-profile --arm stream --entries 4096 --batch-size 256
Fortranfpm run --directory bindings/fortran --profile release --example collection_traversal_profile -- --arm stream --entries 4096 --batch-size 256
OCamldune exec --root bindings/ocaml bin/collection_traversal_profile.exe -- --arm stream --entries 4096 --batch-size 256
Haskellcabal run --project-file=bindings/haskell/cabal.project libdictenstein-collection-profile -- --arm stream --entries 4096 --batch-size 256
Lualua bindings/lua/examples/collection_traversal_profile.lua --arm stream --entries 4096 --batch-size 256

Language guide matrix

The guide is part of the package contract, not release-adjacent prose. Every row names a checked example that exercises the public facade and deterministic resource cleanup. “Tier” controls how frequently a package is release-gated; it does not weaken ownership, snapshot, or error semantics.

GuideRepresented languagesTierBoundary
CC17/C231Direct ldict_* ABI
C++C++20/C++231Move-only RAII over C
PythonPython1ctypes
JVMJava, Kotlin, Scala1Java Foreign Function & Memory API
ClojureClojure1JVM facade
JavaScript familyJavaScript, TypeScript, ClojureScript1Singleton N-API/WebAssembly/WASI runtime
.NETC#2P/Invoke
GoGo2cgo
SwiftSwift2Swift system-library target
RubyRuby2Fiddle
FortranFortran2iso_c_binding
OCamlOCaml3C stubs
HaskellHaskell3Haskell FFI
LuaLua3C userdata module

Regenerate the governed sections after changing bindings/api.json, package metadata, or a public facade:

python3 scripts/generate-binding-guides.py
python3 scripts/check-binding-docs.py

Reading order

  1. Orient — the component diagram in resource-producer.md § 2 shows the whole producer stack on one page.
  2. Call itc-abi-reference.md, front to back: versioning → status discipline → backend matrix → the function groups → the verified example.
  3. Understand what you were handed — the rest of resource-producer.md: snapshots, node-id leasing, flags, and the refcount ledger.
  4. Trust it../security/ffi-boundary.md for the adversarial reading, then the family canon below for the laws this repo instantiates.
  5. Audit itFINDINGS_LEDGER.md plus a local run of python3 scripts/check-bindings.py.

Family documents

Canonical family-level specifications live with the interop crate in liblevenshtein-rust (linked absolutely — cross-repo relative paths do not survive packaging):

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close