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}