5 unstable releases
0.3.0 | Jul 3, 2023 |
---|---|
0.2.3 | Mar 15, 2023 |
0.2.0 | Oct 21, 2022 |
0.1.0 | Sep 4, 2022 |
#2 in #injection
313 downloads per month
Used in 3 crates
12KB
nject
Simple zero cost dependency injection library made for rust
Install
Add the following to your Cargo.toml
:
[dependencies]
nject = "0.3"
Why nject
?
- Zero cost: Using this library is equivalent to manually injecting your dependencies as shown in the benchmarks.
- Compile time only: If configured incorrectly,
nject
will fail at compile time.
Use cases
Removes the need to specify dependencies across your modules
use nject::{injectable, provider};
#[injectable]
struct DepOne;
#[injectable]
struct DepTwo {
dep: DepOne,
}
#[injectable]
struct Facade {
dep: DepTwo,
}
#[provider]
struct Provider;
fn main() {
let _facade: Facade = Provider.provide();
}
Works with lifetimes - enables shared dependencies
use nject::{injectable, provider};
struct DepOne;
#[injectable]
struct Facade<'a> {
dep: &'a DepOne,
}
#[provider]
struct Provider<'a> {
#[provide]
shared: &'a DepOne,
}
fn main() {
let provider = Provider { shared: &DepOne };
let _facade: Facade = provider.provide();
}
Works with dyn traits
use nject::{injectable, provider};
trait Greeter {
fn greet(&self);
}
#[injectable]
struct GreeterOne;
impl Greeter for GreeterOne {
fn greet(&self) {
println!("Greeting");
}
}
#[injectable]
struct Facade<'a> {
boxed_dep: Box<dyn Greeter>,
ref_dep: &'a dyn Greeter,
}
#[provider]
#[provide(Box<dyn Greeter>, Box::<GreeterOne>::new(self.provide()))]
struct Provider {
#[provide(dyn Greeter)]
greeter: GreeterOne,
}
fn main() {
let provider = Provider { greeter: GreeterOne };
let _facade: Facade = provider.provide();
}
Works with generics
use nject::{injectable, provider};
#[injectable]
struct DepOne;
#[injectable]
struct Facade<T> {
dep: T,
}
#[provider]
struct Provider;
fn main() {
let _facade: Facade<DepOne> = Provider.provide();
}
Works with generic providers
use nject::{injectable, provider};
trait Greeter {
fn greet(&self);
}
#[injectable]
struct DevGreeter;
impl Greeter for DevGreeter {
fn greet(&self) {
println!("Greeting Dev");
}
}
#[injectable]
struct ProdGreeter;
impl Greeter for ProdGreeter {
fn greet(&self) {
println!("Greeting production");
}
}
#[injectable]
struct Facade<'a> {
dep: &'a dyn Greeter,
}
#[provider]
struct Provider<'a, T: Greeter>(#[provide(dyn Greeter)] &'a T);
fn main() {
let _dev_facade: Facade = Provider(&DevGreeter).provide();
let _prod_facade: Facade = Provider(&ProdGreeter).provide();
}
Easily inject non-injectable dependencies
use nject::{inject, injectable, provider};
#[inject(Self { non_injectable_value: 123 })]
struct InjectableFromInjectAttr {
non_injectable_value: i32,
}
struct NonInjectable {
non_injectable_value: i32,
}
#[inject(Self {
non_injectable_value: injectable_dep.non_injectable_value + 10,
injectable_dep
}, injectable_dep: InjectableFromInjectAttr)]
struct PartiallyInjectable {
non_injectable_value: i32,
injectable_dep: InjectableFromInjectAttr
}
#[injectable]
struct Facade {
dep_from_injected: InjectableFromInjectAttr,
dep_from_partial_inject: PartiallyInjectable,
#[inject(NonInjectable { non_injectable_value: 456 })]
dep_from_inject_attr: NonInjectable,
#[inject(InjectableFromInjectAttr { non_injectable_value: 789 })]
dep_from_inject_attr_override: InjectableFromInjectAttr,
#[inject(PartiallyInjectable {
non_injectable_value: 111,
injectable_dep
}, injectable_dep: InjectableFromInjectAttr)]
dep_from_partial_inject_attr_override: PartiallyInjectable,
}
#[provider]
struct Provider;
fn main() {
let _facade = Provider.provide::<Facade>();
}
Use modules to export internal shared dependencies
use nject::{injectable, provider};
mod sub {
use nject::{injectable, module};
#[injectable]
struct InternalType( #[inject(123)] i32); // Not visible outside of module.
#[injectable]
pub struct Facade<'a> {
hidden: &'a InternalType
}
#[injectable]
#[module]
pub struct Module {
#[export]
hidden: InternalType
}
}
#[injectable]
#[provider]
struct Provider {
#[import]
subModule: sub::Module
}
fn main() {
#[provider]
struct InitProvider;
let provider = InitProvider.provide::<Provider>();
let _facade = provider.provide::<sub::Facade>();
}
Limitations
- Dependencies can only be exported by a single module.
- Modules can only export types defined in its crate.
- Generic parameters are not supported on modules.
Examples
You can look into the axum example for a Web API use case or into the Leptos example for a Web App.
Credits
- Syn - MIT or Apache-2.0
- Quasi-Quoting - MIT or Apache-2.0
- Rust - MIT or Apache-2.0
Dependencies
~115KB