Aria's async layer requires C++23 and provides coroutine-based primitives for asynchronous work, built on top of the reactive graph. The key types:
- Task<T> — lazy, single-shot coroutine awaitable
- AsyncCommand<R, Args...> — three-state async action (executing / error / result)
- CoroutineScope / ViewModelScope — structured concurrency tied to a lifetime
- CancellationToken — cooperative cancellation
- Combinators — when_all, when_any, with_timeout
Include: #include "aria/async/task.hpp", #include "aria/async/async_command.hpp", etc.
Task<T>
Task<T> is a lazy coroutine — it does nothing until co_awaited.
Basic Usage
co_return 42;
}
int val = co_await compute_value();
std::cout << "Got: " << val << "\n";
}
Void Specialization
std::cout << msg << "\n";
co_return;
}
Exception Handling
Exceptions thrown inside the coroutine body are stored and re-thrown at the co_await site:
throw std::runtime_error("boom");
co_return 0;
}
try {
int v = co_await risky();
} catch (const std::runtime_error& e) {
}
}
Fire-and-Forget (Detached)
co_return;
}
void start_detached() &&
Start the task and detach it: the coroutine frame stays alive until the coroutine completes,...
Definition task.hpp:158
Pass a fresh task to start_detached(). An already-completed task is released without being resumed; a task still suspended in an asynchronous operation must remain under that operation's resumption control.
Warning: Detached tasks have no lifetime guard. Ensure captured references outlive the coroutine.
CancellationToken / CancellationSource
Cooperative cancellation. A CancellationSource owns the flag; a CancellationToken is a read-only view.
Destroying a source cancels its outstanding tokens and wakes cancellation waiters. Move assignment does the same for the destination's previous state before taking ownership of the incoming state; self-move is a no-op.
Definition cancellation.hpp:221
void cancel()
Trigger cancellation.
Definition cancellation.hpp:242
CancellationToken token() const noexcept
Definition cancellation.hpp:225
Definition cancellation.hpp:182
bool is_cancelled() const noexcept
Definition cancellation.hpp:188
Inside a Coroutine
co_await aria::async::sleep_for(100ms);
do_work();
}
}
void throw_if_cancelled() const
Throw OperationCancelled if cancelled. Call at safe await points.
Definition cancellation.hpp:193
Executor
Executors abstract scheduling — where coroutines run.
Abstract executor interface — schedules a callable to run "somewhere".
Definition executor.hpp:37
Schedule On
Hop between executors:
auto data = fetch_from_db(uid);
co_return data;
}
auto schedule_on(IExecutor &exec)
Schedule a coroutine to resume on the given executor.
Definition executor.hpp:472
AsyncCommand<R, Args...>
An async command exposes three reactive properties that the UI can bind to:
| Property | Type | Meaning |
| is_executing | Property<bool> | True while any invocation is in flight |
| last_error | Property<std::optional<Error>> | Most recent error, nullopt when OK |
| last_result | Property<std::optional<R>> | Most recent successful result (R ≠ void) |
Basic Usage
co_return perform_search(query);
}
};
spinner.set_visible(running);
});
Definition async_command.hpp:463
void execute(Args... args)
Fire-and-forget.
Definition async_command.hpp:559
Property< bool > & is_executing
Definition async_command.hpp:586
Cancellable Action
Accept a CancellationToken as the first parameter:
tok.throw_if_cancelled();
co_return heavy_load(id);
}
};
Concurrency Policies
The command retains one action object across calls. Mutable captures keep their state between sequential invocations. Parallel, and work still unwinding after LatestOnly cancellation, can invoke this object from different workers; protect shared mutable state or keep every access on the same single-thread executor, including after the action switches executors.
@ DropIfRunning
silently ignore new invocations while busy
Definition async_command.hpp:125
@ Parallel
default — all invocations run concurrently
Definition async_command.hpp:123
@ LatestOnly
cancel any in-flight invocations before starting
Definition async_command.hpp:124
Inside a ViewModel
public:
: search(ui, worker,
[this](
std::string q) ->
aria::async::Task<Result> {
co_return do_search(q);
})
{
scope_.attach(*this);
}
aria::Property<std::string> query{""};
aria::async::AsyncCommand<Result, std::string> search;
private:
aria::binding::ViewModelScope scope_;
};
Base class for view models.
Definition view_model.hpp:32
Definition validation_key.hpp:110
ViewModelScope
Ties CoroutineScope to a ViewModel's lifetime. Destroying the VM cancels and joins all in-flight coroutines.
public:
PollingVm() { scope_.attach(*this); }
void start() {
co_await aria::async::sleep_for(1s);
refresh();
}
});
}
private:
aria::binding::ViewModelScope scope_;
};
When PollingVm is destroyed, scope_ calls cancel_and_join() (default 5 s timeout). Stuck coroutines are reported as leaks.
Combinators
when_all
Wait for all tasks to complete. The result is a tuple; a Task<void> child occupies a std::monostate slot, including when mixed with value-returning tasks:
load_users(),
load_posts(),
load_comments()
);
}
auto when_all(Task< Ts >... tasks)
Definition when_all.hpp:204
when_any
Complete when the first task finishes (others are cancelled):
fetch_from_primary(),
fetch_from_backup()
);
}
auto when_any(std::vector< Task< T > > tasks)
Definition when_all.hpp:401
with_timeout
Abort if a task exceeds the deadline:
slow_fetch(),
std::chrono::seconds(5)
);
}
auto with_timeout(IDelayedScheduler &timer, std::chrono::milliseconds duration, Factory factory, OnTimeout on_timeout=OnTimeout::Cancel) -> Task< detail::timeout_factory_value_t< Factory > >
Definition timeout.hpp:376
Quick Reference
| Type | Purpose | Produces Value |
| Task<T> | Lazy coroutine | Yes (T) |
| AsyncCommand<R, Args...> | Three-state async action | Via last_result |
| CoroutineScope | Launch + cancel coroutines | No |
| ViewModelScope | Scope tied to VM lifetime | No |
| CancellationToken | Cooperative cancellation check | No |
| CancellationSource | Cancel producer | No |
| IExecutor | Where to run | No |
See Also