Skip to main content

clack_common/
utils.rs

1//! Various CLAP-related utilities.
2
3#[cfg(not(test))]
4#[allow(unused)]
5pub(crate) use std::panic::catch_unwind as handle_panic;
6
7#[cfg(test)]
8#[inline]
9#[allow(unused)]
10pub(crate) fn handle_panic<F: FnOnce() -> R, R>(f: F) -> std::thread::Result<R> {
11    Ok(f())
12}
13
14mod fixed_point;
15mod id;
16mod timestamp;
17mod universal_plugin_id;
18mod version;
19
20pub use fixed_point::*;
21pub use id::ClapId;
22pub use timestamp::Timestamp;
23pub use universal_plugin_id::{UniversalPluginAbi, UniversalPluginId};
24pub use version::ClapVersion;
25
26/// A color, in the ARGB format.
27pub type Color = clap_color;
28
29/// The transparent color. It is also fully black.
30pub const TRANSPARENT_COLOR: Color = Color {
31    alpha: 0,
32    red: 0,
33    green: 0,
34    blue: 0,
35};
36
37use clap_sys::color::clap_color;
38use std::ffi::c_void;
39
40/// An opaque pointer for use in e.g. parameter definitions and parameter-related events.
41#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
42pub struct Cookie(*mut c_void);
43
44impl Cookie {
45    /// Creates a default "empty" cookie, i.e. a Cookie with a `null` pointer.
46    #[inline]
47    pub const fn empty() -> Self {
48        Self(core::ptr::null_mut())
49    }
50
51    /// Creates a [`Cookie`] from the given pointer.
52    #[inline]
53    pub const fn from_raw(ptr: *mut c_void) -> Self {
54        Self(ptr)
55    }
56
57    /// Returns the pointer value contains in this [`Cookie`].
58    #[inline]
59    pub const fn as_raw(&self) -> *mut c_void {
60        self.0
61    }
62}
63
64/// Creates a default "empty" cookie, i.e. a Cookie with a `null` pointer.
65///
66/// This is the same as using [`Cookie::empty`].
67impl Default for Cookie {
68    #[inline]
69    fn default() -> Self {
70        Self::empty()
71    }
72}
73
74// SAFETY: Cookies themselves are just pointers, which plugins have to consider as Send + Sync
75unsafe impl Send for Cookie {}
76// SAFETY: Cookies themselves are just pointers, which plugins have to consider as Send + Sync
77unsafe impl Sync for Cookie {}
78
79/// A safer form of [`core::slice::from_raw_parts`] that returns a properly aligned slice in case
80/// the length is 0.
81///
82/// In C it is common for empty slices to be represented using a null pointer, but this is UB in
83/// Rust, as all references must be aligned and non-null.
84///
85/// This helper avoids that pitfall by ignoring the pointer if the length is zero.
86///
87/// # Safety
88///
89/// Same as [`core::slice::from_raw_parts`], except the provided pointer *can* be null or
90/// dangling for zero-length slices.
91#[inline]
92pub(crate) const unsafe fn slice_from_external_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
93    if len == 0 {
94        return &[];
95    }
96
97    core::slice::from_raw_parts(data, len)
98}
99
100/// Same as [`slice_from_external_parts`] but for mut slices.
101///
102/// # Safety
103///
104/// Same as [`core::slice::from_raw_parts_mut`], except the provided pointer *can* be null or
105/// dangling for zero-length slices.
106#[inline]
107pub(crate) const unsafe fn slice_from_external_parts_mut<'a, T>(
108    data: *mut T,
109    len: usize,
110) -> &'a mut [T] {
111    if len == 0 {
112        return &mut [];
113    }
114
115    core::slice::from_raw_parts_mut(data, len)
116}
117
118#[inline]
119pub(crate) const fn check_clap_size_overflow(value: usize) {
120    #[cold]
121    #[inline(never)]
122    const fn too_big() -> ! {
123        panic!("CLAP size (u32) overflowed")
124    }
125
126    if value > u32::MAX as usize {
127        too_big()
128    }
129}
130
131#[inline]
132pub(crate) const fn usize_to_clap_size(value: usize) -> u32 {
133    check_clap_size_overflow(value);
134
135    #[allow(clippy::cast_possible_truncation)] // We just checked above, it cannot truncate
136    {
137        value as u32
138    }
139}