xdi
Simple service dependency graph container implementation
-
Allow resolve nested service dependency graph
-
Support Transient
-
Support Singletone
-
Support Task local (singletone in task scope)
-
Support Thread local (singletone in thread scope)
-
Allow to map service into any other representation as simple like
.map_as(|service| SomeOther { x: service.x }) -
Allow to map service into trait object as siple like
.map_as_trait::<dyn SomeTrait>() -
Resolve single (first) service by self or by any mapping
-
Resolve all service wich has requested representation, usefull for trait object
-
Non blocking for transient, single lock for singletone/task_local/thread_local init
-
Allow
!Send+!Syncfor transient and thread_local -
Readable errors
-
Simple architecture (constructor -> scope -> mapping)
-
Allow global
ServiceProviderregistration -
Main test cases allowed in tests folder
use DiBuilder;
use ;
How to use
Create container builder
let builder = new;
// or
let builder = default;
Register the service
- Mutable access not required, builder can be shared by ref
- Registration fn takes used ServiceProvider and can resolve nested dependency
As transient
- Create new instance every call
- Allowed !Send + !Sync
builder.transient;
builder.transient;
As singletone
- Lazy creation on the first invocation and return a clone on every next invocation
- Singletone required clone for service (you can wrap to Arc or derive Clone)
- Singletone required Sync + Send because it can be shared anywhere
builder.singletone;
As task local
- Lazy creation on the first invocation from the task scope and return a clone on every next invocation in same task scope
- Task local required clone for service (you can wrap to Arc or derive Clone)
- Task local required Sync + Send because it can be shared anywhere
As thread local
- Lazy creation on the first invocation from the thread scope and return a clone on every next invocation in same thread scope
- Thread local required clone for service (you can wrap to Rc or derive Clone)
- Allowed !Send + !Sync
builder.thread_local;
Injection
You can inject service as fn constructor
All type ctors will be automatically registered on builder.inject() call
Injection use inventory, so you can add injection from dependency crate
// As transient (for transient scope param can be omitted)
// As singleton
// As thread local
// As task local
// For every scope you can define multiple trait map
Map service
- Mapping allow add new service representation for same constructor
- Mapping (Service -> Service) auto-generated
- You can add as many mappings for a single service as you need
Custom map
builder.transient
.map_as;
Trait object map
- Create mapping to
Box<dyn ISomeTrait>if service impl ISomeTrait
builder.transient
.;
Build container
- You can build container as var, or register global
Build container as var
let sp = builder.build;
Build and register global
builder.build_global;
// then access by static global var
let service = get.unwrap..unwrap;
Resolve service by mapping
As service
let service: SomeService = sp.resolve.unwrap;
// let service: Box<dyn ISomeTrait> = sp.resolve().unwrap();
As boxed service
use TypeInfoSource;
let service = sp.resolve_raw.unwrap;
// let service = sp.resolve(Box::<dyn ISomeTrait>::type_info()).unwrap();
let service = service..unwrap;
// let service = service.unbox::<Box<dyn ISomeTrait>>().unwrap();
As vector of services, which has some mapping
builder.transient
.;
builder.transient
.;
let services: = sp.resolve_all.unwrap;
As vector of boxed services, which has some mapping
use ;
builder.transient
.;
builder.transient
.;
let services: = sp.resolve_all_raw.unwrap;
As dependency in task scope