Handlers
A Handler is a function that implements the logic for a specific effect. It receives the effect instance and returns a Control<R>, which tells the runner what to do next.
Control flow
Control<R> has two variants:
Control::resume(value)— resumes the computation, passingvalueback as the result ofyield_. The type ofvaluemust match the effect'sResumetype.Control::cancel()— aborts the entire computation immediately. The final result will beErr(Cancelled).
Sync handlers
A sync handler is a regular closure:
|Log(msg)| {
println!("LOG: {msg}");
Control::resume(())
}Async handlers
An async handler is an async closure (requires Rust 1.85+):
async |FileRead(file)| {
let content = tokio::fs::read_to_string(file).await.unwrap();
Control::resume(content)
}Named function handlers
Handlers can also be named functions:
fn log(_: &mut State, Log(msg): Log<'_>) -> Control<()> {
println!("LOG: {msg}");
Control::resume(())
}
fn file_read(_: &mut State, FileRead(file): FileRead) -> Control<String> {
println!("Reading file: {file}");
Control::resume("file content".to_string())
}Cancellation
Use Control::cancel() when an effect should abort the entire computation:
#[effect(Never)]
struct Cancel;
// The handler cancels the computation
|_: Cancel| Control::cancel()
The Never resume type indicates this effect can never resume — the handler must always cancel.