Attribute Macro lockjaw::injectable [−][src]
#[injectable]
Expand description
Annotates a struct impl that can be provided to the dependency graph.
struct Bar{}
#[injectable]
impl Bar {
#[inject]
pub fn new() -> Self {
Self {}
}
}
struct Foo{
bar : crate::Bar,
s : String,
}
#[injectable]
impl Foo {
#[inject]
pub fn new(bar : crate::Bar,) -> Self {
Self {bar, s: "foo".to_owned()}
}
}
#[component]
trait MyComponent {
fn foo(&self) -> crate::Foo;
}
pub fn main() {
let component = <dyn MyComponent>::new();
let foo = component.foo();
}
epilogue!();
Method attributes
Exactly one method under the #[injectable]
should have a constructor attribute:
These attributes designate which method lockjaw should call to create a instance.
Method attributes are nested under #[injectable]
, and all nested attributes should be
unqualified (always used as #[attribute]
instead of #[lockjaw::attribute]
).
Metadata
Injectables accept additional metadata in the form of
#[injectable(key=value, key2=value)]
.
scope
Optional path to a component
, which makes the injectable
a scoped singleton
under the component
.
The injectable
will only be provided in the component
, and all objects generated from the
same component
instance will share the same scoped injecetable
instance. Since it is shared, the
scoped injectable
can only be depended on as &T
or Cl<T>
, and the scoped injectable
or any objects that depends on it will share the lifetime of the
component
.
pub struct Foo {}
#[injectable(scope : crate::MyComponent)]
impl Foo {
#[inject]
pub fn new()-> Self {
Self {}
}
}
pub struct Bar<'a>{
foo : &'a crate::Foo
}
#[injectable]
impl Bar<'_> {
#[inject]
pub fn new(foo : &'_ crate::Foo) -> Bar<'_> {
Bar {foo}
}
}
#[lockjaw::component]
pub trait MyComponent {
fn bar(&self) -> crate::Bar;
}
pub fn main() {
let component = <dyn MyComponent>::new();
let bar1 = component.bar();
let bar2 = component.bar();
let bar1_ptr: *const Bar = &bar1;
let bar2_ptr: *const Bar = &bar2;
assert_ne!(bar1_ptr, bar2_ptr);
let foo1_ptr : *const Foo = bar1.foo;
let foo2_ptr : *const Foo = bar2.foo;
assert_eq!(foo1_ptr, foo2_ptr);
}
epilogue!();
Scoped injectables
are shared and cannot be mutable while they commonly needs mutability. users
must implement internal mutability.
container
Optional Specifies a container such as RefCell<T>
to place the injectable
in. The metadata
is only applicable when scope
is also used.
The container
must be a generic in the form of CONTAINER<T>
, which has a
pub fn new(value: T) -> CONTAINER<T>
method. Most common rust containers like Cell
, Rc
are
applicable.
When container
is specified, the non-contained form of the struct can not be injected.
Typically, this is used to give internal mutability to a shared instance.
pub struct Foo {
pub i: u32,
}
#[injectable(scope: MyComponent, container: RefCell)]
impl Foo {
#[inject]
pub fn new() -> Self {
Self {
i: Default::default(),
}
}
pub fn count(&mut self) -> u32 {
self.i = self.i + 1;
self.i
}
}
#[component]
pub trait MyComponent {
fn foo(&self) -> &RefCell<crate::Foo>;
}
pub fn main() {
let component: Box<dyn MyComponent> = <dyn MyComponent>::new();
let foo1 = component.foo();
let foo2 = component.foo();
assert_eq!(foo1.borrow_mut().count(), 1);
assert_eq!(foo1.borrow_mut().count(), 2);
assert_eq!(foo2.borrow_mut().count(), 3);
}
epilogue!();