1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Hot-reload mechanics for truce: dylib loading, ABI canary,
//! vtable probe, 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::Plugin`] 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
//!
//! Across the dylib boundary the shell holds a
//! `Box<dyn truce_plugin::PluginLogicCore<S>>` - the generic
//! wrapper-facing trait that both leaf traits forward into via
//! blanket impls in `truce-plugin`. The single trait object
//! carries DSP and GUI methods through one vtable, with `S` baked
//! in by the shell's generic parameter (and recorded in
//! `AbiCanary::sample_precision` so a precision mismatch fails
//! the canary check before vtable-binding).
//!
//! ```ignore
//! use truce_loader::{AbiCanary, PluginLogic, PluginLogicCore};
//!
//! struct MyPlugin { /* ... */ }
//! impl PluginLogic for MyPlugin { /* DSP + GUI */ }
//!
//! // Emitted by `truce::plugin!`; plugin authors don't write these
//! // by hand. `Sample` resolves through the prelude alias
//! // (`f32` for `prelude` / `prelude32` / `prelude64m`,
//! // `f64` for `prelude64`). The macro also emits a
//! // `truce_vtable_probe` symbol that constructs an internal
//! // `ProbePlugin`; that type lives in `__macro_deps` and isn't
//! // intended for direct use.
//! #[unsafe(no_mangle)]
//! pub fn truce_create(p: *const ()) -> Box<dyn PluginLogicCore<Sample>> {
//! Box::new(MyPlugin::new(/* params from p */))
//! }
//!
//! #[unsafe(no_mangle)]
//! pub fn truce_abi_canary() -> AbiCanary { AbiCanary::current::<Sample>() }
//! ```
pub use AbiCanary;
// `ProbePlugin`, `verify_probe`, and `ProbeError` are loader-internal.
// `ProbePlugin` lives under `__macro_deps` so the `export_plugin!`
// macro's `truce_vtable_probe` body can name it without leaking the
// type at the crate root. `verify_probe` / `ProbeError` are only used
// by `NativeLoader::build_candidate` (gated on `feature = "shell"`)
// and are reached via `crate::canary` directly inside `loader.rs`.
// Format wrappers and plugin authors reach the probe by dlopening
// the `truce_vtable_probe` symbol the macro emits, not by `use` import.
pub use *;
pub use ;
pub use NativeLoader;
/// Export the `#[unsafe(no_mangle)]` functions required by the shell.
///
/// `params_ptr` is a raw `Arc<Params>` pointer from the shell.
/// The plugin receives shared params - one copy, no sync.