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}