use std::{
any::TypeId,
collections::{btree_map::IntoValues, BTreeMap},
};
use better_any::{Tid, TidAble, TidExt};
use crate::token_store::TokenStore;
use super::{context::Context, generatable::Generatable, wrapper::GenerationWrapper};
#[derive(Default)]
pub struct GeneratableSet<'set> {
backend: BTreeMap<TypeId, Box<dyn GeneratableBackend<'set>>>,
}
impl<'set> IntoIterator for GeneratableSet<'set> {
type Item = Box<dyn GeneratableBackend<'set>>;
type IntoIter = IntoValues<TypeId, Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.backend.into_values()
}
}
#[allow(dead_code)]
pub enum InsertStatus {
WasInserted,
AlreadyPresent,
}
impl<'set> GeneratableSet<'set> {
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
#[must_use]
pub fn get_or_insert_with<T>(&mut self, f: impl FnOnce() -> T) -> &mut T
where
T: GeneratableBackend<'set>,
{
self.backend
.entry(T::id())
.or_insert_with(|| Box::new(f()))
.as_mut()
.downcast_mut::<T>()
.unwrap()
}
#[allow(dead_code)]
#[must_use]
pub fn get_or_insert_default<T>(&mut self) -> &mut T
where
T: GeneratableBackend<'set> + Default,
{
self.get_or_insert_with::<T>(Default::default)
}
#[allow(dead_code)]
#[must_use]
pub fn get<T>(&self) -> Option<&T>
where
T: GeneratableBackend<'set>,
{
self.backend
.get(&T::id())
.map(AsRef::as_ref)
.and_then(TidExt::downcast_ref)
}
#[allow(dead_code)]
pub fn insert<T>(&mut self, val: T) -> InsertStatus
where
T: GeneratableBackend<'set>,
{
if self.contains::<T>() {
return InsertStatus::AlreadyPresent;
}
self.backend.insert(T::id(), Box::new(val));
InsertStatus::WasInserted
}
#[allow(dead_code)]
pub fn insert_with<T>(&mut self, f: impl FnOnce() -> T) -> InsertStatus
where
T: GeneratableBackend<'set>,
{
if self.contains::<T>() {
return InsertStatus::AlreadyPresent;
}
self.backend.insert(T::id(), Box::new(f()));
InsertStatus::WasInserted
}
#[allow(dead_code)]
#[must_use]
pub fn contains<T>(&self) -> bool
where
T: GeneratableBackend<'set>,
{
self.backend.contains_key(&T::id())
}
pub fn iter(&self) -> impl Iterator<Item = &dyn GeneratableBackend<'set>> {
self.backend.values().map(AsRef::as_ref)
}
#[allow(dead_code)]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut dyn GeneratableBackend<'set>> {
self.backend.values_mut().map(AsMut::as_mut)
}
}
pub trait GeneratableBackend<'a>: Tid<'a> {
fn generate_into(&self, context: &mut Context, token_store: &mut TokenStore);
}
impl<'a, T, A> GeneratableBackend<'a> for GenerationWrapper<'a, T, A>
where
T: Generatable<'a, A> + Ord,
A: TidAble<'a> + Ord + PartialOrd,
{
fn generate_into(&self, context: &mut Context, token_store: &mut TokenStore) {
self.do_generation(context, token_store);
}
}