use crate::context::{Context, ContextMarker};
use crate::types::{EnvError, EnvType};
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct Environment {
current: EnvType,
contexts: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
}
impl Environment {
pub fn current_env(&self) -> &EnvType {
&self.current
}
pub fn context<M: ContextMarker>(&self) -> Option<&Context<M>> {
self.contexts
.get(&TypeId::of::<M>())
.and_then(|ctx| ctx.downcast_ref())
}
pub fn current_value<M: ContextMarker>(&self) -> Option<M::Value> {
self.value::<M>(self.current_env())
}
pub fn value<M: ContextMarker>(&self, env: &EnvType) -> Option<M::Value> {
self.context::<M>().and_then(|ctx| ctx.get_for_env(env))
}
}
#[derive(Default)]
pub struct EnvironmentBuilder {
current: Option<EnvType>,
contexts: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
}
impl EnvironmentBuilder {
pub fn current_env(mut self, env: EnvType) -> Self {
self.current = Some(env);
self
}
pub fn current_from<T>(mut self, config: T) -> Self
where
EnvType: From<T>,
{
self.current = Some(EnvType::from(config));
self
}
pub fn with_context<M: ContextMarker>(mut self, context: Context<M>) -> Self {
self.contexts.insert(TypeId::of::<M>(), Arc::new(context));
self
}
pub fn build(self) -> Result<Environment, EnvError> {
let current = self.current.ok_or(EnvError::NoCurrentEnv)?;
Ok(Environment {
current,
contexts: self.contexts,
})
}
}