57template<
typename T,
typename Key>
58struct AsyncResourceState {
61 CancellationSource cancel;
65 Property<bool> is_loading{
false};
66 Property<std::optional<::aria::Error>> error{std::nullopt};
67 Property<std::string> error_message{
""};
68 Property<std::optional<T>> data{std::optional<T>{}};
80 std::atomic<bool> dirty{
false};
81 std::atomic<bool> in_flight{
false};
82 std::atomic<std::uint64_t> gen{0};
84 AsyncResourceState(IExecutor& u, IExecutor& w) : ui(&u), worker(&w) {}
91 void recompute_loadable_() {
92 const bool loading_now = is_loading.peek();
93 const std::optional<T> d = data.peek();
94 const std::optional<::aria::Error> e = error.peek();
123template<
typename T,
typename Key =
int>
125 using State = detail::AsyncResourceState<T, Key>;
126 std::shared_ptr<State> state_;
136 : state_(
std::make_shared<detail::AsyncResourceState<T, Key>>(ui, worker)),
137 fetcher_(
std::move(fetcher)),
153 bool same_key = state_->has_key
154 && state_->current_key == key;
156 if (same_key && !state_->dirty.load(std::memory_order_acquire)
158 &&
data.get().has_value()) {
162 state_->gen.load(std::memory_order_relaxed)});
166 if (same_key && state_->in_flight.load(std::memory_order_acquire)) {
170 state_->gen.load(std::memory_order_relaxed)});
175 state_->current_key = key;
176 state_->has_key =
true;
181 if (!state_->has_key)
return;
183 do_fetch_(state_->current_key);
187 state_->dirty.store(
true, std::memory_order_release);
192 state_->has_key =
false;
193 state_->dirty.store(
false, std::memory_order_release);
194 state_->is_loading =
false;
195 state_->error = std::nullopt;
196 state_->error_message =
"";
197 state_->data = std::optional<T>{};
198 state_->recompute_loadable_();
224 state_->cancel.cancel();
232 state_->gen.fetch_add(1, std::memory_order_acq_rel);
233 state_->in_flight.store(
false, std::memory_order_release);
235 state_->is_loading =
false;
236 state_->recompute_loadable_();
240 state_->gen.load(std::memory_order_relaxed)});
269 void do_fetch_(Key key) {
270 state_->in_flight.store(
true, std::memory_order_release);
271 state_->dirty.store(
false, std::memory_order_release);
272 auto my_gen = state_->gen.fetch_add(1, std::memory_order_acq_rel) + 1;
279 state_->is_loading =
true;
280 state_->error = std::nullopt;
281 state_->error_message =
"";
282 state_->recompute_loadable_();
287 auto runner = run_one_(key, my_gen);
288 std::move(runner).start_detached();
291 Task<void> run_one_(Key key, std::uint64_t my_gen) {
293 auto fetcher = fetcher_;
294 auto tok = state->cancel.token();
297 tok.throw_if_cancelled();
298 state->is_loading =
true;
299 state->error = std::nullopt;
300 state->error_message =
"";
301 state->recompute_loadable_();
303 std::exception_ptr ex;
304 std::optional<T> result;
307 tok.throw_if_cancelled();
308 T v =
co_await fetcher(key);
309 result.emplace(std::move(v));
311 ex = std::current_exception();
315 tok.throw_if_cancelled();
324 if (state->gen.load(std::memory_order_acquire) != my_gen) {
333 try { std::rethrow_exception(ex); }
334 catch (
const OperationCancelled&) {
340 ::aria::trace::Async{
"AsyncResource",
"cancelled", my_gen},
344 catch (
const TimeoutError& e) {
346 err.message = e.what();
349 ::aria::trace::Async{
"AsyncResource",
"timeout", my_gen},
352 state->error_message = err.message;
353 state->error = std::move(err);
359 ::aria::trace::Async{
"AsyncResource",
"failure", my_gen},
362 state->error_message = err.message;
363 state->error = std::move(err);
366 state->data = result;
369 ::aria::trace::Async{
"AsyncResource",
"fetch_finish", my_gen});
372 state->is_loading =
false;
373 state->in_flight.store(
false, std::memory_order_release);
374 state->recompute_loadable_();
static Loadable loading()
Definition loadable.hpp:81
static Loadable refreshing(T prior)
Build a Refreshing state from an existing Success payload.
Definition loadable.hpp:89
const Error * error() const noexcept
Returns a pointer to the error if has_error(), else nullptr.
Definition loadable.hpp:160
static Loadable success(T v)
Definition loadable.hpp:96
static Loadable idle() noexcept
Definition loadable.hpp:79
void clear()
Definition async_resource.hpp:190
AsyncResource(const AsyncResource &)=delete
Property< std::string > & error_message
Definition async_resource.hpp:259
Property< std::optional< T > > & data
Definition async_resource.hpp:260
AsyncResource & operator=(const AsyncResource &)=delete
Property<::aria::Loadable< T > > & loadable
Five-state loadable view-model – Idle / Loading / Refreshing / Success / Error.
Definition async_resource.hpp:266
void fetch(Key key)
Fetch for key.
Definition async_resource.hpp:152
Property< bool > & is_loading
Definition async_resource.hpp:257
AsyncResource(IExecutor &ui, IExecutor &worker, Fetcher fetcher)
Definition async_resource.hpp:135
void cancel()
Cancel any in-flight fetch and drop its pending write-back, WITHOUT destroying the resource.
Definition async_resource.hpp:219
bool has_data() const
Definition async_resource.hpp:244
~AsyncResource()
Definition async_resource.hpp:144
void invalidate() noexcept
Definition async_resource.hpp:186
void refresh()
Definition async_resource.hpp:180
std::function< Task< T >(Key)> Fetcher
Definition async_resource.hpp:129
Property< std::optional<::aria::Error > > & error
Definition async_resource.hpp:258
Definition cancellation.hpp:218
Abstract executor interface — schedules a callable to run "somewhere".
Definition executor.hpp:36
Definition property.hpp:103
Definition async_command.hpp:118
auto schedule_on(IExecutor &exec)
Schedule a coroutine to resume on the given executor.
Definition executor.hpp:396
void publish_trace_unchecked(const TraceEvent &event) noexcept
Publish an already-built event using one owning sink snapshot.
Definition diagnostics.hpp:293
bool has_trace_sink() noexcept
True iff a sink is currently installed.
Definition diagnostics.hpp:286
@ Async
AsyncCommand / AsyncResource lifecycle.
Definition diagnostics.hpp:68
Definition validation_key.hpp:110
static Error from_exception(std::exception_ptr ex, std::string source_tag)
Catch-all converter from a thrown exception_ptr to a typed Error.
Definition error.hpp:237
static Error cancellation(std::string source_tag="AsyncCommand")
Cancellation.
Definition error.hpp:192
static Error timeout(std::string source_tag="AsyncCommand")
with_timeout deadline expired.
Definition error.hpp:198
Async lifecycle.
Definition diagnostics.hpp:128