Lockjaw is a fully static, compile-time dependency injection framework for Rust inspired by Dagger. It is also what you get when jabbed by a rusty dagger.
Features:
@Inject
=>
#[inject]
constructor injection
in #[injectable]
@Provides
=> #[provides]
bind method return values@Binds
=> #[binds]
bind trait to implementation.@Singleton
/
@Scope
=>
scope=component
shared instance.@Named
=>
#[qualified]
Provider<T>
=> Provider<T>
create
multiple instances at run time.Lazy<T>
=> Lazy<T>
create and cache
instance only when used.#[subcomponent]
Dynamically creatable sub-scopes with additional bindings#[into_vec]
/ #[into_map]
Collect same bindings to a Vec/HashMap, useful for plugin systems.@BindsOptionalOf
=> #[binds_option_of]
Allow some bindings to be missing#[facotry]
create objects with both injected fields and runtime fields.#[define_component]
/ #[entry_point
/ install_in
Automatic module collection from build dependency.See user guide for more information.
Example:
```rust use lockjaw::*; use std::ops::Add;
lockjaw::prologue!("src/lib.rs");
struct GreetCounter {
counter: ::std::cell::RefCell
// Allow GreetCounter to be created in the dependency graph. These bindings are available anywhere.
impl GreetCounter { // Marks a method as the inject constructor. Lockjaw will call this to create the object. #[inject] pub fn new() -> Self { Self{counter : std::cell::RefCell::new(0) } }
}
impl GreetCounter{ pub fn increment(&self) -> i32 { let mut m = self.counter.borrow_mut(); *m = m.add(1); m.clone() } }
pub trait Greeter { fn greet(&self) -> String; }
struct GreeterImpl { greet_counter : crate::GreetCounter, phrase : String }
impl GreeterImpl { // Lockjaw will call this with other injectable objects provided. #[inject] pub fn new(greetcounter : GreetCounter, phrase : String) -> Self { Self { greetcounter, phrase } } }
impl Greeter for GreeterImpl{ fn greet(&self) -> String{ format!("{} {}", self.phrase, self.greet_counter.increment()) } }
// Declare a module so we can do special bindings. These bindings are only available if the // component installs the module, so different bindings can be used based on the situation. struct MyModule {}
impl MyModule {
// When ever someone needs a Greeter, use GreeterImpl as the actual implementation
#[binds]
pub fn bindgreeter(impl : crate::GreeterImpl) -> Cl
// Called when a String is requested
#[provides]
pub fn provide_string() -> String {
"helloworld".to_owned()
}
}
// Components stitch modules and injectables together into a dependency graph, and can create
// objects in the graph. The component installs modules listed in modules
trait MyComponent {
// Allows creating a greeter with the component. The created object has the lifetime of the
// component
fn greeter(&self) -> Cl
pub fn main() { // Creates the component let component = MyComponent::new(); // Creates a greeter. let greeter = component.greeter(); asserteq!(greeter.greet(), "helloworld 1"); // Internal states of the greeter is kept. asserteq!(greeter.greet(), "helloworld 2");
// A new greeter has a new independent set of injected objects.
assert_eq!(component.greeter().greet(), "helloworld 1");
} // called after the last use of lockjaw to perform validation and code generation epilogue!(); ```
This is not an officially supported Google product.
Lockjaw is currently in early development and all APIs are subjected to changes. Some feature are also implemented in a hacky way. Use at your own risk.