1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
//! Implements a factory that aggregates the results of other factories of //! the same type. use std::any::{ Any }; use std::boxed::BoxAny; use typedef::TypeDef; use { Factory, Getter }; /// Proxy for initializing aggregate factory without caring about the type used. /// /// Its intended use is as a container of factories that produce a /// value of the same type. Then it can itself be used to create a new factory /// that aggregates values from all its childs and returns all of them /// in a `Vec<T>` type for single `take`. /// /// The most convenient way to initialize a new aggregate is to use /// `new_aggregate` method on a metafactory. It will make a correctly typed /// aggregate based on the metafactory type. /// /// ``` /// # extern crate metafactory; /// use metafactory::{ metafactory, AsFactoryExt }; /// /// fn main() { /// let true_metafactory = metafactory(|| true); /// let false_metafactory = metafactory(|| false); /// /// // Use any of metafactories to create an aggregate for bool. /// let mut aggregate = false_metafactory.new_aggregate(); /// /// // We can then add both factories to the aggregate. /// // and make a factory from aggregate. /// let true_and_false = aggregate /// .new_factory(vec![ /// true_metafactory.new(Vec::new()).ok().unwrap(), /// false_metafactory.new(Vec::new()).ok().unwrap(), /// ]) /// .as_factory_of::<Vec<bool>>().unwrap(); /// /// assert_eq!(vec![true, false], true_and_false.take()); /// } /// ``` /// /// The example bellow show how to initialize and use aggregate without a /// metafactory. /// /// ``` /// # extern crate metafactory; /// use std::any::Any; /// use metafactory::{ metafactory, argless_as_factory, AsFactoryExt }; /// use metafactory::aggregate::Aggregate; /// /// fn main() { /// // Let's say we know that we will have bunch of `bool` factories. /// // In that case we create a new aggregate for them: /// let mut aggregate = Aggregate::new::<bool>(); /// /// // Once we actually have our factories, we can inject them into aggregate /// // without dealing with types. Of course, we should make sure that types /// // actually match before doing that in the code that is using this /// // implementation. /// // Then we can call `new_factory` to convert all dynamic stuff to /// // statically constructed call hierarchy: /// let anyed_bool_array_factory = aggregate /// .new_factory(vec![ /// argless_as_factory(|| true), /// argless_as_factory(true), /// argless_as_factory(|| 4i == 8), /// ]); /// /// // Of course, that returns it anyed (`Box<Any>`), but we can easily get un-anyed version /// // by downcasting to `Factory<Vec<bool>>` or using a convenience extension /// // method for that: /// let bool_array_factory = anyed_bool_array_factory /// .as_factory_of::<Vec<bool>>().unwrap(); /// /// // Calling it should produce expected boolean vector: /// assert_eq!(bool_array_factory.take(), vec![true, true, false]); /// /// // Of course, the aggregate itself should be usable as argument /// // for other factories: /// let metafactory_all_true = metafactory(|values: Vec<bool>| { /// values.iter().fold(true, |a, &i| a & i) /// }); /// /// // We can pass it when constructing a factory for this lambda metafactory: /// let factory_all_true = metafactory_all_true.new(vec![ /// box bool_array_factory.clone() as Box<Any> /// ]) /// .ok().unwrap() // check for errors here /// .as_factory_of::<bool>().unwrap() // same story with downcasting /// ; /// /// assert_eq!(factory_all_true.take(), false); // not all values are true /// } /// ``` pub struct Aggregate<'a> { typedef: TypeDef, container_typedef: TypeDef, do_new: Box<Fn<(Vec<Box<Any>>,),Box<Any>> + 'a>, } impl<'a> Aggregate<'a> { /// Create new aggregate instance for specified type. pub fn new<T: 'static>() -> Aggregate<'a> { Aggregate { typedef: TypeDef::of::<T>(), container_typedef: TypeDef::of::<Vec<T>>(), do_new: box |&: items: Vec<Box<Any>>| { box Factory::<Vec<T>>::new( box AG::<T>::new( items.into_iter() .map(|i| *i.downcast::<Factory<T>>().ok().expect( format!("failed to downcast factory child to Factory<{}>", TypeDef::name_of::<T>()).as_slice() )) .collect() ) ) } } } /// Return aggregated type. pub fn get_arg_type(&self) -> TypeDef { self.typedef.clone() } /// Return container type. pub fn get_container_type(&self) -> TypeDef { self.container_typedef.clone() } /// Produces factory usable as argument for other factories. /// /// If inner factories make `int` values, this method will make factory /// that makes `Vec<int>` values. pub fn new_factory(&self, items: Vec<Box<Any>>) -> Box<Any> { (self.do_new).call((items,)) } } struct AG<T: 'static> { factories: Vec<Factory<T>>, } impl<T> Clone for AG<T> { fn clone(&self) -> AG<T> { AG::<T> { factories: self.factories.clone() } } } impl<T> AG<T> { pub fn new(factories: Vec<Factory<T>>) -> AG<T> { AG::<T> { factories: factories } } } impl<T> Getter<Vec<T>> for AG<T> { fn take(&self) -> Vec<T> { // Reserve exact result size. let mut items = Vec::<T>::with_capacity(self.factories.len()); // Construct results from factory results. items.extend( self.factories.iter() .map(|f| f.take()) ); items } fn boxed_clone(&self) -> Box<Getter<Vec<T>> + 'static> { box self.clone() } } #[cfg(test)] mod test { use { argless_as_factory, metafactory, AsFactoryExt }; use super::{ Aggregate }; #[test] fn should_be_usable_as_vec_of_types() { let container = Aggregate::new::<int>(); let parent_metafactory = metafactory( |items: Vec<int>| items.into_iter() .map(|i| format!("{}", i)) .collect::<Vec<String>>() .connect(", ") ); let parent_getter = parent_metafactory .new(vec![ container.new_factory( vec![ argless_as_factory(5i), argless_as_factory(13i) ] ) ]).ok().unwrap() .as_factory_of::<String>().unwrap() ; assert_eq!(parent_getter.take(), "5, 13"); } }