Skip to main content

clack_host/plugin/
handle.rs

1use clack_common::extensions::{Extension, PluginExtensionSide, RawExtension};
2use clack_common::plugin::PluginDescriptor;
3use clap_sys::plugin::clap_plugin;
4use std::fmt::{Debug, Formatter};
5use std::marker::PhantomData;
6use std::ops::Deref;
7use std::ptr::NonNull;
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::sync::{Arc, RwLock};
10
11/// A main-thread handle to the plugin instance.
12///
13/// This can be used to make requests to the plugin that can only be made in the main thread, which
14/// is required for e.g. some extensions.
15#[derive(Copy, Clone, Eq, PartialEq)]
16#[repr(transparent)]
17pub struct PluginMainThreadHandle<'a> {
18    raw: NonNull<clap_plugin>,
19    lifetime: PhantomData<&'a clap_plugin>,
20}
21
22impl<'a> PluginMainThreadHandle<'a> {
23    /// # Safety
24    /// The user must ensure the provided plugin pointer is valid.
25    /// This can only be called on the main thread.
26    pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
27        Self {
28            raw,
29            lifetime: PhantomData,
30        }
31    }
32
33    /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
34    ///
35    /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
36    ///
37    /// If you need to access the raw pointer without dereferencing it first, use
38    /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
39    #[inline]
40    pub const fn as_raw(&self) -> &'a clap_plugin {
41        // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
42        unsafe { self.raw.as_ref() }
43    }
44
45    /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
46    ///
47    /// If you need to safely access the plugin instance struct through a shared reference,
48    /// use [`as_raw`](Self::as_raw) instead.
49    #[inline]
50    pub const fn as_raw_ptr(&self) -> *const clap_plugin {
51        self.raw.as_ptr()
52    }
53
54    /// Produces a [`PluginSharedHandle`] from this main-thread handle.
55    #[inline]
56    pub const fn shared(&self) -> PluginSharedHandle<'a> {
57        // SAFETY: This type ensures the provided pointer is valid for 'a
58        unsafe { PluginSharedHandle::new(self.raw) }
59    }
60
61    /// Turns this handle reference to a [`PluginSharedHandle`] reference.
62    #[inline]
63    pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
64        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
65        unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
66    }
67}
68
69impl Debug for PluginMainThreadHandle<'_> {
70    #[inline]
71    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72        write!(f, "PluginMainThreadHandle ({:p})", self.raw)
73    }
74}
75
76impl<'a> Deref for PluginMainThreadHandle<'a> {
77    type Target = PluginSharedHandle<'a>;
78
79    #[inline]
80    fn deref(&self) -> &Self::Target {
81        self.as_shared()
82    }
83}
84
85/// A main-thread handle to the plugin, that can only exist while the plugin is in the 'inactive' state.
86///
87/// This is used by some extensions that e.g. require a function to be called on the main thread only
88/// if the plugin is inactive, and on the audio thread if it is active.
89#[derive(Copy, Clone, Eq, PartialEq)]
90#[repr(transparent)]
91pub struct InactivePluginMainThreadHandle<'a> {
92    raw: NonNull<clap_plugin>,
93    lifetime: PhantomData<&'a clap_plugin>,
94}
95
96impl<'a> InactivePluginMainThreadHandle<'a> {
97    /// # Safety
98    /// The user must ensure the provided plugin pointer is valid.
99    /// This can only be called on the main thread, and the plugin instance must be inactive for `'a`.
100    pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
101        Self {
102            raw,
103            lifetime: PhantomData,
104        }
105    }
106
107    /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
108    ///
109    /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
110    ///
111    /// If you need to access the raw pointer without dereferencing it first, use
112    /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
113    #[inline]
114    pub const fn as_raw(&self) -> &'a clap_plugin {
115        // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
116        unsafe { self.raw.as_ref() }
117    }
118
119    /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
120    ///
121    /// If you need to safely access the plugin instance struct through a shared reference,
122    /// use [`as_raw`](Self::as_raw) instead.
123    #[inline]
124    pub const fn as_raw_ptr(&self) -> *const clap_plugin {
125        self.raw.as_ptr()
126    }
127
128    /// Produces a [`PluginSharedHandle`] from this main-thread handle.
129    #[inline]
130    pub const fn shared(&self) -> PluginSharedHandle<'a> {
131        // SAFETY: This type ensures the provided pointer is valid for 'a
132        unsafe { PluginSharedHandle::new(self.raw) }
133    }
134
135    /// Turns this handle reference to a [`PluginSharedHandle`] reference.
136    #[inline]
137    pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
138        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
139        unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
140    }
141
142    // Note: this function is pretty useless, but is needed for the Deref impl (required by DerefMut)
143    #[inline]
144    const fn as_main_thread_ref(&self) -> &PluginMainThreadHandle<'a> {
145        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
146        unsafe { &*(self as *const Self as *const PluginMainThreadHandle<'a>) }
147    }
148
149    /// Turns this handle reference to an exclusive [`PluginMainThreadHandle`] reference.
150    ///
151    /// This may be useful if you receive a [`InactivePluginMainThreadHandle`] but need to use
152    /// some methods or extensions that do not care whether the plugin instance is currently active or not.
153    ///
154    /// Only one of the [`InactivePluginMainThreadHandle`] and [`PluginMainThreadHandle`] may be
155    /// used at the same time.
156    #[inline]
157    pub const fn as_main_thread(&mut self) -> &PluginMainThreadHandle<'a> {
158        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
159        unsafe { &mut *(self as *mut Self as *mut PluginMainThreadHandle<'a>) }
160    }
161}
162
163impl Debug for InactivePluginMainThreadHandle<'_> {
164    #[inline]
165    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
166        write!(f, "InactivePluginMainThreadHandle ({:p})", self.raw)
167    }
168}
169
170impl<'a> Deref for InactivePluginMainThreadHandle<'a> {
171    type Target = PluginMainThreadHandle<'a>;
172
173    #[inline]
174    fn deref(&self) -> &Self::Target {
175        self.as_main_thread_ref()
176    }
177}
178
179/// A thread-safe handle to the plugin instance.
180///
181/// This can be used to make requests to the plugin that support being made from any threads.
182#[derive(Copy, Clone, Eq, PartialEq)]
183#[repr(transparent)]
184pub struct PluginSharedHandle<'a> {
185    raw: NonNull<clap_plugin>,
186    lifetime: PhantomData<&'a clap_plugin>,
187}
188
189// SAFETY: The Shared handle only exposes thread-safe methods
190unsafe impl Send for PluginSharedHandle<'_> {}
191// SAFETY: The Shared handle only exposes thread-safe methods
192unsafe impl Sync for PluginSharedHandle<'_> {}
193
194impl<'a> PluginSharedHandle<'a> {
195    /// # Safety
196    ///
197    /// Users must ensure the provided instance pointer is valid.
198    pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
199        Self {
200            raw,
201            lifetime: PhantomData,
202        }
203    }
204
205    /// Returns the [`PluginDescriptor`] this instance corresponds to.
206    ///
207    /// This may return `None` if the underlying plugin implementation didn't properly populate
208    /// the descriptor pointer.
209    pub const fn descriptor(&self) -> Option<&'a PluginDescriptor> {
210        // SAFETY: the desc pointer is guaranteed to be valid (if present) by the CLAP spec.
211        let Some(descriptor) = (unsafe { self.as_raw().desc.as_ref() }) else {
212            return None;
213        };
214
215        // SAFETY: the desc pointer is guaranteed to be valid (if present) by the CLAP spec.
216        Some(unsafe { PluginDescriptor::from_raw(descriptor) })
217    }
218
219    /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
220    ///
221    /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
222    ///
223    /// If you need to access the raw pointer without dereferencing it first, use
224    /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
225    #[inline]
226    pub const fn as_raw(&self) -> &'a clap_plugin {
227        // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
228        unsafe { self.raw.as_ref() }
229    }
230
231    /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
232    ///
233    /// If you need to safely access the plugin instance struct through a shared reference,
234    /// use [`as_raw`](Self::as_raw) instead.
235    #[inline]
236    pub const fn as_raw_ptr(&self) -> *const clap_plugin {
237        self.raw.as_ptr()
238    }
239
240    /// Retrieves the plugin's pointer to the given [extension type](Extension) `E`.
241    ///
242    /// This returns `None` if the plugin does not support the given extension.
243    ///
244    /// # Example
245    ///
246    /// ```
247    /// use clack_extensions::params::{PluginParams};
248    /// use clack_host::plugin::PluginSharedHandle;
249    ///
250    /// # fn foo(info: PluginSharedHandle) {
251    /// let info: PluginSharedHandle = /* ... */
252    /// # info;
253    /// if let Some(params) = info.get_extension::<PluginParams>() {
254    ///     // The params extension is supported by this plugin
255    /// } else {
256    ///     // The params extension is not supported by this plugin
257    /// }
258    /// # }
259    /// ```
260    pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
261        let identifier = const { E::IDENTIFIERS.first().unwrap() };
262        // SAFETY: This type ensures the function pointers are valid
263        let ext = unsafe { self.as_raw().get_extension?(self.raw.as_ptr(), identifier.as_ptr()) };
264
265        let ext = NonNull::new(ext as *mut _)?;
266        // SAFETY: The CLAP spec guarantees that the extension lives as long as the instance.
267        let raw = unsafe { RawExtension::from_raw_plugin_extension(ext, self.raw) };
268
269        // SAFETY: pointer comes from the associated E::IDENTIFIER.
270        unsafe { Some(E::from_raw(raw)) }
271    }
272
273    /// Safely dereferences a [`RawExtension`] pointer produced by this plugin instance.
274    ///
275    /// See the documentation of the [`RawExtension`] type for more information about how this works
276    /// internally.
277    ///
278    /// # Panics
279    ///
280    /// This method will panic if the given extension pointer does not match the plugin instance of
281    /// this handle.
282    #[inline]
283    pub fn use_extension<E: Sized>(
284        &self,
285        extension: &RawExtension<PluginExtensionSide, E>,
286    ) -> &'a E {
287        if self.raw != extension.plugin_ptr() {
288            mismatched_instance();
289        }
290
291        // SAFETY: the RawExtension type enforces the pointee is valid for as long as the matching
292        // instance is still alive.
293        unsafe { extension.as_ptr().as_ref() }
294    }
295}
296
297impl Debug for PluginSharedHandle<'_> {
298    #[inline]
299    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
300        write!(f, "PluginSharedHandle ({:p})", self.raw)
301    }
302}
303
304/// An audio-thread handle to an activated plugin instance.
305///
306/// This can be used to make requests to the plugin that can only be made from the audio thread.
307#[derive(Eq, PartialEq)]
308#[repr(transparent)]
309pub struct PluginAudioProcessorHandle<'a> {
310    raw: NonNull<clap_plugin>,
311    lifetime: PhantomData<&'a clap_plugin>,
312}
313
314// SAFETY: This type only exposes audio-thread methods
315unsafe impl Send for PluginAudioProcessorHandle<'_> {}
316
317impl<'a> PluginAudioProcessorHandle<'a> {
318    pub(crate) const fn new(raw: NonNull<clap_plugin>) -> Self {
319        Self {
320            raw,
321            lifetime: PhantomData,
322        }
323    }
324
325    /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
326    ///
327    /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
328    ///
329    /// If you need to access the raw pointer without dereferencing it first, use
330    /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
331    #[inline]
332    pub const fn as_raw(&self) -> &'a clap_plugin {
333        // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
334        unsafe { self.raw.as_ref() }
335    }
336
337    /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
338    ///
339    /// If you need to safely access the plugin instance struct through a shared reference,
340    /// use [`as_raw`](Self::as_raw) instead.
341    #[inline]
342    pub const fn as_raw_ptr(&self) -> *const clap_plugin {
343        self.raw.as_ptr()
344    }
345
346    /// Turns this handle reference to a [`PluginSharedHandle`] reference.
347    #[inline]
348    pub const fn shared(&self) -> PluginSharedHandle<'a> {
349        PluginSharedHandle {
350            raw: self.raw,
351            lifetime: PhantomData,
352        }
353    }
354
355    /// Turns this handle reference to a [`PluginSharedHandle`] reference.
356    #[inline]
357    pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
358        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
359        unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
360    }
361}
362
363impl<'a> Deref for PluginAudioProcessorHandle<'a> {
364    type Target = PluginSharedHandle<'a>;
365
366    #[inline]
367    fn deref(&self) -> &Self::Target {
368        self.as_shared()
369    }
370}
371
372impl Debug for PluginAudioProcessorHandle<'_> {
373    #[inline]
374    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
375        write!(f, "PluginAudioProcessorHandle ({:p})", self.raw)
376    }
377}
378
379/// A handle to a plugin instance that may be in the process of initializing.
380///
381/// In this state, only [querying plugin extensions](Self::get_extension) is allowed.
382#[derive(Clone, Eq, PartialEq)]
383pub struct InitializingPluginHandle<'a> {
384    inner: RemoteHandleInner,
385    lifetime: PhantomData<&'a clap_plugin>,
386}
387
388impl<'a> InitializingPluginHandle<'a> {
389    /// # Safety
390    ///
391    /// Users must ensure the provided instance pointer is valid until the given lock is marked as destroying.
392    pub(crate) const unsafe fn new(lock: Arc<DestroyLock>, instance: NonNull<clap_plugin>) -> Self {
393        Self {
394            lifetime: PhantomData,
395            inner: RemoteHandleInner { instance, lock },
396        }
397    }
398
399    /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
400    ///
401    /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
402    ///
403    /// If you need to access the raw pointer without dereferencing it first, use
404    /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
405    #[inline]
406    pub const fn as_raw(&self) -> &'a clap_plugin {
407        // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
408        unsafe { self.inner.instance.as_ref() }
409    }
410
411    /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
412    ///
413    /// If you need to safely access the plugin instance struct through a shared reference,
414    /// use [`as_raw`](Self::as_raw) instead.
415    #[inline]
416    pub const fn as_raw_ptr(&self) -> *const clap_plugin {
417        self.inner.instance.as_ptr()
418    }
419
420    /// Retrieves the plugin's pointer to the given [extension type](Extension) `E`.
421    ///
422    /// This returns `None` if the plugin does not support the given extension.
423    pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
424        self.inner.get_extension()
425    }
426}
427
428impl Debug for InitializingPluginHandle<'_> {
429    #[inline]
430    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
431        write!(f, "InitializingPluginHandle ({:p})", self.inner.instance)
432    }
433}
434
435/// A handle to a plugin instance that has finished initializing.
436///
437/// This handle can be used to obtain a [`PluginSharedHandle`] to then call the plugin's thread-safe
438/// method.
439///
440/// However, this handle can outlive the plugin instance, as host callbacks may be called during
441/// the plugin's destruction.
442///
443/// Therefore, the [`PluginSharedHandle`] can only be accessed through the [`access`](Self::access)
444/// method, ensuring no access can be made during or after destruction.
445#[derive(Clone, Eq, PartialEq)]
446pub struct InitializedPluginHandle<'a> {
447    inner: RemoteHandleInner,
448    lifetime: PhantomData<&'a clap_plugin>,
449}
450
451impl<'a> InitializedPluginHandle<'a> {
452    /// # Safety
453    ///
454    /// Users must ensure the provided instance pointer is valid until the given lock is marked as destroying.
455    pub(crate) const unsafe fn new(lock: Arc<DestroyLock>, instance: NonNull<clap_plugin>) -> Self {
456        Self {
457            lifetime: PhantomData,
458            inner: RemoteHandleInner { instance, lock },
459        }
460    }
461
462    /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
463    ///
464    /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
465    ///
466    /// If you need to access the raw pointer without dereferencing it first, use
467    /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
468    #[inline]
469    pub const fn as_raw(&self) -> &'a clap_plugin {
470        // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
471        unsafe { self.inner.instance.as_ref() }
472    }
473
474    /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
475    ///
476    /// If you need to safely access the plugin instance struct through a shared reference,
477    /// use [`as_raw`](Self::as_raw) instead.
478    #[inline]
479    pub const fn as_raw_ptr(&self) -> *const clap_plugin {
480        self.inner.instance.as_ptr()
481    }
482
483    /// Attempts to access and perform the given operation on the plugin's handle, returning its
484    /// result.
485    ///
486    /// This method will return `None` if the plugin instance is being or has been destroyed, and
487    /// `f` will not be called.
488    ///
489    /// However, this method guarantees that the plugin instance will block starting its destruction
490    /// while the given operation `f` is still ongoing.
491    ///
492    /// This ensures the plugin instance is always valid if and when `f` runs.
493    ///
494    /// # Realtime safety
495    ///
496    /// This method *may* block the current thread if it is called concurrently while the plugin's
497    /// instance is being destroyed (i.e. [`PluginInstance::drop`] is running).
498    ///
499    /// [`PluginInstance::drop`]: crate::plugin::PluginInstance::drop
500    #[inline]
501    pub fn access<T>(&self, f: impl FnOnce(PluginSharedHandle) -> T) -> Option<T> {
502        self.inner.access(f)
503    }
504
505    /// Retrieves the plugin's pointer to the given [extension type](Extension) `E`.
506    ///
507    /// This returns `None` if the plugin does not support the given extension.
508    pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
509        self.inner.get_extension()
510    }
511}
512
513impl Debug for InitializedPluginHandle<'_> {
514    #[inline]
515    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
516        write!(f, "InitializingPluginHandle ({:p})", self.inner.instance)
517    }
518}
519
520#[derive(Clone)]
521struct RemoteHandleInner {
522    lock: Arc<DestroyLock>,
523    instance: NonNull<clap_plugin>,
524}
525
526impl RemoteHandleInner {
527    fn access<T>(&self, f: impl FnOnce(PluginSharedHandle) -> T) -> Option<T> {
528        self.lock.hold_off_destruction(|| {
529            // SAFETY: this type ensures the plugin is not being destroyed yet.
530            let handle = unsafe { PluginSharedHandle::new(self.instance) };
531            f(handle)
532        })
533    }
534
535    #[inline]
536    fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
537        self.access(|handle| handle.get_extension())?
538    }
539}
540
541impl PartialEq for RemoteHandleInner {
542    #[inline]
543    fn eq(&self, other: &Self) -> bool {
544        self.instance == other.instance
545    }
546}
547
548impl Eq for RemoteHandleInner {}
549
550// SAFETY: The Shared handles only exposes thread-safe methods
551unsafe impl Send for RemoteHandleInner {}
552// SAFETY: The Shared handles only exposes thread-safe methods
553unsafe impl Sync for RemoteHandleInner {}
554
555pub(crate) struct DestroyLock {
556    is_destroying: AtomicBool,
557    lock: RwLock<bool>,
558}
559
560impl DestroyLock {
561    pub(crate) fn new() -> Self {
562        Self {
563            is_destroying: AtomicBool::new(false),
564            lock: RwLock::new(false),
565        }
566    }
567
568    pub(crate) fn start_destroying(&self) {
569        // Notify threads that may use the lock in the future that we are about to start destroying.
570        self.is_destroying.store(true, Ordering::SeqCst);
571
572        let mut guard = self.lock.write().unwrap_or_else(|err| err.into_inner());
573        // This additional check may not be very useful, it's there just in case.
574        *guard = true;
575    }
576
577    fn hold_off_destruction<T>(&self, handler: impl FnOnce() -> T) -> Option<T> {
578        if self.is_destroying.load(Ordering::SeqCst) {
579            return None;
580        }
581
582        // Poisoning doesn't matter, we are only reading a bool
583        let guard = self.lock.read().unwrap_or_else(|err| err.into_inner());
584        if *guard {
585            return None;
586        }
587
588        let result = handler();
589
590        drop(guard);
591
592        Some(result)
593    }
594}
595
596#[cold]
597const fn mismatched_instance() -> ! {
598    panic!("Given plugin instance handle doesn't match the extension pointer it was used on.")
599}