Getting Started
The simplest way to get started is to install the crate using the default features.
cargo add more-di
Example
Let's build the ubiquitous Hello World application. The first thing we need to do is define some traits and structures. We'll use #[injectable]
, which is highly convenient, but not strictly required.
use di::*;
use std::rc::Rc;
// let Bar make itself injectable as Bar
#[injectable]
pub struct Bar;
impl Bar {
pub fn speak(&self) -> &str {
"Hello world!"
}
}
pub trait Foo {
pub fn speak(&self) -> &str;
}
// let FooImpl make itself injectable as dyn Foo
#[injectable(Foo)]
pub struct FooImpl {
bar: Rc<Bar> // ← assigned by #[injectable]
}
impl Foo for FooImpl {
fn speak(&self) -> &str {
self.bar.speak()
}
}
pub trait Thing {}
// let Thing1 make itself injectable as dyn Thing
#[injectable(Thing)]
pub struct Thing1;
impl Thing for Thing1 {}
// let Thing2 make itself injectable as dyn Thing
#[injectable(Thing)]
pub struct Thing2;
impl Thing for Thing2 {}
Now that we have a few injectable types, we can build a basic application.
use crate::*;
use di::*;
fn main() {
// create a collection of registered services. the order of
// registration does not matter.
let services = ServiceCollection::new()
.add(FooImpl::transient())
.add(Bar::singleton())
.add(Thing1::transient());
.add(Thing2::transient());
// build an immutable service provider from the collection
// of services. validation is performed here to ensure
// the provider is a good state. if we're not, then a
// ValidationError will indicate what the problems are.
// if, for example, we forgot to register Bar, an error
// would be returned indicating that Bar is missing.
let provider = services.build_provider().unwrap();
// get the requested service or panic
let foo = provider::get_required::<dyn Foo>();
println!("Foo says '{}'.", foo.speak());
// get all of the requested services, which could be zero
let things: Vec<_> = provider::get_all::<Thing>().collect();
println!("Number of things: {}", things.len());
}