use crate::events::spaces::*;
use clap_sys::events::clap_event_header;
use std::fmt::{Debug, Formatter};
pub mod event_types;
pub mod io;
pub mod spaces;
mod header;
mod helpers;
mod pckn;
use crate::utils::usize_to_clap_size;
pub use header::*;
pub use pckn::*;
pub unsafe trait Event: AsRef<UnknownEvent> + Sized + 'static {
const TYPE_ID: u16;
type EventSpace<'a>: EventSpace<'a>;
#[inline]
fn flags(&self) -> EventFlags {
self.header().flags()
}
#[inline]
fn set_flags(&mut self, flags: EventFlags) {
self.header_mut().set_flags(flags)
}
#[inline]
fn with_flags(mut self, flags: EventFlags) -> Self {
self.header_mut().set_flags(flags);
self
}
#[inline]
fn time(&self) -> u32 {
self.header().time()
}
#[inline]
fn set_time(&mut self, time: u32) {
self.header_mut().set_time(time)
}
#[inline]
fn with_time(mut self, time: u32) -> Self {
self.header_mut().set_time(time);
self
}
#[inline]
fn header(&self) -> &EventHeader<Self> {
unsafe { EventHeader::from_raw_unchecked(self.raw_header()) }
}
#[inline]
fn header_mut(&mut self) -> &mut EventHeader<Self> {
unsafe { EventHeader::from_raw_unchecked_mut(self.raw_header_mut()) }
}
#[inline]
fn as_unknown(&self) -> &UnknownEvent {
unsafe { UnknownEvent::from_raw(self.raw_header()) }
}
#[inline]
fn raw_header(&self) -> &clap_event_header {
unsafe { &*(self as *const Self as *const clap_event_header) }
}
#[inline]
unsafe fn raw_header_mut(&mut self) -> &mut clap_event_header {
unsafe { &mut *(self as *mut Self as *mut clap_event_header) }
}
}
#[repr(transparent)]
pub struct UnknownEvent {
data: [u8],
}
impl UnknownEvent {
#[inline]
pub const fn header(&self) -> &EventHeader {
unsafe { EventHeader::from_raw(&*self.as_raw()) }
}
#[inline]
pub fn as_event<'s, E: Event<EventSpace<'s> = CoreEventSpace<'s>>>(&self) -> Option<&E> {
self.as_event_for_space(EventSpaceId::core())
}
#[inline]
pub fn as_core_event(&self) -> Option<CoreEventSpace<'_>> {
self.as_event_space(EventSpaceId::core())
}
#[inline]
pub fn as_event_for_space<E: Event>(
&self,
space_id: EventSpaceId<E::EventSpace<'_>>,
) -> Option<&E> {
let raw = self.header().as_raw();
if raw.space_id != space_id.id()
|| raw.type_ != E::TYPE_ID
|| raw.size != const { usize_to_clap_size(size_of::<E>()) }
{
return None;
}
Some(unsafe { self.as_event_unchecked() })
}
#[inline]
pub fn as_event_space<'s, S: EventSpace<'s>>(&'s self, space_id: EventSpaceId<S>) -> Option<S> {
if space_id.id() != self.header().space_id()?.id() {
return None;
}
unsafe { S::from_unknown(self) }
}
#[inline]
pub unsafe fn as_event_unchecked<E: Event>(&self) -> &E {
&*(self as *const _ as *const E)
}
#[inline]
pub const unsafe fn from_raw<'e>(header: *const clap_event_header) -> &'e Self {
let data = core::slice::from_raw_parts(header as *const _, (*header).size as usize);
Self::from_bytes_unchecked(data)
}
#[inline]
pub const fn as_raw(&self) -> *const clap_event_header {
self.data.as_ptr().cast()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
#[inline]
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &UnknownEvent {
&*(bytes as *const [u8] as *const _)
}
}
impl<E: Event> PartialEq<E> for UnknownEvent
where
E: PartialEq,
{
fn eq(&self, other: &E) -> bool {
match self.as_event_for_space::<E>(other.header().space_id()) {
None => false,
Some(s) => s.eq(other),
}
}
}
impl Debug for UnknownEvent {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.as_core_event() {
Some(e) => Debug::fmt(&e, f),
None => f
.debug_struct("UnknownEvent")
.field("header", self.header())
.finish(),
}
}
}
impl AsRef<UnknownEvent> for UnknownEvent {
#[inline]
fn as_ref(&self) -> &UnknownEvent {
self
}
}
#[inline]
pub(crate) const fn ensure_event_matches<'s, E: Event<EventSpace<'s> = CoreEventSpace<'s>>>(
header: &clap_event_header,
) {
if header.space_id != 0 {
panic_event_space_mismatch()
}
if header.type_ != E::TYPE_ID {
panic_event_type_mismatch()
}
}
#[inline(never)]
#[cold]
const fn panic_event_space_mismatch() {
panic!(
"CLAP Event mismatch: expected core event space (ID 0), got a non-core event space instead.",
)
}
#[inline(never)]
#[cold]
const fn panic_event_type_mismatch() {
panic!("CLAP Event mismatch: got a different event ID from expected")
}