clack_common/events/header.rs
1use crate::events::Event;
2use crate::events::spaces::{CoreEventSpace, EventSpaceId};
3use crate::utils::usize_to_clap_size;
4use bitflags::bitflags;
5use clap_sys::events::clap_event_header;
6use clap_sys::events::{CLAP_EVENT_DONT_RECORD, CLAP_EVENT_IS_LIVE};
7use std::cmp::Ordering;
8use std::fmt;
9use std::marker::PhantomData;
10
11/// The common metadata header of all CLAP events.
12///
13/// All CLAP events have a common header that contains various metadata about them.
14///
15/// Most of that metadata is information used to discover the event's type: [`type_id`],
16/// [`space_id`] and [`size`]. This is used internally by the [`UnknownEvent`] type to perform
17/// downcasting to concrete types.
18///
19/// All events also carry a sample-accurate timestamp (accessible through [`time`]), as well as
20/// some additional [event flags] (through [`flags`]).
21///
22/// Because event headers internally contain type information for the event, the [`EventHeader`]
23/// is generic over a specific event type parameter `E` in order to guarantee that [`type_id`],
24/// [`space_id`] and [`size`] are coherent with the event's type.
25///
26/// The generic parameter `E` can either be a concrete [`Event`] type (as returned by the
27/// [`Event::header`] method), or `()` for headers of an undetermined event type (as returned by the
28/// [`UnknownEvent::header`] method).
29///
30/// [`type_id`]: EventHeader::type_id
31/// [`space_id`]: EventHeader::space_id
32/// [`size`]: EventHeader::size
33/// [`time`]: EventHeader::time
34/// [`flags`]: EventHeader::flags
35/// [`UnknownEvent`]: super::UnknownEvent
36/// [`UnknownEvent::header`]: super::UnknownEvent::header
37/// [event flags]: EventFlags
38#[repr(C)]
39#[derive(Copy, Clone)]
40pub struct EventHeader<E = ()> {
41 inner: clap_event_header,
42 _event: PhantomData<E>,
43}
44
45impl<E> EventHeader<E> {
46 /// Returns the size of this event, in bytes.
47 ///
48 /// This size includes the size of the event header itself.
49 /// If you need only the size of the payload, see [`payload_size`](Self::payload_size).
50 #[inline]
51 pub const fn size(&self) -> u32 {
52 self.inner.size
53 }
54
55 /// Returns the size of this event's payload, in bytes.
56 ///
57 /// This size does not include the size of the event header itself.
58 /// If you need to also account for the size of the payload, see [`size`](Self::size).
59 #[inline]
60 pub const fn payload_size(&self) -> u32 {
61 const HEADER_SIZE: u32 = const { usize_to_clap_size(size_of::<EventHeader>()) };
62
63 self.inner.size.saturating_sub(HEADER_SIZE)
64 }
65
66 /// The raw event type ID.
67 #[inline]
68 pub const fn type_id(&self) -> u16 {
69 self.inner.type_
70 }
71
72 /// The timestamp at which this event occurs, in samples.
73 ///
74 /// This timestamp is relative to the frame count of the current `process` invocation.
75 #[inline]
76 pub const fn time(&self) -> u32 {
77 self.inner.time
78 }
79
80 /// Sets the timestamp at which this event occurs, in samples.
81 ///
82 /// This timestamp is relative to the frame count of the current `process` invocation.
83 #[inline]
84 pub const fn set_time(&mut self, time: u32) {
85 self.inner.time = time
86 }
87
88 /// Sets the timestamp at which this event occurs, in samples.
89 ///
90 /// This timestamp is relative to the frame count of the current `process` invocation.
91 ///
92 /// This method takes and returns ownership of the event header, allowing it to be used in a
93 /// builder-style pattern.
94 #[inline]
95 pub const fn with_time(mut self, time: u32) -> Self {
96 self.inner.time = time;
97 self
98 }
99
100 /// The event's [flags](EventFlags).
101 #[inline]
102 pub const fn flags(&self) -> EventFlags {
103 EventFlags::from_bits_truncate(self.inner.flags)
104 }
105
106 /// Sets the event's [flags](EventFlags).
107 #[inline]
108 pub const fn set_flags(&mut self, flags: EventFlags) {
109 self.inner.flags = flags.bits();
110 }
111
112 /// Sets the event's [flags](EventFlags).
113 ///
114 /// This method takes and returns ownership of the event header, allowing it to be used in a
115 /// builder-style pattern.
116 #[inline]
117 pub const fn with_flags(mut self, flags: EventFlags) -> Self {
118 self.inner.flags = flags.bits();
119 self
120 }
121
122 // Raw stuff
123
124 /// Gets a shared reference typed event header from a mutable shared to a raw,
125 /// C-FFI compatible header struct, without performing any checks.
126 ///
127 /// # Safety
128 ///
129 /// The caller *must* ensure the given header matches the given event type `E`.
130 #[inline]
131 pub const unsafe fn from_raw_unchecked(header: &clap_event_header) -> &Self {
132 // SAFETY: EventHeader is repr(C) and ABI compatible
133 &*(header as *const clap_event_header as *const Self)
134 }
135
136 /// Gets a mutable reference typed event header from a mutable reference to a raw,
137 /// C-FFI compatible header struct, without performing any checks.
138 ///
139 /// # Safety
140 ///
141 /// The caller *must* ensure the given header matches the given event type `E`.
142 #[inline]
143 pub const unsafe fn from_raw_unchecked_mut(header: &mut clap_event_header) -> &mut Self {
144 // SAFETY: EventHeader is repr(C) and ABI compatible
145 &mut *(header as *mut clap_event_header as *mut Self)
146 }
147
148 /// Returns this header as a shared reference to a raw, C-FFI compatible header struct.
149 #[inline]
150 pub const fn as_raw(&self) -> &clap_event_header {
151 &self.inner
152 }
153
154 /// Returns this header as a mutable reference to a raw, C-FFI compatible header struct.
155 ///
156 /// # Safety
157 ///
158 /// This method allows mutating the event header's fields, most notably `type_`, `size` and
159 /// `space_id`.
160 ///
161 /// Modifying those fields may trigger Undefined Behavior, as it can make other readers of this
162 /// event treat it as a type or size that it is actually not.
163 #[inline]
164 pub const unsafe fn as_raw_mut(&mut self) -> &mut clap_event_header {
165 &mut self.inner
166 }
167
168 /// Returns this header as a raw, C-FFI compatible header struct.
169 #[inline]
170 pub const fn into_raw(self) -> clap_event_header {
171 self.inner
172 }
173}
174
175impl EventHeader<()> {
176 /// Gets an untyped event header from a raw header.
177 #[inline]
178 pub const fn from_raw(header: &clap_event_header) -> &Self {
179 // SAFETY: This EventHeader's type is (), i.e. untyped.
180 unsafe { Self::from_raw_unchecked(header) }
181 }
182
183 /// The untyped event space ID, from this untyped event header.
184 #[inline]
185 pub const fn space_id(&self) -> Option<EventSpaceId> {
186 EventSpaceId::new(self.inner.space_id)
187 }
188}
189
190impl<E: Event> EventHeader<E> {
191 /// Creates a new header for a specific core event type, containing the given `time` and `flags`.
192 ///
193 /// The [`type_id`](Self::type_id), [`space_id`](Self::space_id) and [`size`](Self::size)
194 /// members are derived from the `E` type parameter.
195 ///
196 /// See the [`event_types`](super::event_types) module for a list of all the supported core
197 /// event types.
198 #[inline]
199 pub const fn new_core(time: u32, flags: EventFlags) -> Self
200 where
201 E: for<'a> Event<EventSpace<'a> = CoreEventSpace<'a>>,
202 {
203 Self::new_for_space(EventSpaceId::core(), time, flags)
204 }
205
206 /// Creates a new header for a specific event type, of a given custom event space,
207 /// containing the given `time` and `flags`.
208 ///
209 /// The [`type_id`](Self::type_id) and [`size`](Self::size) members are derived from the `E`
210 /// type parameter.
211 #[inline]
212 pub const fn new_for_space(
213 space_id: EventSpaceId<E::EventSpace<'_>>,
214 time: u32,
215 flags: EventFlags,
216 ) -> Self {
217 Self {
218 inner: clap_event_header {
219 size: const { usize_to_clap_size(size_of::<E>()) },
220 time,
221 space_id: space_id.id(),
222 type_: E::TYPE_ID,
223 flags: flags.bits(),
224 },
225 _event: PhantomData,
226 }
227 }
228
229 /// The typed event space ID from this event header.
230 #[inline]
231 pub const fn space_id(&self) -> EventSpaceId<E::EventSpace<'static>> {
232 // SAFETY: the EventHeader type guarantees the space_id correctness
233 unsafe { EventSpaceId::new_unchecked(self.inner.space_id) }
234 }
235}
236
237impl<E: for<'a> Event<EventSpace<'a> = CoreEventSpace<'a>>> Default for EventHeader<E> {
238 #[inline]
239 fn default() -> Self {
240 Self::new_core(0, EventFlags::empty())
241 }
242}
243
244bitflags! {
245 /// Flags for a CLAP event.
246 #[repr(C)]
247 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
248 pub struct EventFlags: u32 {
249 /// Indicates a live user event, for example a user turning a physical
250 /// knob or playing a physical key.
251 const IS_LIVE = CLAP_EVENT_IS_LIVE;
252
253 /// Indicates that the event should not be recorded.
254 ///
255 /// For example this is useful when a parameter changes because of a
256 /// MIDI CC, because if the host records both the MIDI CC automation and
257 /// the parameter automation there will be a conflict.
258 const DONT_RECORD = CLAP_EVENT_DONT_RECORD;
259 }
260}
261
262impl<E> PartialEq for EventHeader<E> {
263 #[inline]
264 fn eq(&self, other: &Self) -> bool {
265 self.inner.time == other.inner.time
266 }
267}
268
269impl<E> Eq for EventHeader<E> {}
270
271impl<E> fmt::Debug for EventHeader<E> {
272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273 f.debug_struct("EventHeader")
274 .field("time", &self.time())
275 .field("flags", &self.flags())
276 .field("type_id", &self.inner.type_)
277 .field("space_id", &self.inner.space_id)
278 .field("payload_size", &self.payload_size())
279 .finish()
280 }
281}
282
283impl<E> PartialOrd for EventHeader<E> {
284 #[inline]
285 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
286 Some(self.cmp(other))
287 }
288}
289
290impl<E> Ord for EventHeader<E> {
291 fn cmp(&self, other: &Self) -> Ordering {
292 self.inner.time.cmp(&other.inner.time)
293 }
294}