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}