Dependency injection for Rust

How to use:

Cargo.toml: toml waiter_di = "1.6.0" lib.rs and any other file, that uses library: rust use waiter_di::*;

See examples/1getstarted.rs for minimal example of usage.

See examples/2_modules.rs for example with modules and constructors.

See examples/3injectoptions_list.rs for demo of all available injection options.

How to use

Annotate structure with #[component]

```rust

[component]

struct Comp {} ```

Annotate impl blocks with #[provides]

```rust

[provides]

impl Interface for Comp {} ```

Create container:

rust fn main() { let mut container = Container::<profiles::Default>::new(); }

Get dependency ref:

rust fn main() { let comp = Provider::<dyn Interface>::get(&mut container); }

Inject references

For Rc:

```rust

[component]

struct Dependency;

[component]

struct Comp { dependency_rc: Rc }

fn main() { let mut container = Container::::new(); Provider::::get(&mut container); } ```

to use Arc instead of Rc you need to add async feature in cargo: toml waiter_di = { version = "...", features = [ "async" ] }

Also you can use waiter_di::Rc type that will be compiled to Rc or Arc depending on async feature.

To create new struct instead of getting reference:

```rust

[component]

struct Comp { dependency: Dependency, dependency_box: Box }

fn main() { let mut container = Container::::new(); Provider::::create(&mut container); Provider::::create_boxed(&mut container); } ```

Properties

It uses config crate under the hood, for example it tries to find float_prop in args as --float_prop <value>, if not found it tries to find it in environment variables, after that tries config/{profile}.toml, after that config/default.toml

```rust

[derive(Debug, Deserialize)]

struct ConfigObject { i32_prop: i32 }

[component]

struct Comp { config: Config, #[prop("int")] intprop: usize, #[prop("int")] intpropopt: Option, #[prop("int" = 42)] intpropwithdefaultvalue: usize, floatprop: f32, #[prop] config_object: ConfigObject } ```

Dependency cycle

Use Deferred type:

```rust

[component]

struct Comp { dependencydef: Deferred, dependencydefrc: Deferred>, dependencydef_box: Deferred> } ```

Profiles

You can use predefined profiles from `waiter_di::profile" or create custom:

```rust struct CustomProfile;

[provides(profiles::Dev, CustomProfile)]

impl Interface for Comp {}

fn main() { let mut container = Container::::new(); let mut container = Container::::new(); let mut container = Container::::new(); } ```

Get profile from args, environment or config/default.toml

Just define property named profile as --profile <profile> arg, profile env variable or profile property in config/default.toml and use inject! macro:

rust fn main() { let comp = inject!(Comp: profiles::Default, profiles::Dev); }

inject! macro can't be used for several components, so it's recommended to use it with modules:

```rust

[module]

struct SomeModule { component: Component }

[module]

struct RootModule { somemodule: SomeModule } fn main() { let rootmodule = inject!(RootModule: profiles::Default, profiles::Dev); } ```

In this case #[module] is just a synonym for #[component]

Factory functions:

If you can't use #[component] annotation, use factory function instead:

```rust

[provides]

fn createdependency(boolprop: bool) -> Dependency { Dependency { prop: bool_prop } } ```

To use it like a constructor, use it with #[component] on impl block:

```rust struct Comp();

[component]

impl Comp { #[provides] fn new() -> Self { Self() } } ```

Deferred args in factory functions is unsupported. In the rest it can accept the same arg types as #[component].

External types isn't supported for factory functions:

```rust

[provides] // won't compile

fn createexternaltype_dependency() -> HashMap { HashMap::new() } ```

So you need to create crate-local wrapper:

```rust struct Wrapper(HashMap);

[provides]

fn createexternaltype_dependency() -> Wrapper { Wrapper(HashMap::new()) } ```

For convenience you can use #[wrapper] attribute to implement Deref automatically:

```rust

[wrapper]

struct HashMap(std::collections::HashMap);

[provides]

fn createexternaltype_dependency() -> HashMap { return HashMap(std::collections::HashMap::::new()); } ```