pub struct Compose<Ev> { /* private fields */ }
Expand description
Compose capability can be used to orchestrate effects into a single transaction.
Example include:
- Running a number of HTTP requests in parallel and waiting for all to finish
- Chaining effects together, where the output of one is the input of the next and the intermediate results are not useful to the app
- Implementing request timeouts by selecting across a HTTP effect and a time effect
- Any arbitrary graph of effects which depend on each other (or not).
The compose capability doesn’t have any operations it emits to the shell, and type generation fails
on its operation type (Never
)). This is difficult for crux to detect
at the moment. To avoid this problem until a better fix is found, use #[effect(skip)]
to skip the
generation of an effect variant for the compose capability. For example
#[derive(Effect)]
pub struct Capabilities {
pub render: Render<Event>,
#[effect(skip)]
pub compose: Compose<Event>,
}
Note that testing composed effects is more difficult, because it is not possible to enter the effect transaction “in the middle” - only from the beginning - or to ignore some of the effects with out stalling the entire downstream dependency chain.
Implementations§
source§impl<Ev> Compose<Ev>
impl<Ev> Compose<Ev>
pub fn new(context: CapabilityContext<Never, Ev>) -> Self
sourcepub fn spawn<F, Fut>(&self, effects_task: F)
pub fn spawn<F, Fut>(&self, effects_task: F)
Spawn a task which orchestrates across other capabilities.
The argument is a closure which receives a ComposeContext
which can be used to send
events to the app.
For example:
fn update(&self, event: Self::Event, model: &mut Self::Model, caps: &Self::Capabilities) {
match event {
Event::Trigger => caps.compose.spawn(|context| {
let one = caps.one.clone();
let two = caps.two.clone();
async move {
let (result_one, result_two) =
futures::future::join(
one.one_async(10),
two.two_async(20)
).await;
context.update_app(Event::Finished(result_one, result_two))
}
}),
Event::Finished(one, two) => {
model.total = one + two;
}
}
}