clack_plugin/factory/wrapper.rs
1use crate::extensions::wrapper::handle_panic;
2use crate::factory::error::FactoryWrapperError;
3use clack_common::factory::RawFactoryPointer;
4use std::panic::AssertUnwindSafe;
5use std::ptr::NonNull;
6
7/// A wrapper around a `clack` factory of a given `F` type, as well as its `Raw` CLAP representation.
8///
9/// This wrapper allows to safely create a CLAP-compatible factory pointer, as well as soundly
10/// casting that pointer back to this wrapper's type, allowing to access the `F` type using the
11/// [`handle`](FactoryWrapper::handle) function.
12#[repr(C)]
13pub struct FactoryWrapper<Raw, F> {
14 raw: Raw,
15 inner: F,
16}
17
18impl<Raw, F> FactoryWrapper<Raw, F> {
19 /// Creates a new factory wrapper from a `Raw` CLAP type instance and an associated instance of `F`.
20 #[inline]
21 pub const fn new(raw: Raw, inner: F) -> Self {
22 Self { raw, inner }
23 }
24
25 /// Returns a raw factory pointer compatible with this wrapper's `Raw` CLAP representation
26 #[inline]
27 pub fn as_raw(&self) -> RawFactoryPointer<'_, Raw> {
28 // Note that we borrow all of `Self` here, not just the raw field.
29 // This keeps the borrow alive and valid for the whole lifetime of the resulting factory pointer,
30 // which means that when casting back to `Self` we can still soundly access all of `F` as well.
31 let self_ptr: NonNull<Self> = self.into();
32
33 // SAFETY: This pointer comes from a reference, so it is always valid for the matching lifetime
34 unsafe { RawFactoryPointer::from_raw(self_ptr.cast()) }
35 }
36
37 /// Returns a raw pointer to the `Raw` CLAP representation contained in this wrapper.
38 #[inline]
39 pub fn as_raw_ptr(&self) -> *const Raw {
40 self.as_raw().as_raw().as_ptr()
41 }
42
43 /// Returns a shared reference to the `F` factory instance.
44 #[inline]
45 pub const fn factory(&self) -> &F {
46 &self.inner
47 }
48
49 /// Provides a shared reference to the `F` factory instance to the given handler closure.
50 ///
51 /// Besides providing a reference, this function does a few extra safety checks:
52 ///
53 /// * The given `Raw` factory pointer is null-checked;
54 /// * The handler is wrapped in [`std::panic::catch_unwind`];
55 /// * Any [`FactoryWrapperError`] returned by the handler is caught.
56 ///
57 /// If any of the above safety check fails, an error message is logged through stderr (as CLAP
58 /// logging facilities are not available at the factory stage).
59 ///
60 /// Note that some safety checks (e.g. the `Raw` pointer null-checks) may result in the
61 /// closure never being called, and an error being returned only. Users of this function must
62 /// not rely on the completion of this closure for safety, and must handle this function
63 /// returning `None` gracefully.
64 ///
65 /// If all goes well, the return value of the handler closure is forwarded and returned by this
66 /// function.
67 ///
68 /// # Errors
69 ///
70 /// If any safety check failed, or any error or panic occurred inside the handler closure, this
71 /// function returns `None`, and the error message is logged.
72 ///
73 /// # Safety
74 ///
75 /// The `raw` pointer must be created by the [`as_raw`](Self::as_raw) method, from an instance that
76 /// is still valid for the duration of the `handler` call.
77 ///
78 /// While this function does a couple of simple safety checks, only a few common
79 /// cases are actually covered (i.e. null checks), and those **must not** be relied upon: those
80 /// checks only exist to help debugging faulty hosts.
81 ///
82 /// # Example
83 ///
84 /// This is the implementation of the [`plugin_count`](crate::factory::plugin::PluginFactoryImpl::plugin_count)
85 /// callback's C wrapper.
86 ///
87 /// ```
88 /// use clap_sys::factory::plugin_factory::clap_plugin_factory;
89 /// use clack_plugin::plugin::{Plugin, PluginMainThread};
90 /// use clack_plugin::factory::{FactoryWrapper, plugin::PluginFactoryImpl};
91 ///
92 /// unsafe extern "C" fn get_plugin_count<F: PluginFactoryImpl>(factory: *const clap_plugin_factory) -> u32 {
93 /// FactoryWrapper::<clap_plugin_factory, F>::handle(factory, |factory| {
94 /// Ok(factory.plugin_count())
95 /// })
96 /// .unwrap_or(0)
97 /// }
98 /// ```
99 #[must_use]
100 pub unsafe fn handle<T>(
101 raw: *const Raw,
102 handler: impl FnOnce(&F) -> Result<T, FactoryWrapperError>,
103 ) -> Option<T> {
104 // SAFETY: The caller ensures this pointer comes from the reference in as_raw
105 let factory = unsafe { raw.cast::<Self>().as_ref() };
106 let result = factory.ok_or(FactoryWrapperError::NullFactoryInstance);
107
108 let result = result.and_then(|f| f.handle_panic(handler));
109
110 Self::handle_result(result)
111 }
112
113 #[inline]
114 fn handle_panic<T>(
115 &self,
116 handler: impl FnOnce(&F) -> Result<T, FactoryWrapperError>,
117 ) -> Result<T, FactoryWrapperError> {
118 match handle_panic(AssertUnwindSafe(|| handler(&self.inner))) {
119 Err(_) => Err(FactoryWrapperError::Panic),
120 Ok(Err(e)) => Err(e),
121 Ok(Ok(val)) => Ok(val),
122 }
123 }
124
125 #[inline]
126 fn handle_result<T>(result: Result<T, FactoryWrapperError>) -> Option<T> {
127 match result {
128 Ok(value) => Some(value),
129 Err(e) => {
130 eprintln!("[CLAP_PLUGIN_FACTORY_ERROR] {e}");
131
132 None
133 }
134 }
135 }
136}