Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
executor_traits.hpp
Go to the documentation of this file.
1#pragma once
2
3// Executor traits — declare which executors are safe to use in which
4// roles, so that components like `AsyncCommand` can statically reject
5// unsafe combinations.
6//
7// Two orthogonal capabilities are encoded:
8//
9// is_safe_graph_executor_v<E>
10// E may be passed as the **graph-thread (UI) executor**. Calls to
11// `co_await schedule_on(ui)` from a worker thread must end up
12// resuming on the executor's owner thread (the thread that owns
13// the reactive graph), NOT on the calling worker thread.
14//
15// is_safe_worker_executor_v<E>
16// E may be passed as the **worker executor**. Worker tasks may run
17// on any thread (typically a thread pool), as long as the worker
18// never directly writes reactive state — that is the contract that
19// `AsyncCommand` enforces by always hopping back to the graph
20// executor before touching `Property<T>`.
21//
22// Default: both are `false`. Custom executors must opt in by
23// specialising the trait or by inheriting from the marker base classes
24// declared below (CRTP-style markers are deliberately avoided so that
25// users can also retrofit traits onto third-party executor classes).
26//
27// To opt in for an external type:
28//
29// namespace aria::async {
30// template<> struct is_safe_graph_executor<MyMainLoop> : std::true_type {};
31// }
32
34
35#include <type_traits>
36
37namespace aria::async {
38
39// ── primary trait templates (default: false) ──────────────────────────────
40template<typename E> struct is_safe_graph_executor : std::false_type {};
41template<typename E> struct is_safe_worker_executor : std::false_type {};
42
43template<typename E>
45template<typename E>
47
48// ── built-in executor specialisations ─────────────────────────────────────
49
50// InlineExecutor: safe for both roles ONLY when both ui and worker are
51// inline (single-threaded scenarios). The combination of "InlineExecutor
52// graph + multi-threaded worker" is rejected by `AsyncCommand` via a
53// dedicated static_assert; see `async_command.hpp`.
54template<> struct is_safe_graph_executor<InlineExecutor> : std::true_type {};
55template<> struct is_safe_worker_executor<InlineExecutor> : std::true_type {};
56
57// ThreadPoolExecutor: worker only. Property writes from a pool thread
58// would race the reactive graph's owner-thread invariant.
59template<> struct is_safe_worker_executor<ThreadPoolExecutor> : std::true_type {};
60
61// MainThreadExecutor: safe for both. Owner-thread is bound on first
62// pump and asserted thereafter, which is exactly the reactive graph's
63// expectation.
64template<> struct is_safe_graph_executor<MainThreadExecutor> : std::true_type {};
65template<> struct is_safe_worker_executor<MainThreadExecutor> : std::true_type {};
66
67// ── concept aliases ──────────────────────────────────────────────────────
68template<typename E>
69concept SafeGraphExecutor = std::is_base_of_v<IExecutor, E>
71
72template<typename E>
73concept SafeWorkerExecutor = std::is_base_of_v<IExecutor, E>
75
76} // namespace aria::async
Inline executor — runs callable synchronously on the calling thread.
Definition executor.hpp:184
Main-thread executor — queues callables for later execution on the thread that "owns" the executor (t...
Definition executor.hpp:247
Thread pool executor.
Definition executor.hpp:71
Definition executor_traits.hpp:69
Definition executor_traits.hpp:73
Definition async_command.hpp:118
constexpr bool is_safe_worker_executor_v
Definition executor_traits.hpp:46
constexpr bool is_safe_graph_executor_v
Definition executor_traits.hpp:44
Definition executor_traits.hpp:40
Definition executor_traits.hpp:41