oxygengine-core 0.30.0

Core module for Oxygengine
Documentation
use crate::{
    ecs::Entity,
    prefab::{Prefab, PrefabComponent, PrefabError, PrefabProxy},
    state::StateToken,
};
use oxygengine_ignite_derive::Ignite;
use serde::{Deserialize, Serialize};
use std::{
    borrow::Cow,
    collections::{HashMap, VecDeque},
    marker::PhantomData,
};

#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
pub struct Tag(pub Cow<'static, str>);

impl Prefab for Tag {}
impl PrefabComponent for Tag {}

#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
pub struct Name(pub Cow<'static, str>);

impl Prefab for Name {}
impl PrefabComponent for Name {}

#[derive(Ignite, Debug, Default, Clone)]
pub struct NonPersistent(pub StateToken);

impl PrefabProxy<NonPersistentPrefabProxy> for NonPersistent {
    fn from_proxy_with_extras(
        _: NonPersistentPrefabProxy,
        _: &HashMap<String, Entity>,
        state_token: StateToken,
    ) -> Result<Self, PrefabError> {
        Ok(NonPersistent(state_token))
    }
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct NonPersistentPrefabProxy;

impl Prefab for NonPersistentPrefabProxy {}

#[derive(Ignite, Clone)]
pub struct Events<T>
where
    T: Send + Sync,
{
    #[ignite(ignore)]
    buffer: VecDeque<T>,
    #[ignite(ignore)]
    capacity: Option<usize>,
    #[ignite(ignore)]
    pub auto_clear: bool,
}

impl<T> Default for Events<T>
where
    T: Send + Sync,
{
    fn default() -> Self {
        Self::new(None, true)
    }
}

impl<T> Events<T>
where
    T: Send + Sync,
{
    pub fn new(capacity: Option<usize>, auto_clear: bool) -> Self {
        Self {
            buffer: VecDeque::with_capacity(capacity.unwrap_or_default()),
            capacity,
            auto_clear,
        }
    }

    pub fn clear(&mut self) {
        self.buffer.clear();
    }

    pub fn read(&self) -> impl Iterator<Item = &T> {
        self.buffer.iter()
    }

    pub fn consume(&mut self) -> impl Iterator<Item = T> + '_ {
        self.buffer.drain(..)
    }

    pub fn consume_if<F>(&mut self, mut f: F) -> Vec<T>
    where
        F: FnMut(&T) -> bool,
    {
        if self.buffer.is_empty() {
            return Default::default();
        }
        let mut result = Vec::with_capacity(self.buffer.len());
        let mut buffer = VecDeque::with_capacity(self.buffer.capacity());
        for message in self.buffer.drain(..) {
            if f(&message) {
                result.push(message);
            } else {
                buffer.push_back(message);
            }
        }
        result
    }

    pub fn send(&mut self, message: T) {
        if let Some(capacity) = self.capacity {
            if self.buffer.len() >= capacity {
                self.buffer.pop_front();
            }
        }
        self.buffer.push_back(message);
    }

    pub fn try_send(&mut self, message: T) -> bool {
        if let Some(capacity) = self.capacity {
            if self.buffer.len() >= capacity {
                return false;
            }
        }
        self.buffer.push_back(message);
        true
    }
}

impl<T> PrefabProxy<EventsPrefabProxy<T>> for Events<T>
where
    T: Send + Sync + 'static,
{
    fn from_proxy_with_extras(
        proxy: EventsPrefabProxy<T>,
        _: &HashMap<String, Entity>,
        _: StateToken,
    ) -> Result<Self, PrefabError> {
        Ok(Events::new(proxy.capacity, proxy.auto_clear))
    }
}

#[derive(Default, Serialize, Deserialize)]
pub struct EventsPrefabProxy<T>
where
    T: Send + Sync,
{
    #[serde(default)]
    pub capacity: Option<usize>,
    #[serde(default = "EventsPrefabProxy::<T>::default_auto_clear")]
    pub auto_clear: bool,
    #[serde(skip)]
    _phantom: PhantomData<fn() -> T>,
}

impl<T> EventsPrefabProxy<T>
where
    T: Send + Sync,
{
    fn default_auto_clear() -> bool {
        true
    }
}

impl<T> Prefab for EventsPrefabProxy<T> where T: Send + Sync {}

#[cfg(test)]
mod tests {
    use super::*;
    use hecs::Component;

    #[test]
    fn test_component() {
        fn foo<T: Component>() {
            println!("{} is Component", std::any::type_name::<T>());
        }

        foo::<Tag>();
        foo::<Name>();
        foo::<NonPersistent>();
        foo::<Events<()>>();
    }
}