|
|
|
@ -1,7 +1,7 @@ |
|
|
|
|
use super::component::Component; |
|
|
|
|
use super::model_i::{Context, FromContext}; |
|
|
|
|
|
|
|
|
|
use std::any::{Any, type_name}; |
|
|
|
|
use std::any::{type_name, Any}; |
|
|
|
|
|
|
|
|
|
trait ComponentFactory { |
|
|
|
|
type Input; |
|
|
|
@ -14,11 +14,102 @@ trait ContextComponentFactory: ComponentFactory { |
|
|
|
|
fn build_from_context(&self, context: &Context) -> Result<Self::Output, String>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl <T:Any + Sized + 'static, O, CF: ComponentFactory<Input=Component<T>, Output=O>> ContextComponentFactory for CF { |
|
|
|
|
impl<T: Any + Sized + 'static, O, CF: ComponentFactory<Input = Component<T>, Output = O>> |
|
|
|
|
ContextComponentFactory for CF |
|
|
|
|
{ |
|
|
|
|
fn build_from_context(&self, context: &Context) -> Result<Self::Output, String> { |
|
|
|
|
let input = FromContext::from(context).ok_or_else(|| format!("Could not find retrieve component of type {} from context", type_name::<T>()))?; |
|
|
|
|
let input = FromContext::from(context).ok_or_else(|| { |
|
|
|
|
format!( |
|
|
|
|
"Could not find retrieve component of type {} from context", |
|
|
|
|
type_name::<T>() |
|
|
|
|
) |
|
|
|
|
})?; |
|
|
|
|
self.build(input) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[macro_export] |
|
|
|
|
macro_rules! derive_ccf { |
|
|
|
|
($CF:ty; $( $T:ty ),* ) => { |
|
|
|
|
impl ContextComponentFactory for $CF { |
|
|
|
|
fn build_from_context(&self, context: &Context) -> Result<Self::Output, String> { |
|
|
|
|
let input = from_context!(context; $($T),*); |
|
|
|
|
self.build(input) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[macro_export] |
|
|
|
|
macro_rules! from_context { |
|
|
|
|
($context:expr; $( $T:ty ),* ) => { |
|
|
|
|
( |
|
|
|
|
$( |
|
|
|
|
FromContext::from($context).ok_or_else(|| { |
|
|
|
|
format!( |
|
|
|
|
"Could not find retrieve component of type {} from context", |
|
|
|
|
type_name::<$T>() |
|
|
|
|
) |
|
|
|
|
})?, |
|
|
|
|
)* |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod tests { |
|
|
|
|
use super::*; |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq)] |
|
|
|
|
struct A(&'static str); |
|
|
|
|
#[derive(Debug, Eq, PartialEq)] |
|
|
|
|
struct B(u32); |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_from_context_macro() { |
|
|
|
|
// Given
|
|
|
|
|
fn get_input(context: &Context) -> Result<(Component<A>, Component<B>), String> { |
|
|
|
|
Ok(from_context!(context; A, B)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mut context = Context::new(); |
|
|
|
|
context.set(A("Test")); |
|
|
|
|
context.set(B(67)); |
|
|
|
|
|
|
|
|
|
// When
|
|
|
|
|
let (comp_a, comp_b) = get_input(&context).unwrap(); |
|
|
|
|
|
|
|
|
|
// Then
|
|
|
|
|
assert_eq!(*comp_a.borrow(), A("Test")); |
|
|
|
|
assert_eq!(*comp_b.borrow(), B(67)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq)] |
|
|
|
|
struct C(&'static str, u32); |
|
|
|
|
|
|
|
|
|
struct CFactory; |
|
|
|
|
impl ComponentFactory for CFactory { |
|
|
|
|
type Input = (Component<A>, Component<B>); |
|
|
|
|
type Output = C; |
|
|
|
|
|
|
|
|
|
fn build(&self, (comp_a, comp_b): Self::Input) -> Result<Self::Output, String> { |
|
|
|
|
Ok(C(comp_a.borrow().0, comp_b.borrow().0)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_derive_ccf_macro() { |
|
|
|
|
// Given
|
|
|
|
|
derive_ccf!(CFactory; A, B); |
|
|
|
|
let c_factory = CFactory; |
|
|
|
|
let mut context = Context::new(); |
|
|
|
|
context.set(A("test")); |
|
|
|
|
context.set(B(67)); |
|
|
|
|
|
|
|
|
|
// When
|
|
|
|
|
let c = c_factory.build_from_context(&context).unwrap(); |
|
|
|
|
|
|
|
|
|
assert_eq!(c, C("test", 67)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|