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");
    }
}