198 lines
5.7 KiB
Rust
198 lines
5.7 KiB
Rust
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<T: Clone + Send + Sync + 'static> Event for T {}
|
|
|
|
pub type Events<T> = VecDeque<T>;
|
|
|
|
#[derive(Clone)]
|
|
struct TypeErasedBuffer {
|
|
type_id: TypeId,
|
|
item_size: usize,
|
|
data: Vec<MaybeUninit<u8>>,
|
|
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<T: 'static>() -> Self {
|
|
Self {
|
|
type_id: TypeId::of::<T>(),
|
|
item_size: mem::size_of::<T>(),
|
|
data: Default::default(),
|
|
// dropped immediately after the read
|
|
fn_drop_item: |item| unsafe { item.cast::<T>().drop_in_place() },
|
|
}
|
|
}
|
|
|
|
pub fn push<T: 'static>(&mut self, value: T) {
|
|
debug_assert!(TypeId::of::<T>() == 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::<T>());
|
|
|
|
// 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::<T>()
|
|
// 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::<T>());
|
|
}
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.data.len() / self.item_size
|
|
}
|
|
}
|
|
|
|
pub struct EventQueue {
|
|
events: HashMap<TypeId, TypeErasedBuffer>,
|
|
event_write_queue: HashMap<TypeId, TypeErasedBuffer>,
|
|
}
|
|
|
|
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<E>(&mut self, event: E)
|
|
where
|
|
E: Event
|
|
{
|
|
// the compiler wants me to explicit right here for some reason
|
|
/* let default = || RefCell::new(Box::<Events::<E>>::default() as Box<dyn AsSyncAny>);
|
|
|
|
// 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<E> = 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::<E>());
|
|
|
|
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<TypeId> = 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<E>(&self) -> Option<EventReader<E>>
|
|
where
|
|
E: Event
|
|
{
|
|
self.events.get(&TypeId::of::<E>())
|
|
.map(|event| EventReader::new(event.clone()))
|
|
}
|
|
}
|
|
|
|
pub struct EventReader<E: Event> {
|
|
buf: TypeErasedBuffer,
|
|
range: Option<Range<*mut MaybeUninit<u8>>>,
|
|
_marker: PhantomData<E>,
|
|
}
|
|
|
|
impl<E: Event> EventReader<E> {
|
|
fn new(buffer: TypeErasedBuffer) -> Self {
|
|
Self {
|
|
buf: buffer,
|
|
range: None,
|
|
_marker: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.buf.len()
|
|
}
|
|
}
|
|
|
|
impl<E: Event> Iterator for EventReader<E> {
|
|
type Item = E;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
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::<E>().read_unaligned() };
|
|
|
|
// Advance the pointer to be after this event.
|
|
range.start = unsafe { range.start.add(mem::size_of::<E>()) };
|
|
|
|
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());
|
|
}
|
|
} |