[][src]Derive Macro coi::Inject

#[derive(Inject)]
{
    // Attributes available to this derive:
    #[provides]
    #[inject]
}

Generates an impl for Inject and also generates a "Provider" struct with its own Provide impl.

This derive proc macro impls Inject on the struct it modifies, and also processes two attributes:

  • #[provides] - Only one of these is allowed per #[derive(Inject)]. It takes the form
This example is not tested
#[provides(<vis> <ty> with <expr>)]

It generates a provider struct with visibility <vis> that impls Provide with an output type of Arc<<ty>>. It will construct <ty> with <expr>, and all params to <expr> must match the struct fields marked with #[inject] (see the next bullet item). <vis> must match the visibility of <ty> or you will get code that might not compile.

  • #[inject] - All fields marked #[inject] are resolved in the provide fn described above. Given a field <field_name>: <field_ty>, this attribute will cause the following resolution to be generated:
This example is not tested
let <field_name> = Container::resolve::<<field_ty>>(conainer, "<field_name>");

Because of this, it's important that the field name MUST match the string that's used to register the provider in the ContainerBuilder.

Examples

Private trait and no dependencies

use coi::Inject;
use coi_derive::Inject;
trait Priv: Inject {}

#[derive(Inject)]
#[provides(dyn Priv with SimpleStruct)]
struct SimpleStruct;

impl Priv for SimpleStruct {}

Public trait and dependency

use coi::Inject;
use coi_derive::Inject;
use std::sync::Arc;
pub trait Pub: Inject {}
pub trait Dependency: Inject {}

#[derive(Inject)]
#[provides(pub dyn Pub with NewStruct::new(dependency))]
struct NewStruct {
    #[inject]
    dependency: Arc<dyn Dependency>,
}

impl NewStruct {
    fn new(dependency: Arc<dyn Dependency>) -> Self {
        Self {
            dependency
        }
    }
}

impl Pub for NewStruct {}

Struct injection

use coi::Inject;
use coi_derive::Inject;

#[derive(Inject)]
#[provides(pub InjectableStruct with InjectableStruct)]
struct InjectableStruct;

Unnamed fields

use coi::Inject;
use coi_derive::Inject;
use std::sync::Arc;

#[derive(Inject)]
#[provides(Dep1 with Dep1)]
struct Dep1;

#[derive(Inject)]
#[provides(Impl1 with Impl1(dep1))]
struct Impl1(#[inject(dep1)] Arc<Dep1>);

Generics

use coi::{container, Inject};
use coi_derive::Inject;

#[derive(Inject)]
#[provides(Impl1<T> with Impl1::<T>::new())]
struct Impl1<T>(T)
where
    T: Default;

impl<T> Impl1<T>
where
    T: Default,
{
    fn new() -> Self {
        Self(Default::default())
    }
}

fn build_container() {
  // Take note that these providers have to be constructed
  // with explicit types.
  let impl1_provider = Impl1Provider::<bool>::new();
  let container = container! {
      impl1 => impl1_provider,
  };
  let _bool_impl = container
      .resolve::<Impl1<bool>>("impl1")
      .expect("Should exist");
}

If you need some form of constructor fn that takes arguments that are not injected, then you need to manually implement the Provide trait, and this derive will not be useful.