Struct teloc::ServiceProvider [−][src]
pub struct ServiceProvider<Parent, Conts> { /* fields omitted */ }
Expand description
ServiceProvider
struct is used as an IoC-container in which you declare your dependencies.
Algorithm for working in ServiceProvider
is:
- Create an empty by
ServiceProvider::new
function. - Declare your dependencies using
add_*
methods (more about theirs read below). - Fork
ServiceProvider
when you need working with scoped sessions (like when you processing web request). - Get needed dependencies from container using
Resolver::resolve
trait.
If you do not register all of needed dependencies, then compiler do not compile your code. If error puts you into a stupor, read our manual about how read errors.
Example of usage ServiceProvider
:
use std::rc::Rc;
use teloc::*;
struct ConstService {
number: Rc<i32>,
}
#[inject]
impl ConstService {
pub fn new(number: Rc<i32>) -> Self {
ConstService { number }
}
}
#[derive(Dependency)]
struct Controller {
number_service: ConstService,
}
let container = ServiceProvider::new()
.add_transient::<ConstService>()
.add_transient::<Controller>();
let scope = container.fork().add_instance(Rc::new(10));
let controller: Controller = scope.resolve();
assert_eq!(*controller.number_service.number, 10);
Implementations
Forking ServiceProvider
creates a new ServiceProvider
with reference to the parent.
resolve
method on forked ServiceProvider
will find dependencies form self and parent.
Forking ServiceProvider
creates a new ServiceProvider
with reference to the parent.
resolve
method on forked ServiceProvider
will find dependencies form self and parent.
pub fn fork_arc(
self: &Arc<ServiceProvider<Parent, Conts>>
) -> ServiceProvider<Arc<Self>, HNil>
pub fn fork_arc(
self: &Arc<ServiceProvider<Parent, Conts>>
) -> ServiceProvider<Arc<Self>, HNil>
Forking ServiceProvider
creates a new ServiceProvider
with reference to the parent.
resolve
method on forked ServiceProvider
will find dependencies form self and parent.
pub fn _add<Cont: Container>(
self,
data: Cont::Data
) -> ServiceProvider<Parent, HCons<Cont, Conts>>
pub fn _add<Cont: Container>(
self,
data: Cont::Data
) -> ServiceProvider<Parent, HCons<Cont, Conts>>
Method used primary for internal actions. In common usage you don’t need to use it. It add dependencies to the store. You need
to put in first generic parameter some ContainerElem
type.
Usage:
use teloc::*;
use teloc::dev::container::TransientContainer;
struct Service {
data: i32,
}
let sp = ServiceProvider::new()
._add::<TransientContainer<Service>>(());
pub fn add_transient<T>(
self
) -> ServiceProvider<Parent, HCons<TransientContainer<T>, Conts>> where
TransientContainer<T>: Container<Data = ()>,
pub fn add_transient<T>(
self
) -> ServiceProvider<Parent, HCons<TransientContainer<T>, Conts>> where
TransientContainer<T>: Container<Data = ()>,
Add dependency with the Transient
lifetime. Transient services will be created each time
when it called. Use this lifetime for lightweight stateless services.
Can be resolved only by ownership.
Usage:
use teloc::*;
use uuid::Uuid;
struct Service { uuid: Uuid }
#[inject]
impl Service {
fn new() -> Self { Self { uuid: Uuid::new_v4() } }
}
let sp = ServiceProvider::new()
.add_transient::<Service>();
let s1: Service = sp.resolve();
let s2: Service = sp.resolve();
assert_ne!(s1.uuid, s2.uuid);
pub fn add_singleton<T>(
self
) -> ServiceProvider<Parent, HCons<SingletonContainer<T>, Conts>> where
SingletonContainer<T>: Container<Data = ()>,
pub fn add_singleton<T>(
self
) -> ServiceProvider<Parent, HCons<SingletonContainer<T>, Conts>> where
SingletonContainer<T>: Container<Data = ()>,
Add dependency with the Singleton
lifetime. Singleton services will be created only one
time when it will be called first time. It will be same between different calls in parent
and forked ServiceProvider
Can be resolved by reference or by cloning. If you wish to clone this dependency then it
must implement DependencyClone
trait. For more information see DependencyClone
trait.
Usage:
use teloc::*;
use uuid::Uuid;
struct Service { uuid: Uuid }
#[inject]
impl Service {
fn new() -> Self { Self { uuid: Uuid::new_v4() } }
}
let sp = ServiceProvider::new()
.add_singleton::<Service>();
let scope = sp.fork();
let s1: &Service = sp.resolve();
let s2: &Service = scope.resolve();
assert_eq!(s1.uuid, s2.uuid);
Usage with cloning:
use teloc::*;
use uuid::Uuid;
use std::rc::Rc;
struct Service { uuid: Uuid }
#[inject]
impl Service {
fn new() -> Self { Self { uuid: Uuid::new_v4() } }
}
let sp = ServiceProvider::new()
.add_singleton::<Rc<Service>>();
let s1: Rc<Service> = sp.resolve();
let s2: Rc<Service> = sp.resolve();
assert_eq!(s1.uuid, s2.uuid)
pub fn add_instance<T>(
self,
data: T
) -> ServiceProvider<Parent, HCons<InstanceContainer<T>, Conts>> where
InstanceContainer<T>: Container<Data = T>,
pub fn add_instance<T>(
self,
data: T
) -> ServiceProvider<Parent, HCons<InstanceContainer<T>, Conts>> where
InstanceContainer<T>: Container<Data = T>,
Add anything instance to provider. It likes singleton, but it cannot get dependencies from the provider. Use it for adding single objects like configs.
Can be resolved by reference or by cloning. If you wish to clone this dependency then it
must implement DependencyClone
trait. For more information see DependencyClone
trait.
Usage:
use teloc::*;
#[derive(Debug, PartialEq)]
struct Config { token: String, ip: String }
struct Service<'a> { token: &'a str, ip: &'a str }
#[inject]
impl<'a> Service<'a> {
fn new(config: &'a Config) -> Self { Self { token: &config.token, ip: &config.ip } }
}
let config = Config { token: "1234ABCDE".into(), ip: "192.168.0.1".into() };
let sp = ServiceProvider::new()
.add_instance(&config)
.add_transient::<Service>();
let config_ref: &Config = sp.resolve();
let s: Service = sp.resolve();
assert_eq!(&config, config_ref);
assert_eq!(&config_ref.token, s.token);
assert_eq!(&config_ref.ip, s.ip);
pub fn add_transient_c<U, T>(
self
) -> ServiceProvider<Parent, HCons<ConvertContainer<TransientContainer<T>, T, U>, Conts>> where
T: Into<U>,
ConvertContainer<TransientContainer<T>, T, U>: Container<Data = ()>,
TransientContainer<T>: Container<Data = ()>,
pub fn add_transient_c<U, T>(
self
) -> ServiceProvider<Parent, HCons<ConvertContainer<TransientContainer<T>, T, U>, Conts>> where
T: Into<U>,
ConvertContainer<TransientContainer<T>, T, U>: Container<Data = ()>,
TransientContainer<T>: Container<Data = ()>,
Same as ServiceProvider::add_transient
, but can be used for convert one type to another
when resolving. Can be used for creating Box<dyn Trait>
instances, for example.
Suffix _c
means ‘convert’.
Usage:
use teloc::*;
trait NumberService {
fn get_num(&self) -> i32;
}
struct TenService {
number: i32,
}
impl NumberService for TenService {
fn get_num(&self) -> i32 {
self.number
}
}
#[inject]
impl TenService {
fn new() -> Self {
Self { number: 10 }
}
}
impl From<Box<TenService>> for Box<dyn NumberService> {
fn from(x: Box<TenService>) -> Self {
x
}
}
#[derive(Dependency)]
struct Controller {
number_service: Box<dyn NumberService>,
}
let container = ServiceProvider::new()
.add_transient_c::<Box<dyn NumberService>, Box<TenService>>()
.add_transient::<Controller>();
let controller: Controller = container.resolve();
assert_eq!(controller.number_service.get_num(), 10);
pub fn add_singleton_c<U, T>(
self
) -> ServiceProvider<Parent, HCons<ConvertContainer<SingletonContainer<T>, T, U>, Conts>> where
T: Into<U>,
ConvertContainer<SingletonContainer<T>, T, U>: Container<Data = ()>,
SingletonContainer<T>: Container<Data = ()>,
pub fn add_singleton_c<U, T>(
self
) -> ServiceProvider<Parent, HCons<ConvertContainer<SingletonContainer<T>, T, U>, Conts>> where
T: Into<U>,
ConvertContainer<SingletonContainer<T>, T, U>: Container<Data = ()>,
SingletonContainer<T>: Container<Data = ()>,
Same as Provider::add_transient_c
but for Singleton
lifetime.
pub fn add_instance_c<U, T>(
self,
instance: T
) -> ServiceProvider<Parent, HCons<ConvertContainer<InstanceContainer<T>, T, U>, Conts>> where
T: Into<U>,
ConvertContainer<InstanceContainer<T>, T, U>: Container<Data = T>,
InstanceContainer<T>: Container<Data = T>,
pub fn add_instance_c<U, T>(
self,
instance: T
) -> ServiceProvider<Parent, HCons<ConvertContainer<InstanceContainer<T>, T, U>, Conts>> where
T: Into<U>,
ConvertContainer<InstanceContainer<T>, T, U>: Container<Data = T>,
InstanceContainer<T>: Container<Data = T>,
Same as Provider::add_transient_c
but for Instance
lifetime.