#![doc = include_str!("../README.md")]
#![warn(missing_docs)]

/// Module providing the front-facing [`app::App`] structure
pub mod app;
/// Module providing [`controller::Controller`] trait
pub mod controller;
/// Error types
pub mod errors;
/// Renderer internal parts of the library
pub mod renderer;
/// Module providing the [`state::State`] structure, containing most important things for the renderer
pub mod state;
/// Exports most of the stuff you'll need
pub mod prelude;

/// Define a storage for an arbitrary type
#[macro_export]
macro_rules! define_store {
    ($ty:ident) => {
        use paste::paste;
        paste! {
            #[doc = "Handle to a [`" $ty "`] stored inside [`" $ty "Store`]"]
            #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
            pub struct [<$ty Id>](pub(crate) u32);

            #[doc = "Storage for [`" $ty "`]"]
            pub struct [<$ty Store>] {
                [<$ty:snake s>]: Vec<Option<$ty>>,
            }

            impl [<$ty Store>] {
                #[doc = "Create a new instance of [`" $ty "Store`]"]
                pub fn new() -> Self {
                    Self {
                        [<$ty:snake s>]: Vec::new(),
                    }
                }

                #[doc = "Insert a [`" $ty "`]"]
                pub fn insert(&mut self, value: $ty) -> [<$ty Id>] {
                    let id = [<$ty Id>](self.[<$ty:snake s>].len() as u32);
                    self.[<$ty:snake s>].push(Some(value));
                    id
                }

                #[doc = "Get a reference to a [`" $ty "`]"]
                pub fn get(&self, id: [<$ty Id>]) -> Option<&$ty> {
                    self.[<$ty:snake s>]
                        .get(id.0 as usize)
                        .and_then(|value| value.as_ref())
                }

                #[doc = "Get a mutable reference to a [`" $ty "`]"]
                pub fn get_mut(&mut self, id: [<$ty Id>]) -> Option<&mut $ty> {
                    self.[<$ty:snake s>]
                        .get_mut(id.0 as usize)
                        .and_then(|value| value.as_mut())
                }

                #[doc = "Remove [`" $ty "`] from storage"]
                pub fn remove(&mut self, id: [<$ty Id>]) -> Option<$ty> {
                    self.[<$ty:snake s>]
                        .get_mut(id.0 as usize)
                        .and_then(|slot| slot.take())
                }
            }

            impl Default for [<$ty Store>] {
                fn default() -> Self {
                    Self::new()
                }
            }
        }
    };
}
