1---2name: binding-architecture3description: Architecture rules for the polyglot binding layer and the C FFI boundary — crate naming, distribution paths, ownership and null-safety invariants, error-context propagation, and async patterns. Load when designing or editing language bindings, the C ABI, cbindgen headers, or FFI type/error conversions.4---56# Binding Architecture78## Bindings910- Bindings are minimal glue: call Rust core, convert types, convert errors — no business logic11- Canonical surface: Rust core API first, C FFI ABI second, language bindings third;12 integrations/adapters sit outside bindings13- Crate naming: {lib}-py (PyO3), {lib}-node (NAPI-RS), {lib}-rb (Magnus), {lib}-php (ext-php-rs),14 {lib}-wasm (wasm-bindgen), {lib}-ffi (C FFI), {lib}-jni (JNI)15- Distribution paths: packages/python/ (PyPI), typescript/ (npm), ruby/ (RubyGems), php/ (Composer),16 go/ (Go module), java/ (Maven), csharp/ (NuGet), dart/ (pub.dev), swift/ (SwiftPM),17 kotlin-android/ (Maven/Gradle), r/ (CRAN/GitHub), zig/ (Zig package)18- Each binding has its own language-native test suite — 80%+ coverage19- Generated e2e code lives under e2e/{language}/ and is not hand-edited20- Error conversion must preserve context (message + numeric code) at every FFI boundary21- Async: pyo3_asyncio (Python), native #[napi] async (TS), Fiber (Ruby), block on Tokio via FFI only at22 sync host boundaries2324## FFI and language interop2526- Every pointer has one owner, documented with SAFETY comments27- Opaque handles only — never expose Rust types directly, use #[repr(transparent)] wrappers28- Null safety: check ALL pointers before use, return null + error code on failure29- Allocate/free pairs: every \_new() has a matching \_free(), caller owns \*mut30- Every unsafe block has a SAFETY comment: what invariant, why it holds, what breaks if violated31- Generate C headers with cbindgen — CI verifies generated headers match committed32- C ABI is the stable native contract for Go, Java/JNI, C#, Dart, Swift, Kotlin Android, Zig, and R wrappers33- Semantic versioning for C headers, struct layouts frozen at MAJOR.MINOR boundaries34- All exported functions use #[no_mangle] extern "C"35- Rust Result\<T, E> → host exceptions via dedicated conversion functions at every boundary36- Preserve error context across boundaries: message, numeric code (1000+), source location, cause chain