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
123
124
125
126
127
128
129
130
131
132
//! The [`RealtimeContext`] marker type.
use PhantomData;
/// Compile-time witness that the current call stack is running on the
/// host's realtime audio thread.
///
/// LADSPA's `run()` callback executes on the host's realtime thread.
/// Any function reachable from there must be allocation-free,
/// lock-free, and free of blocking system calls (see `CLAUDE.md` §
/// Prohibitions).
///
/// `RealtimeContext` is a [zero-sized type] whose only purpose is to
/// be passed as an argument. A function that requires
/// `&RealtimeContext` is **declaring** at the type level that it is
/// safe to call from the realtime thread. Conversely, code that does
/// not have a `&RealtimeContext` in scope cannot call such functions
/// — the type system rules out the misuse at compile time.
///
/// Instances cannot be constructed by user code. The framework
/// fabricates one inside the FFI shim that adapts LADSPA's `run`
/// callback to the [`Plugin`] trait, and threads it through to the
/// user's [`Plugin::run`] implementation. Outside the crate there is
/// no public path to a `RealtimeContext`, so the only way user code
/// can call a realtime-only function is from within `run()`.
///
/// # Why a marker rather than `unsafe fn`?
///
/// Marking realtime-only functions as `unsafe fn` would not be
/// useful: they are memory-safe in the conventional Rust sense
/// (they don't dereference raw pointers, don't violate aliasing).
/// The hazard they create is *non-realtime behaviour on a realtime
/// thread* — a categorically different unsafety. A bespoke marker
/// lets the framework express that invariant separately from the
/// `unsafe` keyword's existing meaning.
///
/// # Send / Sync
///
/// `RealtimeContext` is [`Send`] but not [`Sync`]. Conceptually a
/// realtime context attaches to *one* thread (the audio thread).
/// `Send` permits passing it across `move` closure boundaries within
/// that thread; `!Sync` prevents sharing it across threads, which
/// would be nonsense — if the context were shared, the "I am on the
/// realtime thread" claim could not be true for every observer.
///
/// # Layout
///
/// `RealtimeContext` is a zero-sized type: `size_of::<RealtimeContext>()
/// == 0`. Taking a reference `&RealtimeContext` is the standard way
/// to pass it; this costs at most a pointer in the calling
/// convention but, with current `rustc`, the parameter is usually
/// optimised away entirely.
///
/// [zero-sized type]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts
/// [`Plugin`]: crate
/// [`Plugin::run`]: crate
///
/// # Compile-fail check
///
/// The type intentionally does not implement [`Sync`]; the following
/// doctest verifies that a future change removing the
/// `PhantomData<Cell<()>>` field would surface as a CI failure.
///
/// ```compile_fail
/// fn requires_sync<T: Sync>() {}
/// requires_sync::<tympan_ladspa::realtime::RealtimeContext>();
/// ```