Skip to main content

clack_common/extensions/
raw.rs

1use crate::extensions::{ExtensionSide, HostExtensionSide, PluginExtensionSide};
2use clap_sys::host::clap_host;
3use clap_sys::plugin::clap_plugin;
4use std::ffi::c_void;
5use std::fmt::{Debug, Formatter};
6use std::marker::PhantomData;
7use std::ptr::NonNull;
8
9/// A raw extension pointer.
10///
11/// This type is used by extension implementations to abstract away most of the safety concerns of
12/// using extension pointers.
13///
14/// Using the `S` type parameter with either [`PluginExtensionSide`] or [`HostExtensionSide`], this
15/// can be used as either a plugin-side extension or a host-side extension, respectively.
16///
17/// The `T` type parameter is the extension struct this points to (e.g. `clap_plugin_state`), or
18/// `()` if the extension pointer is untyped.
19///
20/// Internally, this holds two pointers: a pointer to the actual extension struct, and a pointer
21/// to the matching `clap_plugin` or `clap_host`. These are compared on each use to make sure
22/// that the right extensions are always called with the right instance.
23///
24/// This type does not directly track the lifetimes of its pointers at all, they may become dangling
25/// at any time. However, it is part of the safety contract of this type that the extension pointer
26/// *MUST* be valid as long as the matching `clap_plugin` or `clap_host` still is, as per the CLAP
27/// specification.
28///
29/// This property is then extrapolated so that if any valid `clap_plugin` or `clap_host` reference,
30/// that also matches the pointer stored in this type, is encountered, then it must mean that the
31/// inner extension pointer is also valid, and can be safely de-referenced.
32///
33/// To safely get valid references to the extension struct out of this type, you have to use the
34/// `use_extension()` method on one of the handle types:
35///
36/// * For plugin-side extensions (from the `clack-host` crate): `PluginSharedHandle`,
37///   `PluginMainThreadHandle`, or `PluginAudioProcessorHandle`;
38/// * For host-side extensions (from the `clack-plugin` crate): `HostSharedHandle`,
39///   `HostMainThreadHandle`, or `HostAudioProcessorHandle`.
40///
41/// This pointer type is only useful for *consuming* extension pointers. For producing extension
42/// pointers from an extension implementation, use the [`RawExtensionImplementation`] type instead.  
43#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
44pub struct RawExtension<S: ExtensionSide, T = ()> {
45    extension_ptr: NonNull<T>,
46    host_or_plugin_ptr: NonNull<c_void>, // Can be either clap_host or clap_plugin
47    _side: PhantomData<fn() -> S>,
48}
49
50// SAFETY: this is just a couple of pointers, and the type doesn't care being used on any thread.
51// Thread-safety is enforced by the plugin handle type that is passed to the methods.
52unsafe impl<S: ExtensionSide, T> Send for RawExtension<S, T> {}
53// SAFETY: same as above.
54unsafe impl<S: ExtensionSide, T> Sync for RawExtension<S, T> {}
55
56impl<S: ExtensionSide, T> RawExtension<S, T> {
57    /// Returns the raw pointer to the extension struct.
58    ///
59    /// This pointer may be dangling at any time.
60    ///
61    /// See the [`RawExtension`] type documentation for more information on how to get a valid
62    /// reference to the extension struct instead.
63    #[inline]
64    pub const fn as_ptr(&self) -> NonNull<T> {
65        self.extension_ptr
66    }
67}
68
69impl<S: ExtensionSide> RawExtension<S, ()> {
70    /// Casts this raw extension pointer into an extension pointer of a given type.
71    ///
72    /// # Safety
73    ///
74    /// Users *must* ensure that `T` matches the actual type behind the pointer.
75    pub const unsafe fn cast<T>(&self) -> RawExtension<S, T> {
76        RawExtension {
77            extension_ptr: self.extension_ptr.cast(),
78            host_or_plugin_ptr: self.host_or_plugin_ptr,
79            _side: PhantomData,
80        }
81    }
82}
83
84impl<T> RawExtension<PluginExtensionSide, T> {
85    /// Creates a raw plugin-side extension pointer from a pointer to the extension data, and a
86    /// pointer to the plugin instance.
87    ///
88    /// # Safety
89    ///
90    /// The user *must* ensure the `extension_ptr` is and remains valid for the lifetime of the
91    /// plugin instance.
92    /// This is the case for pointers received from the raw `clap_plugin.get_extension` method.
93    ///
94    /// The given `plugin_ptr` however doesn't have to be valid, and may be dangling.
95    pub const unsafe fn from_raw_plugin_extension(
96        extension_ptr: NonNull<T>,
97        plugin_ptr: NonNull<clap_plugin>,
98    ) -> Self {
99        Self {
100            extension_ptr,
101            host_or_plugin_ptr: plugin_ptr.cast(),
102            _side: PhantomData,
103        }
104    }
105
106    /// Returns the raw pointer to the plugin instance the extension originated from.
107    ///
108    /// This pointer may be dangling at any time, and is not meant to be de-referenced, only
109    /// compared to.
110    /// See the [`RawExtension`] type documentation for more information.
111    pub const fn plugin_ptr(&self) -> NonNull<clap_plugin> {
112        self.host_or_plugin_ptr.cast()
113    }
114}
115
116impl<T> RawExtension<HostExtensionSide, T> {
117    /// Creates a raw host-side extension pointer from a pointer to the extension data, and a
118    /// pointer to the plugin instance.
119    ///
120    /// # Safety
121    ///
122    /// The user *must* ensure the `extension_ptr` is and remains valid for the lifetime of the
123    /// plugin instance.
124    /// This is the case for pointers received from the raw `clap_host.get_extension` method.
125    ///
126    /// The given `host_ptr` however doesn't have to be valid, and may be dangling.
127    pub const unsafe fn from_raw_host_extension(
128        extension_ptr: NonNull<T>,
129        host_ptr: NonNull<clap_host>,
130    ) -> Self {
131        Self {
132            extension_ptr,
133            host_or_plugin_ptr: host_ptr.cast(),
134            _side: PhantomData,
135        }
136    }
137
138    /// Returns the raw pointer to the host instance the extension originated from.
139    ///
140    /// This pointer may be dangling at any time, and is not meant to be de-referenced, only
141    /// compared to.
142    /// See the [`RawExtension`] type documentation for more information.
143    pub const fn host_ptr(&self) -> NonNull<clap_host> {
144        self.host_or_plugin_ptr.cast()
145    }
146}
147
148/// A pointer to an extension's implementation struct.
149///
150/// This type is used to type-erase a reference to the implementation struct of an extension before
151/// transferring it to the consumer through `get_extension`.
152///
153/// This type is also used to enforce the extension pointer is always valid, as extension
154/// implementations produced from Clack always come from statics and therefore always have the
155/// `'static` lifetime.
156///
157/// Note this is *not* the case for all CLAP plugins: extension pointers are only guaranteed to be
158/// valid for the lifetime of the instance (plugin or host) they originate from.
159///
160/// Use the [`RawExtension`] type to properly use and track the lifetime of extension pointers on
161/// the consumer-side.
162#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
163pub struct RawExtensionImplementation {
164    inner: NonNull<c_void>,
165}
166
167impl RawExtensionImplementation {
168    /// Creates a new pointer from a `'static` reference to an implementation struct.
169    pub const fn new<I>(implementation: &'static I) -> Self {
170        Self {
171            // SAFETY: pointer comes from a reference, so it's guaranteed to always be valid.
172            inner: unsafe { NonNull::new_unchecked(implementation as *const _ as *mut _) },
173        }
174    }
175
176    /// Returns the raw pointer to the extension implementation struct.
177    ///
178    /// This pointer is always valid and never dangling, as it originates from a `'static`
179    /// reference.
180    pub const fn as_ptr(&self) -> NonNull<c_void> {
181        self.inner
182    }
183}
184
185impl Debug for RawExtensionImplementation {
186    #[inline]
187    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
188        write!(f, "RawExtensionImplementation({:p})", self.inner)
189    }
190}