Skip to main content

runifold_effect/
handler.rs

1use std::{future::Future, pin::Pin};
2
3use runifold_core::{CancellationToken, EffectRequest, Instant, RunContext, RunError, RunId};
4use serde_json::Value;
5
6/// Boxed future returned by an effect handler.
7#[cfg(not(target_arch = "wasm32"))]
8pub type EffectFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
9
10/// Boxed effect-handler future on single-threaded WASM.
11#[cfg(target_arch = "wasm32")]
12pub type EffectFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
13
14/// Lifecycle-only context passed to an external-effect handler.
15#[derive(Clone, Debug)]
16pub struct EffectExecutionContext {
17    run_id: RunId,
18    deadline: Option<Instant>,
19    cancellation: CancellationToken,
20}
21
22impl EffectExecutionContext {
23    pub(crate) fn for_run(run: &RunContext) -> Self {
24        Self {
25            run_id: run.run_id(),
26            deadline: run.deadline(),
27            cancellation: run.cancellation().child_token(),
28        }
29    }
30
31    /// Returns the owning Run identity.
32    pub const fn run_id(&self) -> RunId {
33        self.run_id
34    }
35
36    /// Returns the effective deadline.
37    pub const fn deadline(&self) -> Option<Instant> {
38        self.deadline
39    }
40
41    /// Returns the descendant cancellation token.
42    pub const fn cancellation(&self) -> &CancellationToken {
43        &self.cancellation
44    }
45}
46
47/// Object-safe implementation boundary for one class of external effect.
48pub trait EffectHandler: Send + Sync {
49    /// Executes a prepared effect request.
50    fn execute(
51        &self,
52        request: &EffectRequest,
53        context: EffectExecutionContext,
54    ) -> EffectFuture<'_, Result<Value, RunError>>;
55}