Skip to main content

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}