use std::any::type_name;
use std::any::Any;
use std::any::TypeId;
use std::collections::BTreeMap;
use anyhow::Result;
use thiserror::Error;
#[derive(Default, Debug)]
pub struct State {
data: BTreeMap<TypeId, Box<dyn Any>>,
}
impl State {
pub fn put<T: 'static>(&mut self, t: T) {
let type_id = TypeId::of::<T>();
self.data.insert(type_id, Box::new(t));
}
pub fn has<T: 'static>(&self) -> bool {
let type_id = TypeId::of::<T>();
self.data.get(&type_id).is_some()
}
pub fn try_borrow<T: 'static>(&self) -> Option<&T> {
let type_id = TypeId::of::<T>();
self.data.get(&type_id).and_then(|b| b.downcast_ref())
}
pub fn borrow<T: 'static>(&self) -> Result<&T> {
if let Some(value) = self.try_borrow() {
Ok(value)
} else {
Err(MissingTypeError::from::<T>().into())
}
}
pub fn try_borrow_mut<T: 'static>(&mut self) -> Option<&mut T> {
let type_id = TypeId::of::<T>();
self.data.get_mut(&type_id).and_then(|b| b.downcast_mut())
}
pub fn borrow_mut<T: 'static>(&mut self) -> Result<&mut T> {
if let Some(value) = self.try_borrow_mut() {
Ok(value)
} else {
Err(MissingTypeError::from::<T>().into())
}
}
pub fn try_take<T: 'static>(&mut self) -> Option<T> {
let type_id = TypeId::of::<T>();
self.data.remove(&type_id).and_then(|b| b.downcast().ok()).map(|b| *b)
}
pub fn take<T: 'static>(&mut self) -> Result<T> {
if let Some(value) = self.try_take() {
Ok(value)
} else {
Err(MissingTypeError::from::<T>().into())
}
}
}
#[derive(Error, Debug)]
#[error("required type {0} is not present in State container")]
pub struct MissingTypeError(&'static str);
impl MissingTypeError {
fn from<T: 'static>() -> MissingTypeError {
MissingTypeError(type_name::<T>())
}
}