#![cfg_attr(not(doctest), doc = include_str!("../README.md") )]
#![feature(once_cell)]
#![feature(trait_alias)]
#![feature(generic_associated_types)]
#![feature(associated_type_defaults)]
#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![warn(clippy::pedantic)]
mod details;
pub mod id;
pub mod prelude;
pub mod scope;
mod scope_map;
pub type DmvId<S, T> = Pin<Box<details::Id<S, T>>>;
pub use id::{Id, RawRepr};
pub use scope::{GlobalScope, Scope};
use details::Id as privId;
use scope_map::ScopeMap;
use std::{
any::{Any, TypeId},
collections::HashMap,
lazy::SyncLazy,
pin::Pin,
sync::Mutex,
};
use num_traits::Num;
macro_rules! gen_global_scope_inits {
($map:ident<$($T:ty),+ $(,).*>) => {$(
$map.entry(TypeId::of::<$T>())
.or_insert_with(|| {
let mut scope_map = ScopeMap::<$T>::new();
scope_map.set(TypeId::of::<GlobalScope>(), 1);
Box::new(scope_map)
});
)*};
($($t:tt)*) => {
compile_error!(concat!(
"encountered unexpected tokens: ",
stringify!($($t)*),
));
};
}
static MAPS: SyncLazy<Mutex<HashMap<TypeId, Box<dyn Any + Send>>>> =
SyncLazy::new(|| {
let mut map: HashMap<_, Box<dyn Any + Send>> = HashMap::new();
gen_global_scope_inits!(map<u8, u16, u32, u64, u128, usize>);
Mutex::new(map)
});
#[derive(Default)]
pub struct Dmv;
impl Dmv {
#[allow(clippy::unused_self)]
#[must_use]
pub fn register<S: Scope, T: RawRepr + Num + Send>(
&self,
) -> Option<DmvId<S, T>> {
let mut lock = MAPS.lock().unwrap();
let scope_map = lock
.get_mut(&TypeId::of::<T>())?
.downcast_mut::<ScopeMap<T>>()
.unwrap();
let val = scope_map.get(TypeId::of::<S>())?;
Some(privId::new(val))
}
#[allow(clippy::unused_self)]
#[must_use]
pub unsafe fn register_unchecked<S: Scope, T: RawRepr>(
&self,
id_val: T,
) -> DmvId<S, T> {
privId::new(id_val)
}
pub fn init_default<S: Scope, T: RawRepr + Send + Num>(&self) {
self.init::<S, T>(T::one());
}
#[allow(clippy::unused_self)]
pub fn init<S: Scope, T: RawRepr + Send + Num>(&self, base: T) {
let mut lock = MAPS.lock().unwrap();
let scope_map = lock
.entry(TypeId::of::<T>())
.or_insert_with(move || Box::new(ScopeMap::<T>::new()))
.downcast_mut::<ScopeMap<T>>()
.unwrap();
if !scope_map.has(TypeId::of::<S>()) {
scope_map.set(TypeId::of::<S>(), base);
}
}
#[allow(clippy::unused_self)]
#[must_use]
pub fn is_init<S: Scope, T: RawRepr + Num>(&self) -> bool {
let maps = MAPS.lock().unwrap();
maps.contains_key(&TypeId::of::<T>())
&& maps
.get(&TypeId::of::<T>())
.unwrap()
.downcast_ref::<ScopeMap<T>>()
.unwrap()
.has(TypeId::of::<S>())
}
#[allow(clippy::unused_self)]
pub unsafe fn reset<S: Scope, T: RawRepr + Send + Num>(&self, base: T) {
MAPS.lock()
.unwrap()
.entry(TypeId::of::<T>())
.or_insert_with(move || Box::new(ScopeMap::<T>::new()))
.downcast_mut::<ScopeMap<T>>()
.unwrap()
.set(TypeId::of::<S>(), base);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let id1 = Dmv.register::<GlobalScope, usize>().unwrap();
let id2 = Dmv.register::<GlobalScope, usize>().unwrap();
let h1 = id1.handle();
let h2 = id2.handle();
assert_ne!(id1, id2);
assert_ne!(*h1, *h2);
}
}