Struct ServiceProvider

Source
pub struct ServiceProvider<Parent, Conts> { /* private fields */ }
Expand description

ServiceProvider struct is used as an IoC-container in which you declare your dependencies.

Algorithm for working in ServiceProvider is:

  1. Create an empty by ServiceProvider::new function.
  2. Declare your dependencies using add_* methods (more about theirs read below).
  3. Fork ServiceProvider when you need working with scoped sessions (like when you processing web request).
  4. 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§

Source§

impl ServiceProvider<EmptyServiceProvider, HNil>

Source

pub fn new() -> Self

Create an empty instance of ServiceProvider

Source§

impl<Parent, Conts> ServiceProvider<Parent, Conts>

Source

pub fn fork(&self) -> ServiceProvider<&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.

Source

pub fn fork_rc( self: &Rc<ServiceProvider<Parent, Conts>>, ) -> ServiceProvider<Rc<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.

Source

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.

Source§

impl<Parent, Conts: HList> ServiceProvider<Parent, Conts>

Source

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>>(());
Source

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);
Source

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)
Source

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);
Source

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);
Source

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.

Source

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.

Trait Implementations§

Source§

impl<Parent: Debug, Conts: Debug> Debug for ServiceProvider<Parent, Conts>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ServiceProvider<EmptyServiceProvider, HNil>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<Parent, Conts> Freeze for ServiceProvider<Parent, Conts>
where Parent: Freeze, Conts: Freeze,

§

impl<Parent, Conts> RefUnwindSafe for ServiceProvider<Parent, Conts>
where Parent: RefUnwindSafe, Conts: RefUnwindSafe,

§

impl<Parent, Conts> Send for ServiceProvider<Parent, Conts>
where Parent: Send, Conts: Send,

§

impl<Parent, Conts> Sync for ServiceProvider<Parent, Conts>
where Parent: Sync, Conts: Sync,

§

impl<Parent, Conts> Unpin for ServiceProvider<Parent, Conts>
where Parent: Unpin, Conts: Unpin,

§

impl<Parent, Conts> UnwindSafe for ServiceProvider<Parent, Conts>
where Parent: UnwindSafe, Conts: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Choices> CoproductSubsetter<CNil, HNil> for Choices

Source§

type Remainder = Choices

Source§

fn subset( self, ) -> Result<CNil, <Choices as CoproductSubsetter<CNil, HNil>>::Remainder>

Extract a subset of the possible types in a coproduct (or get the remaining possibilities) Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<'a, T, TRest, Cont, Infer, InferRest, SP> GetDependencies<'a, HCons<T, TRest>, HCons<(Cont, Infer), InferRest>> for SP
where TRest: HList, SP: Resolver<'a, Cont, T, Infer> + GetDependencies<'a, TRest, InferRest>,

Source§

fn get_deps(&'a self) -> HCons<T, TRest>

Source§

impl<'a, S> GetDependencies<'a, HNil, HNil> for S

Source§

fn get_deps(&'a self) -> HNil

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U, I> LiftInto<U, I> for T
where U: LiftFrom<T, I>,

Source§

fn lift_into(self) -> U

Performs the indexed conversion.
Source§

impl<'a, Cont, T, U, SP, Index, Deps, Infer> Resolver<'a, ConvertContainer<Cont, T, U>, U, (Index, Deps, Infer)> for SP
where U: 'a, Deps: 'a, Cont: 'a, T: Into<U> + 'a, ConvertContainer<Cont, T, U>: ResolveContainer<'a, U, Deps>, SP: Selector<ConvertContainer<Cont, T, U>, Index> + GetDependencies<'a, Deps, Infer>,

Source§

fn resolve(&'a self) -> U

Source§

impl<'a, T, SP, Index> Resolver<'a, InstanceContainer<T>, &'a T, Index> for SP

Source§

fn resolve(&'a self) -> &'a T

Source§

impl<'a, T, SP, Index> Resolver<'a, InstanceContainer<T>, T, Index> for SP

Source§

fn resolve(&'a self) -> T

Source§

impl<'a, T, SP, Index, Deps, Infer> Resolver<'a, SingletonContainer<T>, &'a T, (Index, Deps, Infer)> for SP
where SingletonContainer<T>: ResolveContainer<'a, &'a T, Deps>, T: Dependency<Deps> + 'a, Deps: 'a, SP: GetDependencies<'a, Deps, Infer> + Selector<SingletonContainer<T>, Index>,

Source§

fn resolve(&'a self) -> &'a T

Source§

impl<'a, T, SP, Index, Deps, Infer> Resolver<'a, SingletonContainer<T>, T, (Index, Deps, Infer)> for SP
where SingletonContainer<T>: ResolveContainer<'a, &'a T, Deps>, T: Dependency<Deps> + DependencyClone + 'a, Deps: 'a, SP: GetDependencies<'a, Deps, Infer> + Selector<SingletonContainer<T>, Index>,

Source§

fn resolve(&'a self) -> T

Source§

impl<'a, T, SP, Index, Deps, Infer> Resolver<'a, TransientContainer<T>, T, (Index, Deps, Infer)> for SP
where SP: Selector<TransientContainer<T>, Index> + GetDependencies<'a, Deps, Infer>, T: Dependency<Deps> + 'a, TransientContainer<T>: ResolveContainer<'a, T, Deps>,

Source§

fn resolve(&'a self) -> T

Source§

impl<Source> Sculptor<HNil, HNil> for Source

Source§

type Remainder = Source

Source§

fn sculpt(self) -> (HNil, <Source as Sculptor<HNil, HNil>>::Remainder)

Consumes the current HList and returns an HList with the requested shape. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.