Expand description
Dirk is a framework for compile-time dependency injection, focusing on usability and developer experience.
§Usage
Dependency Injection using dirk relies on two equally important concepts:
- Providers (see
#[provides(...)]
) specify how instances are created- static, not wrapped
- singleton, wrapped in
Arc<RwLock<...>>
(shared globally) - scoped, wrapped in
Rc<RefCell<...>>
(shared inside an individual component)
- Components (see
#[component(...)]
) provide a way to retrieve instances (possibly containing multiple dependencies, specified by so-called bindings)- bindings provided via a provider
- instance bindings, supplied by the user
- scoped instance, wrapped in
Rc<RefCell<...>>
(shared inside an individual component) - cloned instance, not wrapped (cloned wehenever it is required)
- scoped instance, wrapped in
#[use_provides(...)]
and #[use_component(...)]
may be used to import providers and components in other modules.
§Examples
use dirk_framework::provides;
struct UserService {}
#[provides(scoped_inject)]
impl UserService {
fn new() -> Self { UserService { /* ... */ } }
}
struct AuthService {}
#[provides(scoped_inject)]
impl AuthService {
fn new() -> Self { AuthService { /* ... */ } }
}
struct Application {
user_service: Rc<RefCell<UserService>>,
auth_service: Rc<RefCell<AuthService>>
}
#[provides(static_inject)]
impl Application{
fn new(user_service: Rc<RefCell<UserService>>,
auth_service: Rc<RefCell<AuthService>>) -> Self {
Application {user_service, auth_service}
}
}
#[component(
user_service: scoped_bind(UserService),
auth_service: scoped_bind(AuthService),
application: static_bind(Application) [user_service, auth_service]
)]
trait ApplicationComponent {
fn user_service(&self) -> Rc<RefCell<UserService>>;
fn auth_service(&self) -> Rc<RefCell<AuthService>>;
fn application(&self) -> Application;
}
use dirk_framework::component;
use dirk_framework::component::{Component, StaticComponent, builder::Builder};
let component = DirkApplicationComponent::create(); // <- Auto-generated
let application = component.application();
§Generic Components
Components are even allowed to be generic, as long as no where
clause is used and all generic type paramters have lifetime 'static
.
use dirk_framework::component;
use dirk_framework::component::{Component, StaticComponent, builder::Builder};
#[component(answer: cloned_instance_bind(T))]
trait GenericComponent<T: Clone + 'static> {
fn answer(&self) -> T;
}
let component = DirkGenericComponent::builder().answer(42).build();
assert_eq!(component.answer(), 42);
Modules§
- component
- Contains data types used by the
#[component(...)]
macro - provides
- Contains data types used by the
#[provides]
macro
Attribute Macros§
- component
- Declares a component that may be used to instantiate types.
- provides
- Annotates an
impl
block containing a function that provides an instance of a certain type - use_
component - May be used to facilitate using components defined in a different module
- use_
provides - May be used to facilitate injecting or querying types provided in a different module