dyn_loader/lib.rs
1//! # dyn-loader — standardized module loading protocol
2//!
3//! A **language-agnostic module loading protocol** built on the C ABI.
4//! Not a "plugin system": any dynamic library (.so/.dll/.dylib) that follows
5//! the protocol becomes a *module* that any host — in any language — can
6//! load, call, share and release.
7//!
8//! ## Protocol boundary rule (first law)
9//!
10//! **Only standard C interfaces may cross the module boundary.** Legal
11//! transports are: `extern "C"` functions, C scalar types, `#[repr(C)]` POD
12//! structs, C strings, and function pointers. Language-runtime objects
13//! (C++ exceptions, Zig error unions, Rust panics, GC references) must never
14//! cross. The single controlled exception is the [`native`] fat-pointer
15//! pair, valid only under the same-compiler-version clause.
16//!
17//! ## Ownership invariants
18//!
19//! 1. **Whoever allocates, deallocates** — every pointer crossing the
20//! boundary is paired with a free/release function pointer belonging to
21//! the allocating module.
22//! 2. **Whoever creates, operates** — the host receives a calling convention
23//! (vtable layout) plus function pointers; all operations execute inside
24//! the creator's module.
25//!
26//! The only thing that ever crosses the boundary, in any language, is the
27//! protocol itself: pointers plus function pointers.
28//!
29//! ## Layers
30//!
31//! - **[`abi`]** — the protocol standard layer: interface tables
32//! ([`AbiTable<T>`]), ref-counted interface references
33//! ([`AbiRef<T>`], [`AbiStableDynRef`]) and single-owner data boxes
34//! ([`AbiBox`]). Pure C ABI, works from C/C++/Zig/anything.
35//! - **[`native`]** — the Rust convenience layer: skip hand-written vtables
36//! by exchanging native Rust fat pointers (`SafeArcDyn`, `NativeModule`).
37//! Requires identical toolchain on both sides. Rust-to-Rust only.
38//!
39//! ## Module lifecycle
40//!
41//! ```ignore
42//! // Host loads a module and its interface table:
43//! let iface = unsafe { AbiTable::<MyInterface>::load("libmy.so", b"my_get_interface\0")? };
44//! let sum = unsafe { (iface.get().add)(1, 2) };
45//!
46//! // Ref-counted module object (multi-owner):
47//! let obj = unsafe { AbiRef::<MyInterface>::load(&path, b"my_get_dyn\0")? };
48//!
49//! // Single-owner data box (freed by the producer module):
50//! let data = unsafe { AbiBoxHandle::load(&path, b"my_get_data\0")? };
51//! ```
52
53pub mod abi;
54#[path = "native.rs"]
55pub mod native;
56mod helpers;
57
58pub use abi::{
59 AbiBox, AbiBoxHandle, AbiRef, AbiTable, GeneratedFunction, MathModuleVtable, MathSession,
60 abi_box_free_rust,
61};
62pub use helpers::{DynLib, looks_like_plugin};
63pub use native::{
64 AbiDynFatPtr, AbiStableDynRef, ModuleDynEntryPoint, NativeModule, ReleaseFn, RetainFn,
65 SafeArcDyn, pack_fat_ptr, unpack_fat_ptr,
66};