Builder Modules
In the previous chapter the modules are without fields, so Lockjaw can easily create instances of it
(In fact no instance are created since Lockjaw can just call the static methods). However sometimes
we want to be able to affect the values that are bound at runtime, hence need to be able to change
what #[provides]
does using fields in the module.
struct MyModule {
i: i32,
}
#[module]
impl MyModule {
#[provides]
pub fn provide_i32(&self) -> i32 {
self.i
}
}
Since the struct
now has fields Lockjaw can no longer automatically create it, the user must
manually pass in the modules when creating the component.
Implementation note: While Lockjaw can also try to use Default or some other mechanisms, usages like this implies the module has mutable state and generally is a bad idea.
Using builder modules
Instead of passing the runtime modules to the component one by one, they are collected in a single
struct
annotated by
the #[builder_modules]
attribute.
#[builder_modules]
struct MyBuilderModules {
my_module: MyModule,
}
Every field in the struct should be a module. Using a struct
makes sure each module will be
required by the compiler/IDE while exposing the least amount of generated code(which is harder for
users and IDEs to understand, it is better to spell everything out in visible code.).
The #[builder_modules]
can then be installed in the component using
the builder_modules
metadata
#[component(builder_modules: MyBuilderModules)]
trait MyComponent {
fn i32(&self) -> i32;
}
The component only accepts one#[builder_modules]
, which is likely to be specifically tailored for
the component. The modules itself can be shared.
The builder_modules
metadata can be used at the same time with
the modules
metadata.
modules
should be preferred whenever possible as they are easier to use.
Creating components with builder modules
If
the builder_modules
metadata
is specified,
the #[builder_modules] struct
will become the parameter for
the build()
method
of the component which the user must pass.
#[test]
fn test() {
let my_module = MyModule { i: 42 };
let my_builder_modules = MyBuilderModules { my_module };
let component: Box<dyn MyComponent> = <dyn MyComponent>::build(my_builder_modules);
assert_eq!(component.i32(), 42);
let other_component: Box<dyn MyComponent> = <dyn MyComponent>::build(MyBuilderModules {
my_module: MyModule { i: 123 },
});
assert_eq!(other_component.i32(), 123);
}
Source of this chapter