use std::{any::{Any, TypeId}, collections::{HashMap, VecDeque}, marker::PhantomData, mem::{self, MaybeUninit}, ops::Range}; use crate::plugin::Plugin; pub trait Event: Clone + Send + Sync + 'static {} impl Event for T {} pub type Events = VecDeque; #[derive(Clone)] struct TypeErasedBuffer { type_id: TypeId, item_size: usize, data: Vec>, fn_drop_item: fn(item: *mut ()), } impl Drop for TypeErasedBuffer { fn drop(&mut self) { let range = self.data.as_mut_ptr_range(); let mut current = range.start; let end = range.end; while current < end { // SAFETY: current pointer will either be the start of the buffer, or at the start of // the next item (self.fn_drop_item)(current.cast()); // SAFETY: the items are placed right after eachother current = unsafe { current.add(self.item_size) }; } // Safety: all of the events were just dropped unsafe { self.data.set_len(0) }; } } impl TypeErasedBuffer { pub fn new() -> Self { Self { type_id: TypeId::of::(), item_size: mem::size_of::(), data: Default::default(), // dropped immediately after the read fn_drop_item: |item| unsafe { item.cast::().drop_in_place() }, } } pub fn push(&mut self, value: T) { debug_assert!(TypeId::of::() == self.type_id, "The type of the buffer does not match the type that was added to it"); // reserve enough bytes to store T let old_len = self.data.len(); self.data.reserve(mem::size_of::()); // Get a pointer to the end of the data. // SAFETY: we just reserved enough memory to store the data. let end_ptr = unsafe { self.data.as_mut_ptr().add(old_len) }; unsafe { // write the command and its runner into the buffer end_ptr.cast::() // written unaligned to keep everything packed .write_unaligned(value); // we wrote to the vec's buffer without using its api, so we need manually // set the length of the vec. self.data.set_len(old_len + mem::size_of::()); } } pub fn len(&self) -> usize { self.data.len() / self.item_size } } pub struct EventQueue { events: HashMap, event_write_queue: HashMap, } impl Default for EventQueue { fn default() -> Self { Self::new() } } impl EventQueue { pub fn new() -> Self { Self { event_write_queue: HashMap::new(), events: HashMap::new(), } } /// Trigger an event pub fn trigger_event(&mut self, event: E) where E: Event { // the compiler wants me to explicit right here for some reason /* let default = || RefCell::new(Box::>::default() as Box); // Get, or create, a list of events of this type let type_id = event.type_id(); let mut events = self.event_write_queue.entry(type_id) .or_insert_with(default) .borrow_mut(); // downcast resource as an events storage let e: &mut Events = events.as_mut().as_any_mut().downcast_mut().unwrap(); e.push_back(event); */ let type_id = event.type_id(); let events = self.event_write_queue.entry(type_id) .or_insert_with(|| TypeErasedBuffer::new::()); events.push(event); } // Clear events, this should happen at the start of every tick since events are cloned // before being given to the reader. pub fn update_events(&mut self) { self.events.clear(); // get all keys of events let keys: Vec = self.event_write_queue.keys().copied().collect(); // remove all elements from self.event_write_queue and insert them to events for k in keys.into_iter() { let v = self.event_write_queue.remove(&k).unwrap(); self.events.insert(k, v); } } pub fn read_events(&self) -> Option> where E: Event { self.events.get(&TypeId::of::()) .map(|event| EventReader::new(event.clone())) } } pub struct EventReader { buf: TypeErasedBuffer, range: Option>>, _marker: PhantomData, } impl EventReader { fn new(buffer: TypeErasedBuffer) -> Self { Self { buf: buffer, range: None, _marker: PhantomData, } } pub fn len(&self) -> usize { self.buf.len() } } impl Iterator for EventReader { type Item = E; fn next(&mut self) -> Option { if self.range.is_none() { self.range = Some(self.buf.data.as_mut_ptr_range()); } let range = self.range.as_mut().unwrap(); if range.start < range.end { // Retrieve the event in the buffer. // SAFETY: current pointer will either be the start of the buffer, or at the start // of the next event. let event = unsafe { range.start.cast::().read_unaligned() }; // Advance the pointer to be after this event. range.start = unsafe { range.start.add(mem::size_of::()) }; Some(event) } else { None } } } #[derive(Default)] pub struct EventsPlugin; impl Plugin for EventsPlugin { fn setup(&self, game: &mut crate::game::Game) { game.world_mut().add_resource(EventQueue::new()); } }