Skip to main content

Crate truce_loader

Crate truce_loader 

Source
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 PluginLogic impl into the binary.

Structs§

AbiCanary
ABI fingerprint. Compared between shell and dylib before loading.
AudioBuffer
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.
EventList
Ordered list of events within a process block.
ProcessContext
Per-block context handed to process(). Construct via Self::new + the with_* builders. Marked #[non_exhaustive] so adding host-populated fields in future (e.g. host_latency, bus_routing) isn’t a SemVer break for downstream pre-1.0 callers.
Theme
Visual theme for the built-in GUI.
TransportInfo
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.
WidgetRegion
A widget’s hit region on screen.

Enums§

EventBody
ProcessStatus

Constants§

ABI_EPOCH
Hand-bumped ABI epoch. Sizes and alignments can’t see every layout change: Event::port landed in former padding, so event_size stayed 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. When AbiCanary itself 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§

PluginLogic
The f32-buffer user-facing plugin trait.
PluginLogic64
The f64-buffer user-facing plugin trait. Same surface as PluginLogic but with the audio buffer pinned to f64.
PluginLogicCore
Wrapper-facing plugin trait, generic over the audio sample type.