Tasks & AsyncState
Owner-scoped and app-scoped Tokio tasks with every spawn method.
Asynchronous work belongs to the runtime's Tokio scopes. Store observable state
in Signal<AsyncState<T, E>>, start work with spawn_into/TaskScope, render
the signal.
| State | Meaning |
|---|---|
Idle | Not started |
Loading | Future running |
Ready(T) | Completed with value |
Error(E) | Failed with error |
AsyncState
A background load flipping a signal — copy, paste, and run:
use incular::prelude::*;
fn main() {
let state: Signal<AsyncState<String, TaskFailure>> =
Signal::new(AsyncState::Loading);
let shown = state.clone();
let completed = state.clone();
let app = Application::new(move |_cx| {
Container::builder()
.padding(EdgeInsets::all(24.0))
.alignment(Alignment::CENTER)
.child(Text::new(format!(
"ready: {}",
shown.get().is_ready()
)))
.build()
.into()
})
.expect("valid application");
app.spawn_into(
async move { "loaded".to_string() },
move |result, _rt| {
completed.update(|slot| {
*slot = match result {
Ok(value) => AsyncState::Ready(value),
Err(failure) => AsyncState::Error(failure),
}
});
},
);
incular::run(app).expect("run application");
}AsyncValue<T> = AsyncState<T, TaskFailure> (legacy alias; prefer
AsyncState<T, E>).
Inside a build, own the slot with cx.state(|| Signal::new(AsyncState::Idle))
and render the signal as the runnable program above does.
Spawning from a build
spawn (owner-scoped Task<T>), spawn_in (explicit scope), spawn_into
(UI-thread completion), spawn_blocking (Tokio pool), dispatch (primary
window message), task_scope() (mint a child — the only public way),
tokio_handle() (unscoped) — all exercised by the program above through its
app-scope counterparts.
Spawning from the application
App-scope work survives window close: spawn, spawn_blocking,
spawn_into, dispatch, tokio_handle — same shapes as the build-scope
calls, owned by the application instead of a builder.
Task and TaskScope
value() (Error(Cancelled) if cancelled), cancel(), handle(),
is_cancelled(); scope cancel() cascades to children and child scopes.
TokioHandle is the unscoped Tokio handle (prefer spawn); UiDispatcher
sends UI-thread callbacks without implying redraws; RuntimeSpawner mints
child scopes (scope()) and spawns in them (spawn_in,
spawn_into_in, spawn_blocking_in).
spawn* returns Task<T> (not a Future; poll via .value()).
spawn_into* returns TaskHandle and runs complete on the UI thread (may
capture non-Send signals). Late-cancelled blocking results are discarded.
TaskFailure: Cancelled / Panicked / RuntimeStopped.