Skip to main content

clack_plugin/
host.rs

1//! Types and handles for plugins to interact with the host.
2
3use clack_common::extensions::{Extension, HostExtensionSide, RawExtension};
4use clack_common::utils::ClapVersion;
5use clap_sys::host::clap_host;
6use std::ffi::CStr;
7use std::marker::PhantomData;
8use std::ops::Deref;
9use std::ptr::NonNull;
10
11/// Various information about the host, provided at plugin instantiation time.
12#[derive(Copy, Clone)]
13#[repr(transparent)]
14pub struct HostInfo<'a> {
15    raw: NonNull<clap_host>,
16    _lifetime: PhantomData<&'a clap_host>,
17}
18
19impl<'a> HostInfo<'a> {
20    /// Creates a new [`HostInfo`] type from a given raw, C FFI compatible pointer.
21    ///
22    /// # Safety
23    /// Pointer must be valid for the duration of the `'a` lifetime. Moreover, the contents of
24    /// the `clap_host` struct must all also be valid.
25    #[inline]
26    pub const unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
27        Self {
28            raw,
29            _lifetime: PhantomData,
30        }
31    }
32
33    /// The [`ClapVersion`] the host uses.
34    #[inline]
35    pub const fn clap_version(&self) -> ClapVersion {
36        ClapVersion::from_raw(self.as_raw().clap_version)
37    }
38
39    /// A user-friendly name for the host (e.g. "Bitwig Studio").
40    ///
41    /// This should always be set by the host.
42    pub const fn name(&self) -> Option<&'a CStr> {
43        let Some(ptr) = NonNull::new(self.as_raw().name as *mut _) else {
44            return None;
45        };
46        // SAFETY: this type ensures the pointers are valid
47        Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
48    }
49
50    /// The host's vendor (e.g. "Bitwig GmbH").
51    ///
52    /// This field is optional.
53    pub const fn vendor(&self) -> Option<&'a CStr> {
54        let Some(ptr) = NonNull::new(self.as_raw().vendor as *mut _) else {
55            return None;
56        };
57        // SAFETY: this type ensures the pointers are valid
58        Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
59    }
60
61    /// A URL to the host's webpage.
62    ///
63    /// This field is optional.
64    pub const fn url(&self) -> Option<&'a CStr> {
65        let Some(ptr) = NonNull::new(self.as_raw().url as *mut _) else {
66            return None;
67        };
68        // SAFETY: this type ensures the pointers are valid
69        Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
70    }
71
72    /// A version string for the host (e.g. "4.3").
73    ///
74    /// This should always be set by the host.
75    pub const fn version(&self) -> Option<&'a CStr> {
76        let Some(ptr) = NonNull::new(self.as_raw().version as *mut _) else {
77            return None;
78        };
79        // SAFETY: this type ensures the pointers are valid
80        Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
81    }
82
83    /// Retrieves the host's pointer to the given [extension type](Extension) `E`.
84    ///
85    /// This returns `None` if the host does not support the given extension.
86    ///
87    /// # Example
88    ///
89    /// ```
90    /// use clack_extensions::log::{HostLog, LogSeverity};
91    /// use clack_plugin::host::HostInfo;
92    ///
93    /// # fn foo(info: HostInfo) {
94    /// let info: HostInfo = /* ... */
95    /// # info;
96    /// if let Some(log) = info.get_extension::<HostLog>() {
97    ///     // The log extension is supported by this host
98    /// } else {
99    ///     // The log extension is not supported by this host
100    /// }
101    /// # }
102    /// ```
103    pub fn get_extension<E: Extension<ExtensionSide = HostExtensionSide>>(&self) -> Option<E> {
104        let identifier = const { E::IDENTIFIERS.first().unwrap() };
105        // SAFETY: this type ensures the function pointers are valid
106        let ext = unsafe { self.as_raw().get_extension?(self.raw.as_ptr(), identifier.as_ptr()) };
107
108        let ext = NonNull::new(ext as *mut _)?;
109        // SAFETY: The CLAP spec guarantees that the extension lives as long as the instance.
110        let raw = unsafe { RawExtension::from_raw_host_extension(ext, self.raw) };
111
112        // SAFETY: pointer comes from the associated E::IDENTIFIER.
113        unsafe { Some(E::from_raw(raw)) }
114    }
115
116    /// # Safety
117    /// Some functions exposed by [`HostSharedHandle`] cannot be called until plugin is initializing
118    #[inline]
119    pub(crate) const unsafe fn to_handle(self) -> HostSharedHandle<'a> {
120        HostSharedHandle {
121            raw: self.raw,
122            _lifetime: PhantomData,
123        }
124    }
125
126    /// Returns a raw, C FFI-compatible reference to the host handle.
127    #[inline]
128    pub const fn as_raw(&self) -> &'a clap_host {
129        // SAFETY: this type ensures the raw pointer is valid
130        unsafe { self.raw.as_ref() }
131    }
132}
133
134/// A thread-safe handle to the host.
135///
136/// This can be used to fetch information about the host, scan available extensions, or perform
137/// requests to the host.
138#[derive(Copy, Clone)]
139#[repr(transparent)]
140pub struct HostSharedHandle<'a> {
141    raw: NonNull<clap_host>,
142    _lifetime: PhantomData<&'a clap_host>,
143}
144
145// SAFETY: this type only safely exposes the thread-safe operations of clap_host
146unsafe impl Send for HostSharedHandle<'_> {}
147// SAFETY: this type only safely exposes the thread-safe operations of clap_host
148unsafe impl Sync for HostSharedHandle<'_> {}
149
150impl<'a> HostSharedHandle<'a> {
151    /// Returns the host's information.
152    #[inline]
153    pub const fn info(&self) -> HostInfo<'a> {
154        HostInfo {
155            raw: self.raw,
156            _lifetime: PhantomData,
157        }
158    }
159
160    /// Returns a raw, C FFI-compatible reference to the host handle.
161    #[inline]
162    pub const fn as_raw(&self) -> &'a clap_host {
163        // SAFETY: this type enforces the pointer is valid for 'a
164        unsafe { self.raw.as_ref() }
165    }
166
167    /// Returns this handle as a reference to the host's information.
168    #[inline]
169    pub const fn as_info(&self) -> &HostInfo<'a> {
170        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
171        unsafe { &*(self as *const Self as *const HostInfo<'a>) }
172    }
173
174    /// Requests the host to [deactivate](crate::plugin::PluginAudioProcessor::deactivate) and then
175    /// [re-activate](crate::plugin::PluginAudioProcessor::activate) the plugin.
176    /// The operation may be delayed by the host.
177    #[inline]
178    pub fn request_restart(&self) {
179        if let Some(request_restart) = self.as_raw().request_restart {
180            // SAFETY: field is guaranteed to be correct by host. Lifetime is enforced by 'a
181            unsafe { request_restart(self.raw.as_ptr()) }
182        }
183    }
184
185    /// Requests the host to [activate](crate::plugin::PluginAudioProcessor::activate) the plugin,
186    /// and start audio processing.
187    /// This is useful if you have external IO and need to wake the plugin up from "sleep".
188    #[inline]
189    pub fn request_process(&self) {
190        if let Some(request_process) = self.as_raw().request_process {
191            // SAFETY: field is guaranteed to be correct by host. Lifetime is enforced by 'a
192            unsafe { request_process(self.raw.as_ptr()) }
193        }
194    }
195
196    /// Requests the host to schedule a call to the
197    /// [on_main_thread](crate::plugin::PluginMainThread::on_main_thread) method on the main thread.
198    #[inline]
199    pub fn request_callback(&self) {
200        if let Some(request_callback) = self.as_raw().request_callback {
201            // SAFETY: field is guaranteed to be correct by host. Lifetime is enforced by 'a
202            unsafe { request_callback(self.raw.as_ptr()) }
203        }
204    }
205
206    /// Unsafely creates a main-thread host handle from this thread-safe handle.
207    ///
208    /// # Safety
209    ///
210    /// Callers *MUST* ensure this is only called on the main thread, and that they have exclusive (&mut) access.
211    #[inline]
212    pub const unsafe fn as_main_thread_unchecked(&self) -> HostMainThreadHandle<'a> {
213        HostMainThreadHandle {
214            raw: self.raw,
215            _lifetime: PhantomData,
216        }
217    }
218
219    /// Unsafely creates an audio-processor host handle from this thread-safe handle.
220    ///
221    /// # Safety
222    ///
223    /// Callers *MUST* ensure this is only called on the audio thread, and that they have exclusive (&mut) access.
224    #[inline]
225    pub const unsafe fn as_audio_processor_unchecked(&self) -> HostAudioProcessorHandle<'a> {
226        HostAudioProcessorHandle {
227            raw: self.raw,
228            _lifetime: PhantomData,
229        }
230    }
231
232    /// Safely dereferences a [`RawExtension`] pointer produced by this host.
233    ///
234    /// See the documentation of the [`RawExtension`] type for more information about how this works
235    /// internally.
236    ///
237    /// # Panics
238    ///
239    /// This method will panic if the given extension pointer does not match the host
240    /// this handle came from.
241    #[inline]
242    pub fn use_extension<E: Sized>(&self, extension: &RawExtension<HostExtensionSide, E>) -> &'a E {
243        if self.raw != extension.host_ptr() {
244            mismatched_instance();
245        }
246
247        // SAFETY: the RawExtension type enforces the pointee is valid for as long as the matching
248        // instance is still alive.
249        unsafe { extension.as_ptr().as_ref() }
250    }
251
252    /// Creates a [`HostSharedHandle`] from a raw `clap_host` pointer.
253    ///
254    /// # Safety
255    ///
256    ///
257    #[inline]
258    pub unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
259        Self {
260            raw,
261            _lifetime: PhantomData,
262        }
263    }
264
265    /// Returns a [`HostSharedHandle`] that points to the same host, but with an arbitrary lifetime
266    /// instead of the host's.
267    ///
268    /// This can be useful in situations where you need to use host callbacks in a container that
269    /// does not let you use proper lifetimes, but you can still guarantee that host callbacks won't
270    /// be called after the host's `'a` lifetime.
271    ///
272    /// # Safety
273    ///
274    /// The returned handle's lifetime is completely meaningless here.
275    /// Proper care muse be taken in order to ensure *no* methods on this type are used beyond the
276    /// original host `'a` lifetime.
277    #[inline]
278    pub unsafe fn with_arbitrary_lifetime<'b>(&self) -> HostSharedHandle<'b> {
279        HostSharedHandle {
280            raw: self.raw,
281            _lifetime: PhantomData,
282        }
283    }
284}
285
286impl<'a> From<HostSharedHandle<'a>> for HostInfo<'a> {
287    #[inline]
288    fn from(h: HostSharedHandle<'a>) -> Self {
289        h.info()
290    }
291}
292
293impl<'a> Deref for HostSharedHandle<'a> {
294    type Target = HostInfo<'a>;
295
296    #[inline]
297    fn deref(&self) -> &Self::Target {
298        self.as_info()
299    }
300}
301
302/// A main-thread handle to the host.
303///
304/// This can be used to perform requests to the host that can only be made from the main thread.
305#[repr(transparent)]
306pub struct HostMainThreadHandle<'a> {
307    raw: NonNull<clap_host>,
308    _lifetime: PhantomData<&'a clap_host>,
309}
310
311impl<'a> HostMainThreadHandle<'a> {
312    /// Gets a thread-safe host handle from this handle.
313    #[inline]
314    pub const fn shared(&self) -> HostSharedHandle<'a> {
315        HostSharedHandle {
316            raw: self.raw,
317            _lifetime: PhantomData,
318        }
319    }
320
321    /// Returns this handle as a reference to a thread-safe host handle from this handle.
322    #[inline]
323    pub const fn as_shared(&self) -> &HostSharedHandle<'a> {
324        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
325        unsafe { &*(self as *const Self as *const HostSharedHandle<'a>) }
326    }
327
328    /// Returns a raw, C FFI-compatible reference to the host handle.
329    #[inline]
330    pub const fn as_raw(&self) -> &'a clap_host {
331        // SAFETY: this type enforces the pointer is valid for 'a
332        unsafe { self.raw.as_ref() }
333    }
334
335    /// Creates a [`HostMainThreadHandle`] from a raw `clap_host` pointer.
336    ///
337    /// # Safety
338    ///
339    ///
340    #[inline]
341    pub unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
342        Self {
343            raw,
344            _lifetime: PhantomData,
345        }
346    }
347
348    /// Returns a [`HostMainThreadHandle`] that points to the same host, but with an arbitrary lifetime
349    /// instead of the host's.
350    ///
351    /// This can be useful in situations where you need to use host callbacks in a container that
352    /// does not let you use proper lifetimes, but you can still guarantee that host callbacks won't
353    /// be called after the host's `'a` lifetime.
354    ///
355    /// # Safety
356    ///
357    /// The returned handle's lifetime is completely meaningless here.
358    /// Proper care muse be taken in order to ensure *no* methods on this type are used beyond the
359    /// original host `'a` lifetime.
360    #[inline]
361    pub unsafe fn with_arbitrary_lifetime<'b>(&self) -> HostMainThreadHandle<'b> {
362        HostMainThreadHandle {
363            raw: self.raw,
364            _lifetime: PhantomData,
365        }
366    }
367}
368
369impl<'a> From<HostMainThreadHandle<'a>> for HostSharedHandle<'a> {
370    #[inline]
371    fn from(h: HostMainThreadHandle<'a>) -> Self {
372        h.shared()
373    }
374}
375
376impl<'a> Deref for HostMainThreadHandle<'a> {
377    type Target = HostSharedHandle<'a>;
378
379    #[inline]
380    fn deref(&self) -> &Self::Target {
381        self.as_shared()
382    }
383}
384
385/// An audio-processor handle to the host.
386///
387/// This can be used to perform requests to the host that can only be made from the audio thread.
388#[repr(transparent)]
389pub struct HostAudioProcessorHandle<'a> {
390    raw: NonNull<clap_host>,
391    _lifetime: PhantomData<&'a clap_host>,
392}
393
394// SAFETY: this type only exposes the audio-thread-safe (Send) operation of clap_host
395unsafe impl Send for HostAudioProcessorHandle<'_> {}
396
397impl<'a> HostAudioProcessorHandle<'a> {
398    /// Gets a thread-safe host handle from this handle.
399    #[inline]
400    pub const fn shared(&self) -> HostSharedHandle<'a> {
401        HostSharedHandle {
402            raw: self.raw,
403            _lifetime: PhantomData,
404        }
405    }
406
407    /// Returns a raw, C FFI-compatible reference to the host handle.
408    #[inline]
409    pub const fn as_raw(&self) -> &'a clap_host {
410        // SAFETY: this type enforces the pointer is valid for 'a
411        unsafe { self.raw.as_ref() }
412    }
413
414    /// Returns this handle as a reference to a thread-safe host handle from this handle.
415    #[inline]
416    pub const fn as_shared(&self) -> &HostSharedHandle<'a> {
417        // SAFETY: this cast is valid since both types are just a NonNull<clap_host> and repr(transparent)
418        unsafe { &*(self as *const Self as *const HostSharedHandle<'a>) }
419    }
420
421    /// Creates a [`HostAudioProcessorHandle`] from a raw `clap_host` pointer.
422    ///
423    /// # Safety
424    ///
425    ///
426    #[inline]
427    pub unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
428        Self {
429            raw,
430            _lifetime: PhantomData,
431        }
432    }
433
434    /// Returns a [`HostAudioProcessorHandle`] that points to the same host, but with an arbitrary lifetime
435    /// instead of the host's.
436    ///
437    /// This can be useful in situations where you need to use host callbacks in a container that
438    /// does not let you use proper lifetimes, but you can still guarantee that host callbacks won't
439    /// be called after the host's `'a` lifetime.
440    ///
441    /// # Safety
442    ///
443    /// The returned handle's lifetime is completely meaningless here.
444    /// Proper care muse be taken in order to ensure *no* methods on this type are used beyond the
445    /// original host `'a` lifetime.
446    #[inline]
447    pub unsafe fn with_arbitrary_lifetime<'b>(&self) -> HostAudioProcessorHandle<'b> {
448        HostAudioProcessorHandle {
449            raw: self.raw,
450            _lifetime: PhantomData,
451        }
452    }
453}
454
455impl<'a> From<HostAudioProcessorHandle<'a>> for HostSharedHandle<'a> {
456    #[inline]
457    fn from(h: HostAudioProcessorHandle<'a>) -> Self {
458        h.shared()
459    }
460}
461
462impl<'a> Deref for HostAudioProcessorHandle<'a> {
463    type Target = HostSharedHandle<'a>;
464
465    #[inline]
466    fn deref(&self) -> &Self::Target {
467        self.as_shared()
468    }
469}
470
471#[inline(never)]
472#[cold]
473const fn mismatched_instance() -> ! {
474    panic!("Given host handle doesn't match the extension pointer it was used on.")
475}