Crate metafactory[stability] [-]  [+] [src]

Fork me on GitHub

MetaFactory can be used to construct value creation chains from closures or other sources that produce values.

Let's look at really small example first:

 use metafactory::{ metafactory, argless_as_factory, AsFactoryExt };

 fn main() {
     let meta_sum = metafactory(
         |a: int, b: int| a + b
     );

     let sum_factory = meta_sum.new(vec![
         argless_as_factory(5i),
         argless_as_factory(6i),
     ]).ok().unwrap();

     let getter = sum_factory.as_factory_of::<int>().unwrap();

     assert_eq!(getter.take(), 11);
 }

What is going on? Well, first we use metafactory generic function to convert arbitrary closure to MetaFactory object meta_sum.

It has a method new, which is used above to return a real concrete factory sum_factory. As argument, it takes other factories. The method argless_as_factory() returns factories for clonable values 5i and 6i.

So, metafactories can be created from different sources: clonable objects or closures. In this case 5i is a clonable object.

Returned sum_factory has a Box<Any> type, and can be downcasted to a Factory of appropriate type with as_factory_of method.

Then you can call take() on this factory getter to invoke your closure and return a new value.

Note a lot of unwrap calls. All the potential argument or type mismatches produce correct errors that can be dealt with.

Now, the example above might seem a bit involved, but consider what it allows us to do: provided argument counts and types match, we can connect any chain of factories together, at runtime.

Let's expand example to add a new factory that uses sum_factory as an argument, and creates our own struct:

 use metafactory::{ metafactory, argless_as_factory, AsFactoryExt };

 /// Our own struct.
 struct Foo {
     value: int,
 }

 fn main() {
     // initialization

     let meta_sum = metafactory(
         |a: int, b: int| a + b
     );

     let meta_foo = metafactory(
         |sum: int| Foo { value: sum }
     );

     // plugging in

     let foo_factory = meta_foo.new(vec![
         meta_sum.new(vec![
             argless_as_factory(5i),
             argless_as_factory(6i),
         ]).ok().unwrap()
     ]).ok().unwrap();

     // using

     let getter = foo_factory.as_factory_of::<Foo>().unwrap();

     assert_eq!(getter.take().value, 11);
 }

So, the intention of this library is to have a mechanism to separate 3 things: creating the values, plugging-in the factories values, and using them.

Created metafactories can also be used to inspect closure argument types. It is also possible to clone the created factory: in such case, all the call tree is also cloned internally. This makes it possible to pass a copy of a factory to a task.

Factories intentionally do not produce any kind of singletons or references, only new values. You can also look at them as configurable stream of values.

If this library looks a bit lower-level, it is because it is intended as such: more convenient wrappers like dependency injection or plugin architecture can be implemented on top of this.

Finally, a more complete example of available functionality:

 use metafactory::{ metafactory, AsFactoryExt };

 fn main() {
     // build argument-factory from cloneable source.
     let meta_arg1 = metafactory(5i);

     // build argument-factory from lambda.
     let meta_arg2 = metafactory(|| 14i32);

     // build a factory that uses other factories create added numbers.
     let meta_adder = metafactory(|a1: int, a2: i32| a1 + a2 as int);

     // it knows the cloneable source returns int
     assert!(meta_arg1.get_type().is::<int>());
     // it knows the lambda source returns i32
     assert!(meta_arg2.get_type().is::<i32>());
     // it knows the lambda with 2 args returns int
     assert!(meta_adder.get_type().is::<int>());

     // create a factory for adder, pass other 2 factories as arguments
     let boxany = meta_adder.new(vec![
         meta_arg1.new(Vec::new()).ok().unwrap(),
         meta_arg2.new(Vec::new()).ok().unwrap(),
     ]).ok().unwrap();

     // conveniently downcast factory to callable instance
     let factory = boxany.as_factory_of::<int>().unwrap();

     // value should be the sum.
     assert_eq!(19, factory.take());

     // factory can be cloned
     let factory2 = factory.clone();

     // both clones invoke the same construction path and return the same value
     assert_eq!(factory.take(), factory2.take());
 }

Modules

aggregate

Implements a factory that aggregates the results of other factories of the same type.

error

Closure argument error types.

Structs

Factory

A factory proxy.

Traits

AsFactoryExt

Downcast value to Factory.

Getter

Gettable value trait.

MetaFactory

Implements reflection and initiation of any abstract object constructor.

ToMetaFactory

Trait for values convertable to MetaFactory.

Functions

argless_as_factory

Create a new MetaFactory and return Factory in Box<Any> for source with no arguments.

metafactory

Create a new MetaFactory for any compatible value source.