Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
view_model_scope.hpp
Go to the documentation of this file.
1#pragma once
2
3// ViewModelScope — wires CoroutineScope into a ViewModel so that destroying
4// the VM cancels every coroutine launched into it AND waits for them to
5// exit before VM teardown returns.
6//
7// Usage (inside a ViewModel subclass):
8//
9// class MyVm : public ViewModel {
10// public:
11// MyVm() { scope_.attach(*this); }
12//
13// void start_polling() {
14// scope_.launch([this](async::CancellationToken tok) -> async::Task<void> {
15// while (!tok.is_cancelled()) {
16// co_await schedule_after(timer_, 1s);
17// tok.throw_if_cancelled();
18// poll_data();
19// }
20// });
21// }
22// private:
23// binding::ViewModelScope scope_;
24// };
25//
26// Declare the scope after the VM members used by its work (members are
27// destroyed in reverse order). Its destructor cancels and joins before those
28// members are torn down. If work touches state destroyed by a custom VM
29// destructor body, call cancel_and_join() at the start of that body.
30//
31// When MyVm is destroyed: the scope calls
32// `cancel_and_join()` (bounded by `kJoinTimeoutMs`, default 5 s). It
33// cancels the source synchronously, then blocks until every wrapper
34// coroutine has decremented the inflight counter to zero. If any
35// coroutine is stuck on a non-cancellable await, the leak is reported
36// through the async error sink (see <aria/async/async_error_sink.hpp>)
37// and teardown returns rather than blocking process shutdown
38// indefinitely.
39
41#include "aria/async/scope.hpp"
43
44#include <chrono>
45#include <cstddef>
46#include <memory>
47#include <utility>
48
49namespace aria::binding {
50
52public:
58 static constexpr std::chrono::milliseconds kJoinTimeoutMs{5000};
59
60 ViewModelScope() : state_(std::make_shared<State>()) {}
61
62 ~ViewModelScope() { shutdown_(*state_); }
67
74 void attach(ViewModel& vm) {
75 auto keep = state_;
76 vm.add_destroy_hook([keep]() noexcept {
77 // Structured-concurrency boundary: cancel + wait. If any
78 // coroutine is stuck, CoroutineScope reports the leak
79 // through the async error sink (see scope.hpp).
80 shutdown_(*keep);
81 });
82 }
83
84 [[nodiscard]] async::CancellationToken token() const noexcept {
85 return state_->scope.token();
86 }
87 [[nodiscard]] bool is_cancelled() const noexcept {
88 return state_->scope.is_cancelled();
89 }
90 [[nodiscard]] std::size_t inflight_count() const noexcept {
91 return state_->scope.inflight_count();
92 }
93
95 void cancel() noexcept { state_->scope.cancel(); }
96
99 bool cancel_and_join(std::chrono::milliseconds timeout = kJoinTimeoutMs) noexcept {
100 return state_->scope.cancel_and_join(timeout);
101 }
102
103 template<typename Fn>
104 void launch(Fn factory) { state_->scope.launch(std::move(factory)); }
105
107 state_->scope.launch_simple(std::move(task));
108 }
109
110private:
111 struct State {
113 bool teardown_started = false;
114 };
115 static void shutdown_(State& state) noexcept {
116 if (std::exchange(state.teardown_started, true)) return;
117 state.scope.cancel_and_join(kJoinTimeoutMs);
118 }
119 std::shared_ptr<State> state_;
120};
121
122} // namespace aria::binding
Definition cancellation.hpp:182
Definition scope.hpp:75
Definition task.hpp:78
Base class for view models.
Definition view_model.hpp:32
void add_destroy_hook(std::function< void()> hook)
std::size_t inflight_count() const noexcept
Definition view_model_scope.hpp:90
bool is_cancelled() const noexcept
Definition view_model_scope.hpp:87
void launch(Fn factory)
Definition view_model_scope.hpp:104
ViewModelScope(ViewModelScope &&)=delete
ViewModelScope & operator=(ViewModelScope &&)=delete
void launch_simple(async::Task< void > task)
Definition view_model_scope.hpp:106
ViewModelScope & operator=(const ViewModelScope &)=delete
ViewModelScope(const ViewModelScope &)=delete
ViewModelScope()
Definition view_model_scope.hpp:60
static constexpr std::chrono::milliseconds kJoinTimeoutMs
Default timeout for cancel_and_join() invoked from the VM's destroy-hook.
Definition view_model_scope.hpp:58
void cancel() noexcept
Request cancellation only (non-blocking).
Definition view_model_scope.hpp:95
async::CancellationToken token() const noexcept
Definition view_model_scope.hpp:84
bool cancel_and_join(std::chrono::milliseconds timeout=kJoinTimeoutMs) noexcept
Cancel + synchronously wait for all in-flight coroutines to exit, with the given timeout.
Definition view_model_scope.hpp:99
void attach(ViewModel &vm)
Tie this scope's lifetime to the ViewModel's destructor.
Definition view_model_scope.hpp:74
~ViewModelScope()
Definition view_model_scope.hpp:62
Definition binding_engine.hpp:25
Definition validation_key.hpp:110