Incular logoIncular
API ReferenceState & Async

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.

StateMeaning
IdleNot started
LoadingFuture 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.

Related: Action, Signal.

On this page