Skip to main content

pipecrab_runtime/
offload.rs

1//! [`offload`](fn@self::offload) runs CPU-bound or blocking work off the
2//! orchestrator thread.
3//!
4//! The pipeline runs on a single `!Send` thread, and a stage's `perform` must
5//! keep yielding so an interrupt can preempt it. Heavy or blocking work run
6//! inline would freeze the whole pipeline; `offload` is the one place work
7//! crosses to another thread. That is why `F` and `T` are `Send + 'static` —
8//! the bound is the offload boundary, not a requirement on the pipeline itself.
9
10/// Run `f` off the orchestrator thread and `await` its result.
11///
12/// Wrap CPU-bound or blocking work in `offload(...)` and `.await` it: the
13/// orchestrator stays free to keep polling — including the system lane — while
14/// the work runs elsewhere, so interrupt barge-in stays responsive.
15///
16/// # Native
17///
18/// Runs `f` on a fresh [`std::thread`] and returns its result over a
19/// `futures::channel::oneshot`. Runtime-agnostic and tokio-free; a runtime
20/// adapter can later back this with a pooled `spawn_blocking`.
21///
22/// Dropping the returned future before it resolves detaches the worker thread —
23/// it still runs to completion, but its result is discarded. If `f` panics, the
24/// worker unwinds and drops the sender; awaiting the returned future then panics
25/// (a fresh panic noting the worker produced no result — the original payload is
26/// not propagated).
27#[cfg(not(target_arch = "wasm32"))]
28pub async fn offload<F, T>(f: F) -> T
29where
30    F: FnOnce() -> T + Send + 'static,
31    T: Send + 'static,
32{
33    let (tx, rx) = futures::channel::oneshot::channel();
34    std::thread::spawn(move || {
35        let _ = tx.send(f());
36    });
37    rx.await.expect("offload worker panicked or was dropped before sending a result")
38}
39
40/// wasm stub: offloading to a Web Worker is not yet implemented.
41///
42/// `wasm32-unknown-unknown` has no `std::thread`, so this placeholder keeps the
43/// crate compiling for wasm. The eventual implementation will post `f` to a Web
44/// Worker and resolve over a `oneshot`; see the native version for the intended
45/// semantics.
46#[cfg(target_arch = "wasm32")]
47pub async fn offload<F, T>(_f: F) -> T
48where
49    F: FnOnce() -> T + Send + 'static,
50    T: Send + 'static,
51{
52    unimplemented!("offload on wasm32 (Web Worker path) is not yet implemented")
53}