Skip to main content

clack_common/events/io/
output.rs

1use crate::events::UnknownEvent;
2use crate::events::io::implementation::{OutputEventBuffer, raw_output_events};
3use crate::events::io::void_output_events;
4use clap_sys::events::clap_output_events;
5use std::error::Error;
6use std::fmt::{Display, Formatter};
7use std::marker::PhantomData;
8
9/// An ordered list of timestamped events.
10///
11/// `OutputEvents`s are always ordered: an event at index `i` will always have a timestamp smaller than
12/// or equal to the timestamp of the next event at index `i + 1`.
13///
14/// `OutputEvents`s do not own the event data, they are only lightweight wrappers around a compatible
15/// event buffer (i.e. [`OutputEventBuffer`]), see [`OutputEvents::from_buffer`].
16///
17/// Unlike [`Vec`s](Vec) or slices, `OutputEvents`s only support appending a new event to
18/// the list ([`try_push`](OutputEvents::try_push)).
19///
20/// This type also implements a few extra features based on these operations for convenience,
21/// such as the [`Extend`](Extend) trait.
22///
23/// # Example
24///```
25/// use clack_common::events::{Event, EventHeader, Pckn};
26/// use clack_common::events::event_types::NoteOnEvent;
27/// use clack_common::events::io::{EventBuffer, OutputEvents};
28///
29/// let mut buf = EventBuffer::new();
30/// let mut output_events = OutputEvents::from_buffer(&mut buf);
31///
32/// let event = NoteOnEvent::new(0, Pckn::new(0u16, 0u16, 12u16, 60u32), 4.2);
33/// output_events.try_push(event.as_unknown()).unwrap();
34///
35/// assert_eq!(1, buf.len());
36/// ```
37#[repr(C)]
38pub struct OutputEvents<'a> {
39    inner: clap_output_events,
40    _lifetime: PhantomData<(&'a clap_output_events, *const ())>,
41}
42
43impl<'a> OutputEvents<'a> {
44    /// Creates a mutable reference to an OutputEvents list from a given C FFI-compatible pointer.
45    ///
46    /// # Safety
47    /// The caller must ensure the given pointer is valid for the lifetime `'a`.
48    #[inline]
49    pub const unsafe fn from_raw_mut(raw: &mut clap_output_events) -> &'a mut Self {
50        // SAFETY: OutputEvents list has the same layout and is repr(C)
51        &mut *(raw as *mut _ as *mut _)
52    }
53
54    /// Returns a reference to a C FFI-compatible representation of this event list.
55    #[inline]
56    pub const fn as_raw(&mut self) -> &clap_output_events {
57        // SAFETY: OutputEvents list has the same layout and is repr(C)
58        unsafe { &*(self as *const _ as *const _) }
59    }
60
61    /// Returns a C FFI-compatible mutable pointer to this event list.
62    ///
63    /// # Safety
64    ///
65    /// This method allows mutating the list's inner fields.
66    /// Modifying those fields may trigger Undefined Behavior.
67    #[inline]
68    pub const unsafe fn as_raw_mut(&mut self) -> &mut clap_output_events {
69        // SAFETY: OutputEvents list has the same layout and is repr(C)
70        unsafe { &mut *(self as *mut _ as *mut _) }
71    }
72
73    /// Create a new event list by wrapping an event buffer implementation.
74    ///
75    /// This buffer may have been used by a previous `OutputEvents`, and will keep all events that
76    /// have been [`push`ed](OutputEvents::try_push) into it. This allows to reuse event buffers
77    /// between process trips.
78    ///
79    /// # Realtime Safety
80    ///
81    /// This is a very cheap, realtime-safe operation that does not change the given buffer in any
82    /// way. However, since users of the `OutputEvents` may call `append` on it, the buffer should have
83    /// a reasonable amount of storage pre-allocated, as to not have to perform additional
84    /// allocations on the audio thread.
85    ///
86    /// # Example
87    /// ```
88    /// use clack_common::events::io::{EventBuffer, OutputEvents};
89    ///
90    /// // Allocate the buffer on the main thread
91    /// let mut buf = EventBuffer::new();
92    ///
93    /// // Later, on the DSP thread
94    /// let output_events = OutputEvents::from_buffer(&mut buf);
95    /// ```
96    #[inline]
97    pub const fn from_buffer<O: OutputEventBuffer>(buffer: &'a mut O) -> Self {
98        Self {
99            inner: raw_output_events(buffer),
100            _lifetime: PhantomData,
101        }
102    }
103
104    /// Creates a void "list" which ignores every event that is pushed to it.
105    ///
106    /// This can be useful if you do not intend to support output events at all.
107    #[inline]
108    pub const fn void() -> Self {
109        Self {
110            inner: void_output_events(),
111            _lifetime: PhantomData,
112        }
113    }
114
115    /// Appends a copy of the given event to the list.
116    ///
117    /// Note that the event is not guaranteed to be added at the end of the list: in order to
118    /// efficiently preserve ordering, some implementations may choose to insert it in a position
119    /// following all events with smaller timestamps, and preceding all events with greater
120    /// timestamps.
121    ///
122    /// For best performance however, it is recommended to insert the events in order if possible.
123    ///
124    /// # Errors
125    ///
126    /// This method will return a [`TryPushError`] if the event could not be pushed to the list.
127    ///
128    /// The exact reason is left at the implementer's discretion, but this is usually a sign that
129    /// the implementer ran out of buffer space, and either cannot or refuses to allocate more.
130    ///
131    /// # Realtime Safety
132    ///
133    /// This operation may cause the underlying event buffer to be reallocated by the host, therefore
134    /// realtime safety cannot be guaranteed. However, it is expected for hosts to pre-allocate a
135    /// reasonable amount of space before forwarding the list to the plugin, in order to make
136    /// allocations as unlikely as possible.
137    #[inline]
138    pub fn try_push<E: AsRef<UnknownEvent>>(&mut self, event: E) -> Result<(), TryPushError> {
139        let try_push = self.inner.try_push.ok_or(TryPushError)?;
140
141        // SAFETY: this function pointer is safely initialized by from_raw or from_buffer
142        if !unsafe { try_push(&self.inner, event.as_ref().as_raw()) } {
143            Err(TryPushError {})
144        } else {
145            Ok(())
146        }
147    }
148}
149
150/// An error that may occur when [`OutputEvents::try_push`] couldn't complete.
151///
152/// See the documentation of [`OutputEvents::try_push`] for more information.
153#[non_exhaustive]
154#[derive(Debug, Default, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
155pub struct TryPushError;
156
157impl TryPushError {
158    /// Creates a new [`TryPushError`].
159    #[inline]
160    pub const fn new() -> Self {
161        Self {}
162    }
163}
164
165impl Display for TryPushError {
166    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
167        f.write_str("Failed to push event into output event buffer")
168    }
169}
170
171impl Error for TryPushError {}
172
173impl<'a, I: OutputEventBuffer> From<&'a mut I> for OutputEvents<'a> {
174    #[inline]
175    fn from(implementation: &'a mut I) -> Self {
176        Self::from_buffer(implementation)
177    }
178}
179
180impl OutputEventBuffer for OutputEvents<'_> {
181    #[inline]
182    fn try_push(&mut self, event: &UnknownEvent) -> Result<(), TryPushError> {
183        OutputEvents::try_push(self, event)
184    }
185}
186
187impl<'a: 'b, 'b> Extend<&'b UnknownEvent> for OutputEvents<'a> {
188    #[inline]
189    fn extend<T: IntoIterator<Item = &'b UnknownEvent>>(&mut self, iter: T) {
190        #[allow(unused_must_use)]
191        for event in iter {
192            self.try_push(event);
193        }
194    }
195}
196
197#[cfg(test)]
198mod test {
199    extern crate static_assertions as sa;
200    use super::*;
201
202    sa::assert_not_impl_any!(OutputEvents<'static>: Send, Sync);
203}