dilib-rs
A dependency injection library for Rust.
Usage
[]
= "0.2.0"
Example
Basic Usage
use Container;
;
;
;
let mut container = new;
container.add_singleton.unwrap;
container.add_scoped.unwrap;
container.add_scoped_with_name.unwrap;
let printer = container..unwrap;
let en = container..unwrap;
let es = container..unwrap;
printer.print;
printer.print;
Table of Contents
Container
The container is the main storage for the 2 types of provides:
Scoped: creates a new instance each timeSingleton: returns the same instance each time
All these providers can be named using the methods ended with with_name(...).
Scoped provider
The scoped providers creates a new instance each time they are called.
use Container;
let mut container = new;
container.add_scoped.unwrap;
let s = container..unwrap;
assert_eq!;
Singleton provider
The singleton providers returns the same instance each time they are called.
use Container;
use Mutex;
let mut container = new;
container.add_singleton.unwrap;
let c2 = container..unwrap;
assert_eq!;
Inject trait
The Inject trait is a mechanism to create a type using the
providers of a container.
To add a type that implements Inject to the container,
you use the add_deps methods, this adds the type as a Scoped provider.
use ;
use ;
;
let mut container = new;
container.add_singleton.unwrap;
container.add_scoped_with_name.unwrap;
container..unwrap;
let f1 = container..unwrap;
let f2 = container..unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Bind trait to implementation
To add a trait to a container you should bind the trait to its implementation using the macros:
add_scoped_trait!(container, name, trait => impl)add_singleton_trait!(container, name, trait => impl)add_scoped_trait!(container, name, trait @ Inject)add_singleton_trait!(container, name, trait @ Inject)
The
nameis optional.
This adds the trait as a Box<dyn Trait>.
And you can get the values back using:
get_scoped_trait!(container, name, trait)get_singleton_trait!(container, name, trait)get_resolved_trait(container, name, trait)
The
nameis also optional.
This returns the trait as a Box<dyn Trait>.
use ;
;
;
;
let mut container = new;
add_singleton_trait!.unwrap;
add_scoped_trait!.unwrap;
add_scoped_trait!.unwrap;
// All types are returned as `Box<dyn Trait>`
let discount = get_resolved_trait!.unwrap;
let apple = get_resolved_trait!.unwrap;
let orange = get_resolved_trait!.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
get, get_scoped and get_singleton
There are 3 ways to retrieve a value from the container:
getget_scopedget_singleton
And it's named variants:
get_with_nameget_scoped_with_nameget_singleton_with_name
get_scoped and get_singleton are self-explanatory, they get
a value from a scoped or singleton provider.
But get can get any scoped and singleton value,
the difference is that get returns a Resolved<T>
and the others returns a T (scoped) or Arc<T> (singletons).
Resolved<T> is just an enum for a Scoped(T) and Singleton(Arc<T>)
where you can convert it back using into_scoped or into_singleton,
it also implements Deref over T.
Derive Inject
This requires the
derivefeature.
Inject is implemented for all types that implement Default
and can be auto-implemented using #[derive]. When using the derive
types Arc<T> and Singleton<T> will be injected as singleton,
and other types as scoped unless specified.
use ;
use *;
let mut container = new;
container.add_singleton_with_name.unwrap;
container.add_scoped_with_name.unwrap;
container.;
let apple = container..unwrap;
assert_eq!;
assert_eq!;
Global Container
This requires the
globalfeature.
dilib also offers a global container so you don't require
to declare your own, you can access the values of the container
using get_scoped!, get_singleton!or get_resolved!,
you can also access the container directly using get_container().
use ;
init_container.expect;
let orange = resolve!.unwrap;
let num = resolve!.unwrap;
assert_eq!;
assert_eq!;
Provide
This requires the
unstable_providefeature.
Why unstable_provide?
The feature unstable_provide make possible to have dependency
injection more similar to other frameworks like C# EF Core or Java Spring.
To allow run code before main we use the the ctor crate, which have been tested in several OS so is stable for most of the use cases.
provide macro
You can use the #[provide] macro over any function or type that implements
**Inject to register it to the global container.
use RwLock;
use init_container;
use ;
;
;
// Initialize the container to register the providers
init_container.unwrap;
let user_repository = resolve!;
user_repository.add;
let users = user_repository.get_all;
let db = resolve!.unwrap;
println!;
println!;