Expand description
Hot-reload mechanics for truce: dylib loading, ABI canary, and the
shells (HotShell<P, S>, StaticShell<P, L, S>) that bridge the
user-facing truce_plugin::PluginLogic / truce_plugin::PluginLogic64
leaf traits onto truce_core::PluginRuntime for format wrappers.
Plugin authors don’t reach into this crate directly. They write
impl PluginLogic for MyPlugin (the leaf trait is sample-pinned
via the prelude re-export) and the truce::plugin! macro picks
the static or hot shell based on the shell Cargo feature.
§ABI boundary
PluginLogic is a stateless descriptor with a separate type DspState,
so the DSP state can live in the shell rather than the reloadable
dylib. The dylib exports a flat set of Rust-ABI functions
(export_plugin!) over an opaque *mut () state pointer (an erased
Box<State>) plus the shell’s Arc<Params> pointer. HotShell owns
the state and, on a reload, keeps it when the new dylib’s
truce_state_fingerprint matches (code-only edit) - so a reverb tail
survives the swap - and re-inits it otherwise. StaticShell holds a
typed L::DspState directly.
use truce_loader::{AbiCanary, PluginLogic, PluginLogicCore};
struct MyPlugin; // stateless descriptor
impl PluginLogic for MyPlugin { type DspState = MyState; /* ... */ }
// Emitted by `truce::plugin!` (plugin authors don't write these).
// `Sample` resolves through the prelude alias (`f32` for `prelude` /
// `prelude32` / `prelude64m`, `f64` for `prelude64`).
#[unsafe(no_mangle)]
pub fn truce_init_state(params: *const ()) -> *mut () { /* Box<State> */ }
#[unsafe(no_mangle)]
pub fn truce_process(state: *mut (), params: *const (), /* ... */) { }
#[unsafe(no_mangle)]
pub fn truce_abi_canary_v2() -> AbiCanary { AbiCanary::current::<Sample>() }Modules§
- static_
shell StaticShell- embeds the plugin directly into the binary.
Macros§
- export_
plugin - Export the
#[unsafe(no_mangle)]symbols the hot-reload shell binds. - export_
static - Compile-time static embedding of a
PluginLogicimpl into the binary.
Structs§
- AbiCanary
- ABI fingerprint. Compared between shell and dylib before loading.
- Audio
Buffer - Non-interleaved audio buffer. Borrows host memory through the format wrapper.
- Color
- Color as RGBA (0.0–1.0).
- Event
- A timestamped event within a process block.
- Event
List - Ordered list of events within a process block.
- Process
Context - Per-block context handed to
process(). Construct viaSelf::new+ thewith_*builders. Marked#[non_exhaustive]so adding host-populated fields in future (e.g.host_latency,bus_routing) isn’t aSemVerbreak for downstream pre-1.0 callers. - Theme
- Visual theme for the built-in GUI.
- Transport
Info - Host-populated transport snapshot. Constructed by every format
wrapper from the host’s own transport struct via struct-literal
expressions, so this stays “exhaustive” (no
#[non_exhaustive], which would block cross-crate construction). Adding a new field is a coordinated workspace-wide change. - Widget
Region - A widget’s hit region on screen.
Enums§
Constants§
- ABI_
EPOCH - Hand-bumped ABI epoch. Sizes and alignments can’t see every
layout change:
Event::portlanded in former padding, soevent_sizestayed the same while a stale shell would read uninitialized padding as the port. Bump this when any boundary-crossing type changes layout invisibly to the size / align fields below. WhenAbiCanaryitself gains or loses a field, bump the export symbol version instead (truce_abi_canary_vN) - the canary crosses the boundary by value, so two different canary layouts must never call each other.
Traits§
- Plugin
Logic - The
f32-buffer user-facing plugin trait. - Plugin
Logic64 - The
f64-buffer user-facing plugin trait. Same surface asPluginLogicbut with the audio buffer pinned tof64. - Plugin
Logic Core - Wrapper-facing plugin trait, generic over the audio sample type.