1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! An implementation of a fine-grained reactive system.
//!
//! Fine-grained reactivity is an approach to modeling the flow of data through an interactive
//! application by composing together three categories of reactive primitives:
//! 1. **Signals**: atomic units of state, which can be directly mutated.
//! 2. **Computations**: derived values, which cannot be mutated directly but update whenever the signals
//! they depend on change. These include both synchronous and asynchronous derived values.
//! 3. **Effects**: side effects that synchronize the reactive system with the non-reactive world
//! outside it.
//!
//! Signals and computations are "source" nodes in the reactive graph, because an observer can
//! subscribe to them to respond to changes in their values. Effects and computations are "subscriber"
//! nodes, because they can listen to changes in other values.
//!
//! ```rust
//! # any_spawner::Executor::init_futures_executor();
//! use reactive_graph::{
//! computed::ArcMemo,
//! effect::Effect,
//! prelude::{Read, Set},
//! signal::ArcRwSignal,
//! };
//!
//! let count = ArcRwSignal::new(1);
//! let double_count = ArcMemo::new({
//! let count = count.clone();
//! move |_| *count.read() * 2
//! });
//!
//! // the effect will run once initially
//! Effect::new(move |_| {
//! println!("double_count = {}", *double_count.read());
//! });
//!
//! // updating `count` will propagate changes to the dependencies,
//! // causing the effect to run again
//! count.set(2);
//! ```
//!
//! This reactivity is called "fine grained" because updating the value of a signal only affects
//! the effects and computations that depend on its value, without requiring any diffing or update
//! calculations for other values.
//!
//! This model is especially suitable for building user interfaces, i.e., long-lived systems in
//! which changes can begin from many different entry points. It is not particularly useful in
//! "run-once" programs like a CLI.
//!
//! ## Design Principles and Assumptions
//! - **Effects are expensive.** The library is built on the assumption that the side effects
//! (making a network request, rendering something to the DOM, writing to disk) are orders of
//! magnitude more expensive than propagating signal updates. As a result, the algorithm is
//! designed to avoid re-running side effects unnecessarily, and is willing to sacrifice a small
//! amount of raw update speed to that goal.
//! - **Automatic dependency tracking.** Dependencies are not specified as a compile-time list, but
//! tracked at runtime. This in turn enables **dynamic dependency tracking**: subscribers
//! unsubscribe from their sources between runs, which means that a subscriber that contains a
//! condition branch will not re-run when dependencies update that are only used in the inactive
//! branch.
//! - **Asynchronous effect scheduling.** Effects are spawned as asynchronous tasks. This means
//! that while updating a signal will immediately update its value, effects that depend on it
//! will not run until the next "tick" of the async runtime. (This in turn means that the
//! reactive system is *async runtime agnostic*: it can be used in the browser with
//! `wasm-bindgen-futures`, in a native binary with `tokio`, in a GTK application with `glib`,
//! etc.)
//!
//! The reactive-graph algorithm used in this crate is based on that of
//! [Reactively](https://github.com/modderme123/reactively), as described
//! [in this article](https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph).
use Arguments;
pub
pub use untrack;
/// Reexports frequently-used traits.
// TODO remove this, it's just useful while developing