use bevy_ecs::ResMut;
use std::marker::PhantomData;
#[derive(Debug)]
struct EventInstance<T> {
pub event_count: usize,
pub event: T,
}
#[derive(Debug)]
enum State {
A,
B,
}
#[derive(Debug)]
pub struct Events<T> {
events_a: Vec<EventInstance<T>>,
events_b: Vec<EventInstance<T>>,
a_start_event_count: usize,
b_start_event_count: usize,
event_count: usize,
state: State,
}
impl<T> Default for Events<T> {
fn default() -> Self {
Events {
a_start_event_count: 0,
b_start_event_count: 0,
event_count: 0,
events_a: Vec::new(),
events_b: Vec::new(),
state: State::A,
}
}
}
fn map_instance_event<T>(event_instance: &EventInstance<T>) -> &T {
&event_instance.event
}
pub struct EventReader<T> {
last_event_count: usize,
_marker: PhantomData<T>,
}
impl<T> Default for EventReader<T> {
fn default() -> Self {
Self {
last_event_count: 0,
_marker: PhantomData::default(),
}
}
}
impl<T> EventReader<T> {
pub fn iter<'a>(&mut self, events: &'a Events<T>) -> impl DoubleEndedIterator<Item = &'a T> {
let a_index = if self.last_event_count > events.a_start_event_count {
self.last_event_count - events.a_start_event_count
} else {
0
};
let b_index = if self.last_event_count > events.b_start_event_count {
self.last_event_count - events.b_start_event_count
} else {
0
};
self.last_event_count = events.event_count;
match events.state {
State::A => events
.events_b
.get(b_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_instance_event)
.chain(
events
.events_a
.get(a_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_instance_event),
),
State::B => events
.events_a
.get(a_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_instance_event)
.chain(
events
.events_b
.get(b_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_instance_event),
),
}
}
pub fn latest<'a>(&mut self, events: &'a Events<T>) -> Option<&'a T> {
self.iter(events).rev().next()
}
pub fn find_latest<'a>(
&mut self,
events: &'a Events<T>,
predicate: impl FnMut(&&T) -> bool,
) -> Option<&'a T> {
self.iter(events).rev().find(predicate)
}
pub fn earliest<'a>(&mut self, events: &'a Events<T>) -> Option<&'a T> {
self.iter(events).next()
}
}
impl<T: bevy_ecs::Resource> Events<T> {
pub fn send(&mut self, event: T) {
let event_instance = EventInstance {
event,
event_count: self.event_count,
};
match self.state {
State::A => self.events_a.push(event_instance),
State::B => self.events_b.push(event_instance),
}
self.event_count += 1;
}
pub fn get_reader(&self) -> EventReader<T> {
EventReader {
last_event_count: 0,
_marker: PhantomData,
}
}
pub fn get_reader_current(&self) -> EventReader<T> {
EventReader {
last_event_count: self.event_count,
_marker: PhantomData,
}
}
pub fn update(&mut self) {
match self.state {
State::A => {
self.events_b = Vec::new();
self.state = State::B;
self.b_start_event_count = self.event_count;
}
State::B => {
self.events_a = Vec::new();
self.state = State::A;
self.a_start_event_count = self.event_count;
}
}
}
pub fn update_system(mut events: ResMut<Self>) {
events.update();
}
pub fn clear(&mut self) {
self.events_a.clear();
self.events_b.clear();
}
pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
let map = |i: EventInstance<T>| i.event;
match self.state {
State::A => self
.events_b
.drain(..)
.map(map)
.chain(self.events_a.drain(..).map(map)),
State::B => self
.events_a
.drain(..)
.map(map)
.chain(self.events_b.drain(..).map(map)),
}
}
pub fn extend<I>(&mut self, events: I)
where
I: Iterator<Item = T>,
{
for event in events {
self.send(event);
}
}
pub fn iter_current_update_events(&self) -> impl DoubleEndedIterator<Item = &T> {
match self.state {
State::A => self.events_a.iter().map(map_instance_event),
State::B => self.events_b.iter().map(map_instance_event),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct TestEvent {
i: usize,
}
#[test]
fn test_events() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
let mut reader_missed = events.get_reader();
let mut reader_a = events.get_reader();
events.send(event_0);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_0],
"reader_a created before event receives event"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![],
"second iteration of reader_a created before event results in zero events"
);
let mut reader_b = events.get_reader();
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_0],
"reader_b created after event receives event"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![],
"second iteration of reader_b created after event results in zero events"
);
events.send(event_1);
let mut reader_c = events.get_reader();
assert_eq!(
get_events(&events, &mut reader_c),
vec![event_0, event_1],
"reader_c created after two events receives both events"
);
assert_eq!(
get_events(&events, &mut reader_c),
vec![],
"second iteration of reader_c created after two event results in zero events"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_1],
"reader_a receives next unread event"
);
events.update();
let mut reader_d = events.get_reader();
events.send(event_2);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_2],
"reader_a receives event created after update"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_1, event_2],
"reader_b receives events created before and after update"
);
assert_eq!(
get_events(&events, &mut reader_d),
vec![event_0, event_1, event_2],
"reader_d receives all events created before and after update"
);
events.update();
assert_eq!(
get_events(&events, &mut reader_missed),
vec![event_2],
"reader_missed missed events unread after to update() calls"
);
}
fn get_events(
events: &Events<TestEvent>,
reader: &mut EventReader<TestEvent>,
) -> Vec<TestEvent> {
reader.iter(events).cloned().collect::<Vec<TestEvent>>()
}
}