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, DerefMut};
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(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(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) -> &mut 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
179impl DerefMut for InactivePluginMainThreadHandle<'_> {
180 #[inline]
181 fn deref_mut(&mut self) -> &mut Self::Target {
182 self.as_main_thread()
183 }
184}
185
186/// A thread-safe handle to the plugin instance.
187///
188/// This can be used to make requests to the plugin that support being made from any threads.
189#[derive(Copy, Clone, Eq, PartialEq)]
190#[repr(transparent)]
191pub struct PluginSharedHandle<'a> {
192 raw: NonNull<clap_plugin>,
193 lifetime: PhantomData<&'a clap_plugin>,
194}
195
196// SAFETY: The Shared handle only exposes thread-safe methods
197unsafe impl Send for PluginSharedHandle<'_> {}
198// SAFETY: The Shared handle only exposes thread-safe methods
199unsafe impl Sync for PluginSharedHandle<'_> {}
200
201impl<'a> PluginSharedHandle<'a> {
202 /// # Safety
203 ///
204 /// Users must ensure the provided instance pointer is valid.
205 pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
206 Self {
207 raw,
208 lifetime: PhantomData,
209 }
210 }
211
212 /// Returns the [`PluginDescriptor`] this instance corresponds to.
213 ///
214 /// This may return `None` if the underlying plugin implementation didn't properly populate
215 /// the descriptor pointer.
216 pub const fn descriptor(&self) -> Option<&'a PluginDescriptor> {
217 // SAFETY: the desc pointer is guaranteed to be valid (if present) by the CLAP spec.
218 let Some(descriptor) = (unsafe { self.as_raw().desc.as_ref() }) else {
219 return None;
220 };
221
222 // SAFETY: the desc pointer is guaranteed to be valid (if present) by the CLAP spec.
223 Some(unsafe { PluginDescriptor::from_raw(descriptor) })
224 }
225
226 /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
227 ///
228 /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
229 ///
230 /// If you need to access the raw pointer without dereferencing it first, use
231 /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
232 #[inline]
233 pub const fn as_raw(&self) -> &'a clap_plugin {
234 // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
235 unsafe { self.raw.as_ref() }
236 }
237
238 /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
239 ///
240 /// If you need to safely access the plugin instance struct through a shared reference,
241 /// use [`as_raw`](Self::as_raw) instead.
242 #[inline]
243 pub const fn as_raw_ptr(&self) -> *const clap_plugin {
244 self.raw.as_ptr()
245 }
246
247 /// Retrieves the plugin's pointer to the given [extension type](Extension) `E`.
248 ///
249 /// This returns `None` if the plugin does not support the given extension.
250 ///
251 /// # Example
252 ///
253 /// ```
254 /// use clack_extensions::params::{PluginParams};
255 /// use clack_host::plugin::PluginSharedHandle;
256 ///
257 /// # fn foo(info: PluginSharedHandle) {
258 /// let info: PluginSharedHandle = /* ... */
259 /// # info;
260 /// if let Some(params) = info.get_extension::<PluginParams>() {
261 /// // The params extension is supported by this plugin
262 /// } else {
263 /// // The params extension is not supported by this plugin
264 /// }
265 /// # }
266 /// ```
267 pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
268 let identifier = const { E::IDENTIFIERS.first().unwrap() };
269 // SAFETY: This type ensures the function pointers are valid
270 let ext = unsafe { self.as_raw().get_extension?(self.raw.as_ptr(), identifier.as_ptr()) };
271
272 let ext = NonNull::new(ext as *mut _)?;
273 // SAFETY: The CLAP spec guarantees that the extension lives as long as the instance.
274 let raw = unsafe { RawExtension::from_raw_plugin_extension(ext, self.raw) };
275
276 // SAFETY: pointer comes from the associated E::IDENTIFIER.
277 unsafe { Some(E::from_raw(raw)) }
278 }
279
280 /// Safely dereferences a [`RawExtension`] pointer produced by this plugin instance.
281 ///
282 /// See the documentation of the [`RawExtension`] type for more information about how this works
283 /// internally.
284 ///
285 /// # Panics
286 ///
287 /// This method will panic if the given extension pointer does not match the plugin instance of
288 /// this handle.
289 #[inline]
290 pub fn use_extension<E: Sized>(
291 &self,
292 extension: &RawExtension<PluginExtensionSide, E>,
293 ) -> &'a E {
294 if self.raw != extension.plugin_ptr() {
295 mismatched_instance();
296 }
297
298 // SAFETY: the RawExtension type enforces the pointee is valid for as long as the matching
299 // instance is still alive.
300 unsafe { extension.as_ptr().as_ref() }
301 }
302}
303
304impl Debug for PluginSharedHandle<'_> {
305 #[inline]
306 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
307 write!(f, "PluginSharedHandle ({:p})", self.raw)
308 }
309}
310
311/// An audio-thread handle to an activated plugin instance.
312///
313/// This can be used to make requests to the plugin that can only be made from the audio thread.
314#[derive(Eq, PartialEq)]
315#[repr(transparent)]
316pub struct PluginAudioProcessorHandle<'a> {
317 raw: NonNull<clap_plugin>,
318 lifetime: PhantomData<&'a clap_plugin>,
319}
320
321// SAFETY: This type only exposes audio-thread methods
322unsafe impl Send for PluginAudioProcessorHandle<'_> {}
323
324impl<'a> PluginAudioProcessorHandle<'a> {
325 pub(crate) const fn new(raw: NonNull<clap_plugin>) -> Self {
326 Self {
327 raw,
328 lifetime: PhantomData,
329 }
330 }
331
332 /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
333 ///
334 /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
335 ///
336 /// If you need to access the raw pointer without dereferencing it first, use
337 /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
338 #[inline]
339 pub const fn as_raw(&self) -> &'a clap_plugin {
340 // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
341 unsafe { self.raw.as_ref() }
342 }
343
344 /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
345 ///
346 /// If you need to safely access the plugin instance struct through a shared reference,
347 /// use [`as_raw`](Self::as_raw) instead.
348 #[inline]
349 pub const fn as_raw_ptr(&self) -> *const clap_plugin {
350 self.raw.as_ptr()
351 }
352
353 /// Turns this handle reference to a [`PluginSharedHandle`] reference.
354 #[inline]
355 pub const fn shared(&self) -> PluginSharedHandle<'a> {
356 PluginSharedHandle {
357 raw: self.raw,
358 lifetime: PhantomData,
359 }
360 }
361
362 /// Turns this handle reference to a [`PluginSharedHandle`] reference.
363 #[inline]
364 pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
365 // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
366 unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
367 }
368}
369
370impl<'a> Deref for PluginAudioProcessorHandle<'a> {
371 type Target = PluginSharedHandle<'a>;
372
373 #[inline]
374 fn deref(&self) -> &Self::Target {
375 self.as_shared()
376 }
377}
378
379impl Debug for PluginAudioProcessorHandle<'_> {
380 #[inline]
381 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
382 write!(f, "PluginAudioProcessorHandle ({:p})", self.raw)
383 }
384}
385
386/// A handle to a plugin instance that may be in the process of initializing.
387///
388/// In this state, only [querying plugin extensions](Self::get_extension) is allowed.
389#[derive(Clone, Eq, PartialEq)]
390pub struct InitializingPluginHandle<'a> {
391 inner: RemoteHandleInner,
392 lifetime: PhantomData<&'a clap_plugin>,
393}
394
395impl<'a> InitializingPluginHandle<'a> {
396 /// # Safety
397 ///
398 /// Users must ensure the provided instance pointer is valid until the given lock is marked as destroying.
399 pub(crate) const unsafe fn new(lock: Arc<DestroyLock>, instance: NonNull<clap_plugin>) -> Self {
400 Self {
401 lifetime: PhantomData,
402 inner: RemoteHandleInner { instance, lock },
403 }
404 }
405
406 /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
407 ///
408 /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
409 ///
410 /// If you need to access the raw pointer without dereferencing it first, use
411 /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
412 #[inline]
413 pub const fn as_raw(&self) -> &'a clap_plugin {
414 // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
415 unsafe { self.inner.instance.as_ref() }
416 }
417
418 /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
419 ///
420 /// If you need to safely access the plugin instance struct through a shared reference,
421 /// use [`as_raw`](Self::as_raw) instead.
422 #[inline]
423 pub const fn as_raw_ptr(&self) -> *const clap_plugin {
424 self.inner.instance.as_ptr()
425 }
426
427 /// Retrieves the plugin's pointer to the given [extension type](Extension) `E`.
428 ///
429 /// This returns `None` if the plugin does not support the given extension.
430 pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
431 self.inner.get_extension()
432 }
433}
434
435impl Debug for InitializingPluginHandle<'_> {
436 #[inline]
437 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
438 write!(f, "InitializingPluginHandle ({:p})", self.inner.instance)
439 }
440}
441
442/// A handle to a plugin instance that has finished initializing.
443///
444/// This handle can be used to obtain a [`PluginSharedHandle`] to then call the plugin's thread-safe
445/// method.
446///
447/// However, this handle can outlive the plugin instance, as host callbacks may be called during
448/// the plugin's destruction.
449///
450/// Therefore, the [`PluginSharedHandle`] can only be accessed through the [`access`](Self::access)
451/// method, ensuring no access can be made during or after destruction.
452#[derive(Clone, Eq, PartialEq)]
453pub struct InitializedPluginHandle<'a> {
454 inner: RemoteHandleInner,
455 lifetime: PhantomData<&'a clap_plugin>,
456}
457
458impl<'a> InitializedPluginHandle<'a> {
459 /// # Safety
460 ///
461 /// Users must ensure the provided instance pointer is valid until the given lock is marked as destroying.
462 pub(crate) const unsafe fn new(lock: Arc<DestroyLock>, instance: NonNull<clap_plugin>) -> Self {
463 Self {
464 lifetime: PhantomData,
465 inner: RemoteHandleInner { instance, lock },
466 }
467 }
468
469 /// Returns a shared reference to the raw, C-FFI compatible plugin instance struct.
470 ///
471 /// This type enforces that the reference is valid for the lifetime of the instance (`'a`).
472 ///
473 /// If you need to access the raw pointer without dereferencing it first, use
474 /// [`as_raw_ptr`](Self::as_raw_ptr) instead.
475 #[inline]
476 pub const fn as_raw(&self) -> &'a clap_plugin {
477 // SAFETY: this type enforces that the clap_plugin instance is valid for 'a.
478 unsafe { self.inner.instance.as_ref() }
479 }
480
481 /// Returns a raw pointer to the raw, C-FFI compatible plugin instance struct, without dereferencing it.
482 ///
483 /// If you need to safely access the plugin instance struct through a shared reference,
484 /// use [`as_raw`](Self::as_raw) instead.
485 #[inline]
486 pub const fn as_raw_ptr(&self) -> *const clap_plugin {
487 self.inner.instance.as_ptr()
488 }
489
490 /// Attempts to access and perform the given operation on the plugin's handle, returning its
491 /// result.
492 ///
493 /// This method will return `None` if the plugin instance is being or has been destroyed, and
494 /// `f` will not be called.
495 ///
496 /// However, this method guarantees that the plugin instance will block starting its destruction
497 /// while the given operation `f` is still ongoing.
498 ///
499 /// This ensures the plugin instance is always valid if and when `f` runs.
500 ///
501 /// # Realtime safety
502 ///
503 /// This method *may* block the current thread if it is called concurrently while the plugin's
504 /// instance is being destroyed (i.e. [`PluginInstance::drop`] is running).
505 ///
506 /// [`PluginInstance::drop`]: crate::plugin::PluginInstance::drop
507 #[inline]
508 pub fn access<T>(&self, f: impl FnOnce(PluginSharedHandle) -> T) -> Option<T> {
509 self.inner.access(f)
510 }
511
512 /// Retrieves the plugin's pointer to the given [extension type](Extension) `E`.
513 ///
514 /// This returns `None` if the plugin does not support the given extension.
515 pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
516 self.inner.get_extension()
517 }
518}
519
520impl Debug for InitializedPluginHandle<'_> {
521 #[inline]
522 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
523 write!(f, "InitializingPluginHandle ({:p})", self.inner.instance)
524 }
525}
526
527#[derive(Clone)]
528struct RemoteHandleInner {
529 lock: Arc<DestroyLock>,
530 instance: NonNull<clap_plugin>,
531}
532
533impl RemoteHandleInner {
534 fn access<T>(&self, f: impl FnOnce(PluginSharedHandle) -> T) -> Option<T> {
535 self.lock.hold_off_destruction(|| {
536 // SAFETY: this type ensures the plugin is not being destroyed yet.
537 let handle = unsafe { PluginSharedHandle::new(self.instance) };
538 f(handle)
539 })
540 }
541
542 #[inline]
543 fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
544 self.access(|handle| handle.get_extension())?
545 }
546}
547
548impl PartialEq for RemoteHandleInner {
549 #[inline]
550 fn eq(&self, other: &Self) -> bool {
551 self.instance == other.instance
552 }
553}
554
555impl Eq for RemoteHandleInner {}
556
557// SAFETY: The Shared handles only exposes thread-safe methods
558unsafe impl Send for RemoteHandleInner {}
559// SAFETY: The Shared handles only exposes thread-safe methods
560unsafe impl Sync for RemoteHandleInner {}
561
562pub(crate) struct DestroyLock {
563 is_destroying: AtomicBool,
564 lock: RwLock<bool>,
565}
566
567impl DestroyLock {
568 pub(crate) fn new() -> Self {
569 Self {
570 is_destroying: AtomicBool::new(false),
571 lock: RwLock::new(false),
572 }
573 }
574
575 pub(crate) fn start_destroying(&self) {
576 // Notify threads that may use the lock in the future that we are about to start destroying.
577 self.is_destroying.store(true, Ordering::SeqCst);
578
579 let mut guard = self.lock.write().unwrap_or_else(|err| err.into_inner());
580 // This additional check may not be very useful, it's there just in case.
581 *guard = true;
582 }
583
584 fn hold_off_destruction<T>(&self, handler: impl FnOnce() -> T) -> Option<T> {
585 if self.is_destroying.load(Ordering::SeqCst) {
586 return None;
587 }
588
589 // Poisoning doesn't matter, we are only reading a bool
590 let guard = self.lock.read().unwrap_or_else(|err| err.into_inner());
591 if *guard {
592 return None;
593 }
594
595 let result = handler();
596
597 drop(guard);
598
599 Some(result)
600 }
601}
602
603#[cold]
604const fn mismatched_instance() -> ! {
605 panic!("Given plugin instance handle doesn't match the extension pointer it was used on.")
606}