To use Shaku, you define interfaces using traits that inherit from shaku::Interface, implement them in structs using the #[derive(Component)] macro, and register them in a module using the module! macro.
For components that require runtime parameters (like configuration strings or numbers), you can use the .with_component_parameters::<T>(...) method on the module builder during initialization. Dependencies within components are injected using the #[shaku(inject)] attribute on fields.
use shaku::{module, Component, Interface, HasComponent};
use std::sync::Arc;
trait Logger: Interface {
fn log(&self, content: &str);
}
trait DateLogger: Interface {
fn log_date(&self);
}
#[derive(Component)]
#[shaku(interface = Logger)]
struct LoggerImpl;
impl Logger for LoggerImpl {
fn log(&self, content: &str) {
println!("{}", content);
}
}
#[derive(Component)]
#[shaku(interface = DateLogger)]
struct DateLoggerImpl {
#[shaku(inject)]
logger: Arc<dyn Logger>,
today: String,
year: usize,
}
impl DateLogger for DateLoggerImpl {
fn log_date(&self) {
self.logger.log(&format!("Today is {}, {}", self.today, self.year));
}
}
module! {
MyModule {
components = [LoggerImpl, DateLoggerImpl],
providers = []
}
}
fn main() {
let module = MyModule::builder()
.with_component_parameters::<DateLoggerImpl>(DateLoggerImplParameters {
today: "Jan 26".to_string(),
year: 2020
})
.build();
let date_logger: &dyn DateLogger = module.resolve_ref();
date_logger.log_date();
}