use std::any::type_name;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::ops::Deref;
use std::rc::Rc;
use super::component::{Component, ContextComponentExtension};
use super::context::Context;
use super::error::{AlreadyRegisteredError, Error, NotRegisteredError};
pub trait FromContext<T: 'static> {
fn from_context(&self, context: &mut Context) -> Result<T, Error>;
}
impl<T: 'static, FN: Fn(&mut Context) -> Result<T, Error>> FromContext<T> for FN {
fn from_context(&self, context: &mut Context) -> Result<T, Error> {
self(context)
}
}
pub struct Factory<T: 'static>(Rc<dyn FromContext<T>>);
impl<T: 'static> Debug for Factory<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "Factory for component of type {}", type_name::<T>())
}
}
impl<T: 'static> Factory<T> {
pub fn from<FC: FromContext<T> + 'static>(from_context: FC) -> Self {
Factory(Rc::new(from_context))
}
}
impl<T: 'static> Clone for Factory<T> {
fn clone(&self) -> Self {
Factory(self.0.clone())
}
}
impl<T: 'static> Deref for Factory<T> {
type Target = dyn FromContext<T>;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
pub trait ContextFactoryExtension {
fn get_factory<T: 'static>(&self) -> Option<Factory<T>>;
fn register_factory<T: 'static>(
&mut self,
factory: Factory<T>,
) -> Result<(), (AlreadyRegisteredError, Factory<T>)>;
fn replace_factory<T: 'static>(
&mut self,
factory: Factory<T>,
) -> Result<Factory<T>, (NotRegisteredError, Factory<T>)>;
fn build<T: 'static>(&mut self) -> Result<T, Error>;
fn build_and_register_component<T: 'static>(&mut self) -> Result<Component<T>, Error>;
fn get_or_build_component<T: 'static>(&mut self) -> Result<Component<T>, Error>;
}
impl ContextFactoryExtension for Context {
fn get_factory<T: 'static>(&self) -> Option<Factory<T>> {
self.get().cloned()
}
fn register_factory<T: 'static>(
&mut self,
factory: Factory<T>,
) -> Result<(), (AlreadyRegisteredError, Factory<T>)> {
if self.get::<Factory<T>>().is_none() {
self.set(factory);
Ok(())
} else {
Err((AlreadyRegisteredError::of_type::<Factory<T>>(), factory))
}
}
fn replace_factory<T: 'static>(
&mut self,
mut factory: Factory<T>,
) -> Result<Factory<T>, (NotRegisteredError, Factory<T>)> {
match self.get_mut::<Factory<T>>() {
Some(mut_ref) => {
std::mem::swap(mut_ref, &mut factory);
Ok(factory)
}
None => Err((NotRegisteredError::of_type::<Factory<T>>(), factory)),
}
}
fn build<T: 'static>(&mut self) -> Result<T, Error> {
match self.get_factory::<T>() {
Some(factory) => factory.from_context(self),
None => Err(Error::NotRegistered(NotRegisteredError::of_type::<
Factory<T>,
>())),
}
}
fn build_and_register_component<T: 'static>(&mut self) -> Result<Component<T>, Error> {
if self.get_component::<T>().is_some() {
return Err(Error::AlreadyRegistered(AlreadyRegisteredError::of_type::<
Component<T>,
>()));
}
match self.build::<T>() {
Ok(t) => self
.register_component(t)
.map_err(|(error, _)| Error::AlreadyRegistered(error)),
Err(error) => Err(error),
}
}
fn get_or_build_component<T: 'static>(&mut self) -> Result<Component<T>, Error> {
if let Some(component) = self.get_component::<T>() {
Ok(component)
} else {
self.build_and_register_component()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_factory() {
#[derive(Debug)]
struct Config {
initial_count: u32,
};
#[derive(Debug)]
struct Counter(u32);
let mut context = Context::default();
let config_factory = Factory::from(|_: &mut Context| Ok(Config { initial_count: 5 }));
context.register_factory(config_factory).unwrap();
let counter_factory = Factory::from(|context: &mut Context| {
let config_component = context.get_or_build_component::<Config>()?;
let initial_count = config_component.borrow().initial_count;
Ok(Counter(initial_count))
});
context.register_factory(counter_factory).unwrap();
let counter_component = context.get_or_build_component::<Counter>().unwrap();
let config_component = context.get_component::<Config>().unwrap();
assert_eq!(counter_component.borrow().0, 5);
assert_eq!(config_component.borrow().initial_count, 5);
}
}