pebble-engine 3.1.2

A modular, ECS-style graphics/app framework for Rust.
Documentation
use crate::ecs::{
    resources::{Read, Resources, Write},
    system_param::SystemParam,
};

/// Double-buffered event storage, registered via
/// [`App::add_event`](crate::app::App::add_event). An event sent during
/// tick `N` is visible to readers for the rest of `N` and all of `N + 1`,
/// then dropped — so a reader sees it exactly once no matter when it runs
/// relative to the writer. Read/write it via [`EventReader`]/[`EventWriter`],
/// not directly.
pub struct Events<T> {
    current: Vec<(usize, T)>,
    previous: Vec<(usize, T)>,
    next_id: usize,
}

impl<T> Default for Events<T> {
    fn default() -> Self {
        Self { current: Vec::new(), previous: Vec::new(), next_id: 0 }
    }
}

impl<T> Events<T> {
    pub fn send(&mut self, event: T) {
        self.current.push((self.next_id, event));
        self.next_id += 1;
    }

    pub(crate) fn update(&mut self) {
        self.previous = std::mem::take(&mut self.current);
    }
}

/// Reads unread [`Events<T>`] as a system parameter. Each reader keeps its
/// own cursor (like [`Local`](crate::ecs::local::Local)), so multiple
/// readers of the same event type don't interfere with each other.
pub struct EventReader<'a, T: 'static> {
    events: Read<'a, Events<T>>,
    last_seen: &'a mut usize,
}

impl<'a, T: 'static> EventReader<'a, T> {
    /// Every event sent since this reader last called `iter`, oldest first.
    pub fn iter(&mut self) -> impl Iterator<Item = &T> + '_ {
        let seen = *self.last_seen;
        let unread: Vec<&T> = self
            .events
            .previous
            .iter()
            .chain(self.events.current.iter())
            .filter(|(id, _)| *id >= seen)
            .map(|(_, event)| event)
            .collect();
        *self.last_seen = self.events.next_id;
        unread.into_iter()
    }

    /// `true` if there's nothing unread for this reader.
    pub fn is_empty(&self) -> bool {
        let seen = *self.last_seen;
        !self.events.previous.iter().chain(self.events.current.iter()).any(|(id, _)| *id >= seen)
    }
}

impl<T: 'static> SystemParam for EventReader<'static, T> {
    type Item<'a> = EventReader<'a, T>;
    type State = usize;

    fn fetch<'a>(_world: &'a hecs::World, resources: &'a Resources, state: &'a mut Self::State) -> Self::Item<'a> {
        EventReader { events: Read { inner: resources.get::<Events<T>>() }, last_seen: state }
    }
}

impl<T> SystemParam for Option<EventReader<'static, T>>
where
    T: 'static + Sync + Send,
{
    type Item<'a> = Option<EventReader<'a, T>>;
    type State = usize;

    fn fetch<'a>(world: &'a hecs::World, resources: &'a Resources, state: &'a mut Self::State) -> Self::Item<'a> {
        resources.contains::<Events<T>>().then(|| EventReader::fetch(world, resources, state))
    }
}

/// Sends into [`Events<T>`] as a system parameter.
pub struct EventWriter<'a, T: 'static> {
    events: Write<'a, Events<T>>,
}

impl<'a, T: 'static> EventWriter<'a, T> {
    /// Queues `event`, visible to readers for the rest of this tick and all
    /// of the next.
    pub fn send(&mut self, event: T) {
        self.events.send(event);
    }
}

impl<T: 'static> SystemParam for EventWriter<'static, T> {
    type Item<'a> = EventWriter<'a, T>;
    type State = ();

    fn fetch<'a>(_world: &'a hecs::World, resources: &'a Resources, _state: &'a mut Self::State) -> Self::Item<'a> {
        EventWriter { events: Write { inner: resources.get_mut::<Events<T>>() } }
    }
}

impl<T> SystemParam for Option<EventWriter<'static, T>>
where
    T: 'static + Sync + Send,
{
    type Item<'a> = Option<EventWriter<'a, T>>;
    type State = ();

    fn fetch<'a>(world: &'a hecs::World, resources: &'a Resources, state: &'a mut Self::State) -> Self::Item<'a> {
        resources.contains::<Events<T>>().then(|| EventWriter::fetch(world, resources, state))
    }
}

pub(crate) fn age_events<T: Send + Sync + 'static>(mut events: Write<Events<T>>) {
    events.update();
}