56class ReactionNode final :
public Node,
public std::enable_shared_from_this<ReactionNode> {
58 explicit ReactionNode(std::function<
void()> fn)
66 ~ReactionNode() noexcept
override {
70 [[nodiscard]] std::shared_ptr<Node> retain_for_recompute() noexcept
override {
71 return weak_from_this().lock();
76 bool recompute()
override {
84 void observe_source(
Node& src) {
88 edges_.push_back(std::make_unique<Edge>());
93 std::function<void()> fn_;
94 std::vector<std::unique_ptr<Edge>> edges_;
102template<PropertyValue T>
113 static_assert(std::copyable<T>,
114 "Property<T> requires T to be copyable for snapshot reads. "
115 "If T is move-only, store it via "
116 "std::shared_ptr<T> or model the state with an ObservableList<T>.");
118 "Property<T> requires T to be equality-comparable (==/!=): writes "
119 "with the same value are silently dropped. Provide an operator== "
120 "for T or wrap it in a thin struct that defines one.");
138 [[nodiscard]] T
get()
const {
140 t->record_read(
const_cast<Property&
>(*
this));
152 t->record_read(
const_cast<Property&
>(*
this));
164 [[nodiscard]] T
peek() const noexcept(
std::is_nothrow_copy_constructible_v<T>) {
169 [[nodiscard]]
const T&
peek_ref() const noexcept {
return value_; }
173 operator T()
const {
return get(); }
179 void set(
const T& new_val) { set_impl_(new_val); }
180 void set(T&& new_val) { set_impl_(std::move(new_val)); }
188 template<std::invocable<T&> Fn>
190 std::forward<Fn>(fn)(value_);
201 auto reaction = std::make_shared<detail::ReactionNode>(
202 [
this, fn = std::move(fn)] { fn(value_); });
203 reaction->set_debug_name(
"Property::on_changed");
204 reaction->observe_source(*
this);
205 return ::aria::Subscription{std::move(reaction)};
212 const detail::NodeHandle alive{
this};
214 if (!alive)
return {};
221 auto last = std::make_shared<T>(value_);
222 return on_changed([fn = std::move(fn), last](
const T& v) {
223 T old = std::move(*last);
237 [[nodiscard]] std::any
get_any()
const override {
238 return std::any{
get()};
241 [[nodiscard]]
bool set_any(
const std::any& value)
override {
242 if (
auto* typed = std::any_cast<T>(&value)) {
250 std::function<
void(
const std::any&)> on_changed_any)
override {
251 return on_changed([cb = std::move(on_changed_any)](
const T& v) {
256 [[nodiscard]]
const std::type_info&
type() const noexcept
override {
262 void set_impl_(U&& new_val) {
264 if (value_ == new_val)
return;
271 T tmp(std::forward<U>(new_val));
Type-erased Property surface.
Definition i_property.hpp:51
Property(T initial=T{})
Definition property.hpp:122
RAII handle to a single subscription.
Definition subscription.hpp:44
void assert_on_graph_thread() const noexcept
Definition graph.hpp:155
Common base for every node participating in the reactive graph.
Definition node.hpp:136
static Graph & graph() noexcept
Returns the process-wide singleton Graph this node belongs to.
Definition graph.inl:30
void notify_changed()
Called by a Source after its value has actually changed: bumps the version and colors all downstream ...
Definition graph.inl:117
Node(NodeKind kind) noexcept
Definition node.hpp:144
void retire_() noexcept
Retire before derived members (including user captures) are destroyed.
Definition graph.inl:42
void attach_as_observer_of(Node &source, Edge &edge) noexcept
Definition graph.inl:64
bool set_any(const std::any &value) override
Try to set the property's value from a std::any.
Definition property.hpp:241
T value_type
Definition property.hpp:105
Property & operator=(T &&v)
Definition property.hpp:183
T peek() const noexcept(std::is_nothrow_copy_constructible_v< T >)
Snapshot read that does NOT register a dependency.
Definition property.hpp:164
Property(T initial=T{})
Definition property.hpp:122
const T & peek_ref() const noexcept
Snapshot read by const reference (never tracks, never copies).
Definition property.hpp:169
Property & operator=(const T &v)
Definition property.hpp:182
void set(T &&new_val)
Definition property.hpp:180
void set(const T &new_val)
Commit a new value.
Definition property.hpp:179
::aria::Subscription observe(std::function< void(const T &, const T &)> fn)
Two-argument form: receive (old, new).
Definition property.hpp:220
Property(const Property &)=delete
Property & operator=(Property &&)=delete
T get() const
Auto-tracked read.
Definition property.hpp:138
~Property() noexcept override
Definition property.hpp:125
::aria::Subscription bind(std::function< void(const T &)> fn)
Fire once with the current value, then on every subsequent change.
Definition property.hpp:210
::aria::Subscription subscribe_any(std::function< void(const std::any &)> on_changed_any) override
Subscribe to value changes.
Definition property.hpp:249
const std::type_info & type() const noexcept override
The runtime type of the wrapped value.
Definition property.hpp:256
Property(Property &&)=delete
std::any get_any() const override
Read the current value as a std::any.
Definition property.hpp:237
void mutate(Fn &&fn)
Mutate-in-place: always fires a change (cannot detect no-op because the mutation is opaque).
Definition property.hpp:189
Property & operator=(const Property &)=delete
::aria::Subscription on_changed(std::function< void(const T &)> fn)
Run fn(new_value) every time the value changes.
Definition property.hpp:200
const T & get_ref() const
Auto-tracked read by const reference.
Definition property.hpp:150
Type that supports == and != (required for change detection).
Definition concepts.hpp:30
Definition computed.hpp:60
NodeKind
Definition node.hpp:87
@ Reaction
Definition node.hpp:90
@ Source
Definition node.hpp:88
TrackingContext * current_tracker() noexcept
Returns the current tracker of the global graph.
Definition graph.hpp:300
Definition validation_key.hpp:110