use std::{
any::TypeId,
collections::VecDeque,
panic::RefUnwindSafe,
sync::{atomic::AtomicBool, MutexGuard},
};
#[derive(Debug)]
pub struct Event<const SIZE: usize>(anythingy::Thing<SIZE>);
impl<const SIZE: usize> RefUnwindSafe for Event<SIZE> {}
unsafe impl<const SIZE: usize> Send for Event<SIZE> {}
impl<const SIZE: usize> Event<SIZE> {
#[inline]
pub fn new<T>(t: T) -> Self
where
T: Send + RefUnwindSafe + 'static,
{
Self(anythingy::Thing::new(t))
}
#[inline]
const fn fitting<T: 'static>() -> bool {
anythingy::Thing::<SIZE>::fitting::<T>()
}
#[inline]
const fn size_requirement<T: 'static>() -> usize {
anythingy::Thing::<SIZE>::size_requirement::<T>()
}
#[inline]
pub fn get<T: 'static>(self) -> T {
self.0.get()
}
#[inline]
pub fn get_ref<T: 'static>(&self) -> &T {
self.0.get_ref()
}
}
use crate::{
err::{EventError, EventSizeError, Value},
map::RegisteredMap,
query::{Query, UnblockingQuery},
slot::{Slot, SlotType},
DEFAULT_EVENT_SIZE,
};
pub struct EventBackend<const EVENT_SIZE: usize = DEFAULT_EVENT_SIZE> {
pub(crate) registered: RegisteredMap<EVENT_SIZE>,
}
impl<const EVENT_SIZE: usize> EventBackend<EVENT_SIZE> {
#[must_use]
pub const fn new() -> Self {
Self {
registered: RegisteredMap::new(),
}
}
pub fn register_store<T>(&mut self, typ: SlotType<T>) -> Result<(), EventError<T>>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
return Err(EventError::event_size_empty(EventSizeError::new(
EVENT_SIZE,
Event::<EVENT_SIZE>::size_requirement::<T>(),
)));
}
let id = TypeId::of::<T>();
let slot = Slot::new(typ);
if let Some(registered) = self.registered.get_mut(&id) {
registered.slot = Some(slot);
return Ok(());
}
let mut registered = Registered::new();
registered.slot = Some(slot);
_ = self.registered.insert(id, registered);
Ok(())
}
pub fn register_listener<T>(
&mut self,
listener: impl Fn(&T) + Send + Sync + RefUnwindSafe + 'static,
) -> Result<usize, EventSizeError>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
return Err(EventSizeError::new(
EVENT_SIZE,
Event::<EVENT_SIZE>::size_requirement::<T>(),
));
}
let id = TypeId::of::<T>();
let map_f = move |event: &Event<EVENT_SIZE>| {
let value = event.get_ref::<T>();
listener(value);
};
if let Some(registered) = self.registered.get_mut(&id) {
registered.listener.push(Box::new(map_f));
return Ok(registered.listener.len());
}
let mut registered = Registered::new();
registered.listener.push(Box::new(map_f));
_ = self.registered.insert(id, registered);
Ok(1)
}
pub fn new_event<T>(&self, value: T) -> Result<(), EventError<T, Value>>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
let err = EventSizeError::new(EVENT_SIZE, Event::<EVENT_SIZE>::size_requirement::<T>());
return Err(EventError::event_size(value, err));
}
let id = TypeId::of::<T>();
if let Some(registered) = self.registered.get(&id) {
registered.handle_event(Event::new(value));
} else {
return Err(EventError::unregisted_event(value));
}
Ok(())
}
pub fn query<T>(&self) -> Result<UnblockingQuery<T, EVENT_SIZE>, EventError<T>>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
return Err(EventError::event_size_empty(EventSizeError::new(
EVENT_SIZE,
Event::<EVENT_SIZE>::size_requirement::<T>(),
)));
}
let id = TypeId::of::<T>();
self.registered.get(&id).map_or_else(
|| Err(EventError::unregisted_event_empty()),
|registed| {
registed.events_clone().map_or_else(
|| Err(EventError::registered_without_store()),
|events| Ok(UnblockingQuery::new(events)),
)
},
)
}
pub fn query_blocking<T>(&self) -> Result<Query<T, EVENT_SIZE>, EventError<T>>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
return Err(EventError::event_size_empty(EventSizeError::new(
EVENT_SIZE,
Event::<EVENT_SIZE>::size_requirement::<T>(),
)));
}
let id = TypeId::of::<T>();
self.registered.get(&id).map_or_else(
|| Err(EventError::unregisted_event_empty()),
|registed| {
registed.events().map_or_else(
|| Err(EventError::registered_without_store()),
|events| Ok(Query::new(events)),
)
},
)
}
pub fn disable<T>(&self) -> Result<(), EventError<T>>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
return Err(EventError::event_size_empty(EventSizeError::new(
EVENT_SIZE,
Event::<EVENT_SIZE>::size_requirement::<T>(),
)));
}
let id = TypeId::of::<T>();
match self.registered.get(&id) {
Some(registered) => registered.disable(),
None => return Err(EventError::unregisted_event_empty()),
}
Ok(())
}
pub fn disable_all(&self) {
for registered in self.registered.values() {
registered.disable();
}
}
pub fn enable<T>(&self) -> Result<(), EventError<T>>
where
T: Send + RefUnwindSafe + 'static,
{
if !Event::<EVENT_SIZE>::fitting::<T>() {
return Err(EventError::event_size_empty(EventSizeError::new(
EVENT_SIZE,
Event::<EVENT_SIZE>::size_requirement::<T>(),
)));
}
let id = TypeId::of::<T>();
match self.registered.get(&id) {
Some(registered) => registered.enable(),
None => return Err(EventError::unregisted_event_empty()),
}
Ok(())
}
pub fn enable_all(&self) {
for registered in self.registered.values() {
registered.enable();
}
}
pub fn cleanup(&mut self) {
for registered in self.registered.values_mut() {
registered.cleanup();
}
}
}
impl Default for EventBackend<DEFAULT_EVENT_SIZE> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<const EVENT_SIZE: usize> std::fmt::Debug for EventBackend<EVENT_SIZE> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EventBackend")
.field("registered", &self.registered.len())
.finish()
}
}
type Listener<const SIZE: usize> = Box<dyn Fn(&Event<SIZE>) + Sync + RefUnwindSafe + Send>;
pub struct Registered<const SIZE: usize> {
slot: Option<Slot<SIZE>>,
listener: Vec<Listener<SIZE>>,
enabled: AtomicBool,
}
impl<const SIZE: usize> Registered<SIZE> {
#[inline]
pub fn new() -> Self {
Self {
slot: None,
listener: Vec::new(),
enabled: AtomicBool::new(true),
}
}
pub fn handle_event(&self, event: Event<SIZE>) {
if !self.enabled.load(std::sync::atomic::Ordering::Relaxed) {
return;
}
for listener in &self.listener {
_ = std::panic::catch_unwind(|| (listener)(&event));
}
if let Some(slot) = &self.slot {
slot.push(event);
}
}
#[inline]
pub fn events_clone(&self) -> Option<VecDeque<Event<SIZE>>> {
self.slot.as_ref().map(Slot::events_clone)
}
#[inline]
pub fn events(&self) -> Option<MutexGuard<VecDeque<Event<SIZE>>>> {
self.slot.as_ref().map(Slot::events)
}
#[inline]
pub fn cleanup(&mut self) {
self.listener = Vec::new();
if let Some(slot) = &mut self.slot {
slot.cleanup();
}
}
#[inline]
fn enable(&self) {
self.enabled
.store(true, std::sync::atomic::Ordering::Relaxed);
}
#[inline]
fn disable(&self) {
self.enabled
.store(false, std::sync::atomic::Ordering::Relaxed);
}
}
impl<const SIZE: usize> std::fmt::Debug for Registered<SIZE> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Registered")
.field("slot", &self.slot)
.field("listener", &self.listener.len())
.field("enabled", &self.enabled)
.finish()
}
}
#[cfg(test)]
mod tests {
use crate::DEFAULT_EVENT_SIZE;
use super::EventBackend;
const fn const_listener<E>(_: &E) {}
#[test]
fn test_eventbackend_setup_listener() {
let mut events: EventBackend<DEFAULT_EVENT_SIZE> = EventBackend::new();
let res = events.register_listener(const_listener::<u32>);
assert!(res.is_ok());
assert_eq!(res.unwrap(), 1);
let res = events.register_listener(const_listener::<u32>);
assert!(res.is_ok());
assert_eq!(res.unwrap(), 2);
}
#[test]
fn test_eventbackend_setup_register() {
let mut events: EventBackend<DEFAULT_EVENT_SIZE> = EventBackend::new();
let res = events.register_listener(const_listener::<u32>);
assert!(res.is_ok());
assert_eq!(res.unwrap(), 1);
let res = events.register_listener(const_listener::<u32>);
assert!(res.is_ok());
assert_eq!(res.unwrap(), 2);
}
#[test]
fn test_eventbackend_setup_mixed() {
let mut events: EventBackend<DEFAULT_EVENT_SIZE> = EventBackend::new();
let res = events.register_listener::<u32>(const_listener);
assert!(res.is_ok());
assert_eq!(res.unwrap(), 1);
let res = events.register_store::<u32>(crate::SlotType::First);
assert!(res.is_ok());
}
}