Skip to main content

clack_common/events/io/
implementation.rs

1use crate::events::io::TryPushError;
2use crate::events::spaces::CoreEventSpace;
3use crate::events::{Event, UnknownEvent};
4use crate::utils::{handle_panic, usize_to_clap_size};
5use clap_sys::events::{clap_event_header, clap_input_events, clap_output_events};
6
7/// A trait for all types which can act as an ordered, indexed list of [`UnknownEvent`]s.
8///
9/// This is the backing implementation of an [`InputEvents`](crate::events::io::InputEvents), which
10/// is how input events are shared from the CLAP host to the plugin.
11///
12/// Note that events are indexed using `u32` instead of the standard `usize`, to match the CLAP
13/// specification.
14#[allow(clippy::len_without_is_empty)] // This is not necessary, the trait is intended for FFI
15pub trait InputEventBuffer: Sized {
16    /// Returns the number of events in this list.
17    fn len(&self) -> u32;
18    /// Returns the event at the given `index`.
19    ///
20    /// If `index` is out of bounds, then this must return `None` instead.
21    fn get(&self, index: u32) -> Option<&UnknownEvent>;
22}
23
24/// A trait for all types which can act as an ordered queue for outbound [`UnknownEvent`]s.
25///
26/// This is the backing implementation of an [`OutputEvents`](crate::events::io::OutputEvents), which
27/// is how output events are shared from the CLAP plugin to the host.
28///
29/// Note that events are indexed using `u32` instead of the standard `usize`, to match the CLAP
30/// specification.
31pub trait OutputEventBuffer: Sized {
32    /// Attempts to push a given event to the queue.
33    ///
34    /// # Errors
35    ///
36    /// This may return a [`TryPushError`] if the event couldn't be pushed for any reason (e.g. the
37    /// underlying implementation ran out of buffer space).
38    fn try_push(&mut self, event: &UnknownEvent) -> Result<(), TryPushError>;
39}
40
41pub(crate) const fn raw_input_events<I: InputEventBuffer>(buffer: &I) -> clap_input_events {
42    clap_input_events {
43        ctx: buffer as *const I as *mut I as *mut _,
44        size: Some(size::<I>),
45        get: Some(get::<I>),
46    }
47}
48
49pub(crate) const fn raw_output_events<I: OutputEventBuffer>(buffer: &mut I) -> clap_output_events {
50    clap_output_events {
51        ctx: buffer as *mut _ as *mut _,
52        try_push: Some(try_push::<I>),
53    }
54}
55
56pub(crate) const fn void_output_events() -> clap_output_events {
57    clap_output_events {
58        ctx: core::ptr::null_mut(),
59        try_push: Some(void_push),
60    }
61}
62
63/// # Safety
64///
65/// The caller must guarantee that:
66///
67/// * `input_events` is valid for reads and points to a valid clap_input_events instance;
68/// * The `ctx` pointer it contains points to a value of type `I` and is created from a shared reference (`&`) to it.
69#[inline]
70unsafe fn get_input_buffer<'a, I: InputEventBuffer>(
71    input_events: *const clap_input_events,
72) -> &'a I {
73    // SAFETY: The caller must guarantee the given input_events points to a valid clap_input_events instance and must be valid for reads
74    let ctx = unsafe { (*input_events).ctx };
75    let buf_impl: *mut I = ctx.cast();
76    // SAFETY: The caller must guarantee the ctx pointer is of type I and valid for 'a
77    unsafe { &*buf_impl }
78}
79
80#[allow(clippy::missing_safety_doc)]
81unsafe extern "C" fn size<I: InputEventBuffer>(list: *const clap_input_events) -> u32 {
82    handle_panic(|| {
83        // SAFETY: We only use this function in instances that we created ourselves from an instance of `I`.
84        let buf = unsafe { get_input_buffer(list) };
85        I::len(buf)
86    })
87    .unwrap_or(0)
88}
89
90#[allow(clippy::missing_safety_doc)]
91unsafe extern "C" fn get<I: InputEventBuffer>(
92    list: *const clap_input_events,
93    index: u32,
94) -> *const clap_event_header {
95    handle_panic(|| {
96        // SAFETY: We only use this function in instances that we created ourselves from an instance of `I`.
97        let buf = unsafe { get_input_buffer(list) };
98        I::get(buf, index)
99            .map(|e| e.as_raw() as *const _)
100            .unwrap_or_else(core::ptr::null)
101    })
102    .unwrap_or(core::ptr::null())
103}
104
105/// # Safety
106///
107/// The caller must guarantee that:
108///
109/// * `output_events` is valid for reads and points to a valid clap_input_events instance;
110/// * The `ctx` pointer it contains points to a value of type `I` and is created from an exclusive reference (`&mut`) to it.
111#[inline]
112unsafe fn get_output_buffer<'a, O: OutputEventBuffer>(
113    output_events: *const clap_output_events,
114) -> &'a mut O {
115    // SAFETY: The caller must guarantee the given output_events points to a valid clap_output_events instance and must be valid for reads
116    let ctx = unsafe { (*output_events).ctx };
117    let buf_impl: *mut O = ctx.cast();
118    // SAFETY: The caller must guarantee the ctx pointer is of type I and valid for 'a
119    unsafe { &mut *buf_impl }
120}
121
122#[allow(clippy::missing_safety_doc)]
123unsafe extern "C" fn try_push<O: OutputEventBuffer>(
124    list: *const clap_output_events,
125    event: *const clap_event_header,
126) -> bool {
127    handle_panic(|| {
128        // SAFETY: We only use this function in instances that we created ourselves from an instance of `O`.
129        let buf = unsafe { get_output_buffer(list) };
130        // SAFETY: event is guaranteed to be valid by the CLAP spec
131        let event = unsafe { UnknownEvent::from_raw(event) };
132
133        O::try_push(buf, event).is_ok()
134    })
135    .unwrap_or(false)
136}
137
138#[allow(clippy::missing_safety_doc)]
139unsafe extern "C" fn void_push(
140    _list: *const clap_output_events,
141    _event: *const clap_event_header,
142) -> bool {
143    true
144}
145
146impl InputEventBuffer for () {
147    #[inline]
148    fn len(&self) -> u32 {
149        0
150    }
151
152    #[inline]
153    fn get(&self, _index: u32) -> Option<&UnknownEvent> {
154        None
155    }
156}
157
158impl<T: Event> InputEventBuffer for T {
159    #[inline]
160    fn len(&self) -> u32 {
161        1
162    }
163
164    #[inline]
165    fn get(&self, index: u32) -> Option<&UnknownEvent> {
166        match index {
167            0 => Some(self.as_unknown()),
168            _ => None,
169        }
170    }
171}
172
173impl<T: InputEventBuffer, U: InputEventBuffer> InputEventBuffer for (&T, &U) {
174    #[inline]
175    fn len(&self) -> u32 {
176        self.0.len() + self.1.len()
177    }
178
179    #[inline]
180    fn get(&self, index: u32) -> Option<&UnknownEvent> {
181        let first_len = self.0.len();
182        if index < first_len {
183            self.0.get(index)
184        } else {
185            // No underflow possible: we checked if index was >= first_len above
186            self.1.get(index - first_len)
187        }
188    }
189}
190
191impl<T: Event, const N: usize> InputEventBuffer for [T; N] {
192    #[inline]
193    fn len(&self) -> u32 {
194        const { usize_to_clap_size(N) }
195    }
196
197    #[inline]
198    fn get(&self, index: u32) -> Option<&UnknownEvent> {
199        self.as_slice().get(index as usize).map(|e| e.as_unknown())
200    }
201}
202
203impl<T: Event> InputEventBuffer for &[T] {
204    #[inline]
205    fn len(&self) -> u32 {
206        let len = <[T]>::len(self);
207        usize_to_clap_size(len)
208    }
209
210    #[inline]
211    fn get(&self, index: u32) -> Option<&UnknownEvent> {
212        <[T]>::get(self, index as usize).map(|e| e.as_unknown())
213    }
214}
215
216impl<T: Event> InputEventBuffer for Vec<T> {
217    #[inline]
218    fn len(&self) -> u32 {
219        let len = <[T]>::len(self);
220        usize_to_clap_size(len)
221    }
222
223    #[inline]
224    fn get(&self, index: u32) -> Option<&UnknownEvent> {
225        <[T]>::get(self, index as usize).map(|e| e.as_unknown())
226    }
227}
228
229impl InputEventBuffer for &UnknownEvent {
230    #[inline]
231    fn len(&self) -> u32 {
232        1
233    }
234
235    #[inline]
236    fn get(&self, index: u32) -> Option<&UnknownEvent> {
237        match index {
238            0 => Some(self),
239            _ => None,
240        }
241    }
242}
243
244impl<const N: usize> InputEventBuffer for [&UnknownEvent; N] {
245    #[inline]
246    fn len(&self) -> u32 {
247        const { usize_to_clap_size(N) }
248    }
249
250    #[inline]
251    fn get(&self, index: u32) -> Option<&UnknownEvent> {
252        self.as_slice().get(index as usize).copied()
253    }
254}
255
256impl InputEventBuffer for &[&UnknownEvent] {
257    #[inline]
258    fn len(&self) -> u32 {
259        let len = <[&UnknownEvent]>::len(self);
260        usize_to_clap_size(len)
261    }
262
263    #[inline]
264    fn get(&self, index: u32) -> Option<&UnknownEvent> {
265        <[&UnknownEvent]>::get(self, index as usize).copied()
266    }
267}
268
269impl InputEventBuffer for Vec<&UnknownEvent> {
270    #[inline]
271    fn len(&self) -> u32 {
272        let len = <[&UnknownEvent]>::len(self);
273        usize_to_clap_size(len)
274    }
275
276    #[inline]
277    fn get(&self, index: u32) -> Option<&UnknownEvent> {
278        <[&UnknownEvent]>::get(self, index as usize).copied()
279    }
280}
281
282impl<T: InputEventBuffer> InputEventBuffer for Option<T> {
283    #[inline]
284    fn len(&self) -> u32 {
285        match self {
286            Some(b) => b.len(),
287            None => 0,
288        }
289    }
290
291    #[inline]
292    fn get(&self, index: u32) -> Option<&UnknownEvent> {
293        match self {
294            None => None,
295            Some(b) => b.get(index),
296        }
297    }
298}
299
300impl<'a, T: Event<EventSpace<'a> = CoreEventSpace<'a>> + Clone> OutputEventBuffer for Option<T> {
301    fn try_push(&mut self, event: &UnknownEvent) -> Result<(), TryPushError> {
302        if self.is_some() {
303            return Err(TryPushError);
304        };
305
306        if let Some(event) = event.as_event::<T>() {
307            *self = Some(event.clone());
308            Ok(())
309        } else {
310            Err(TryPushError)
311        }
312    }
313}
314
315impl<'a, T: Event<EventSpace<'a> = CoreEventSpace<'a>> + Clone> OutputEventBuffer for Vec<T> {
316    fn try_push(&mut self, event: &UnknownEvent) -> Result<(), TryPushError> {
317        if let Some(event) = event.as_event::<T>() {
318            self.push(event.clone());
319            Ok(())
320        } else {
321            Err(TryPushError)
322        }
323    }
324}