reactive_signals/
lib.rs

1//!
2//! reactive-signals is a dx-first scope-based fine-grained reactive system. It is based on the excellent ideas in
3//! [leptos_reactive](https://crates.io/crates/leptos_reactive) but is written from scratch to
4//! provide the simplest API and mental model possible for developers.
5//!
6//! > This documentation assumes that you know [Leptos](https://crates.io/crates/leptos) and are familiar
7//! > with the concepts of reactivity.
8//! > - <sup>TBD</sup> (to be done) means that the feature will be added in the future.
9//! > - <sup>TBC</sup> (to be confirmed) means that it is a possible future addition
10//! >
11//! > Note: This project is not yet ready for use! It needs a full test coverage first.
12//!
13//!
14//! # Features
15//!
16//! - Slim and powerful API surface. Essentially: [Scope](crate::Scope), [Signal](crate::Signal), [signal!](crate::signal!).
17//! - Developer experience: You create reactive signals and they update automatically in a predictable manner.
18//!   There's not much more to know.
19//! - Memory and performance overhead that is so low that a developer doesn't need to worry about it.
20//! - An easy-to-use [signal!] macro for creating all kinds of signals including data and functional signals,
21//!   server-side and client-side signals etc.
22//! - [Signal]s produce a reactive value, for data signals, it's the inner data and for functional signals,
23//!   it's the value produced by the function. Subscribers are notified when the value is updated,
24//!   or for a value that implements [PartialEq], when it is changed.
25//! - Type-safe attached data to scopes. See the [Scope] doc.<sup>TBD</sup>
26//! - 4 times less memory overhead and 3.5 times faster (worst case) than [leptos_reactive](https://crates.io/crates/leptos_reactive).
27//!   See [Benchmarks](Self#Benchmarks) below.
28//! - Push-pull updates: Guarantees that the nodes are only updated once and only if necessary.
29//!   See the end of the [reactively](https://github.com/modderme123/reactively) readme for more information.<sup>TBC</sup>
30//! - Tokio [tracing](https://crates.io/crates/tracing) compatibility.<sup>TBC</sup>
31//! - async signals with runtimes using a custom async runtime when running in a web browser and
32//!   [tokio](https://crates.io/crates/tokio) when running in a server. See the [signal!] doc.<sup>TBC</sup>
33//! - Mirror the leptos_reactive API with deprecations that give instructions on how to upgrade
34//!   to give a smooth upgrade experience. If there's interest, of course.<sup>TBC</sup>
35//! - Production-class test-coverage.<sup>TBC</sup>
36//! - See [Evolutions](Self#Evolutions) for more possible features.
37//!
38//! # Examples
39//!
40//! See the examples in [Scope](crate::Scope), [Signal](crate::Signal), [signal!](crate::signal!).
41//!
42//! # Cargo features
43//!
44//! - `unsafe-cell`: Internally, the reactive-signals use [RefCell](::core::cell::RefCell) for interior mutability.
45//!   Once reactive-signals is mature and if your app is well tested, then [UnsafeCell](::core::cell::UnsafeCell)
46//!   can be used, resulting in a performance improvement of around 40% and a reduction in memory use by some 20%.
47//!
48//!
49//! # Evolutions
50//!
51//! - **Timetravel**. Due to how reactive-signals is structured it is possible to create state snapshots that can
52//!   be used to create a real-time visualization of the signals, grouped by their
53//!   scope with edges between connected signals. Each outside action or event would trigger
54//!   a new state snapshot. A state snapshot would be visualized by highlighting the
55//!   triggering signal and all its dependencies recursively. When the signal's value implements Debug or Display
56//!   it can be used to visualize its content.
57//! - **Polled signals**. Option to register signals for polling so that a runtime vec will contain all changed signals
58//!   since the last polling. This could be used to group DOM updates into one update per frame avoiding
59//!   the overhead of many small and costly calls out of the WASM. The usefulness of it for Leptos would need to be investigated.
60//! - **Remote shim** (speculative). Everything that goes in or out of a WASM is converted between Rust and JS data.
61//!   It should be possible to put a shim in that serializes it to a remote app. Why do such a thing? It would help to make
62//!   full hot-reloading possible and to apply various tricks for greatly speeding up the compile times.
63//!
64//!
65//! # Benchmarks
66//!
67//! Measurements have been rounded for ease of reading and reasoning. They measure ScopeInner and SignalInner
68//! (not part of public API) which are where the data is stored as Scope and Signal only has index (integer) data
69//!
70//!
71//! ## Performance
72//!
73//! These measurements have been produced using [criterion](https://crates.io/crates/criterion) by measuring on
74//! 1000 instances and calculating the time for one. It has been measured on a Macbook M1.
75//!
76//! | What                 | Time  | With `unsafe-cell`
77//! | ---                  | ---   | ---
78//! | Create a ScopeInner  | 10 ns |  8 ns
79//! | Create a SignalInner | 55 ns | 50 ns
80//! | Notify a subscriber  | 25 ns | 15 ns
81//!
82//! The leptos_reactive profiling example "Leptos create 1000 signals" measures 245 µs.
83//! The same measures 70 µs using reactive-signals. That makes for a 3.5 times improvement.
84//!
85//! ## Memory use
86//!
87//! These measurements has been produced using [dhat](https://crates.io/crates/dhat) by creating
88//! 1000 instances and calculating the size of one.
89//!
90//! | What                     | Heap use | With `unsafe-cell`
91//! | ---                      | ---      | ---
92//! | ScopeInner               | 40 bytes | 32 bytes
93//! | SignalInner              | 80 bytes | 70 bytes
94//! | Subscription<sup>*</sup> | 8 bytes  | 12 bytes
95//!
96//! <sup>*</sup> The memory use for each signal subscription.
97//!
98//! In leptos_reactive, 1000 signals and one memo uses 400kb and
99//! in reactive-signals creating 1000 function signals each with a subscription
100//! uses 100kb. In other words, reactive-signals use 4 times less memory than
101//! leptos_reactive
102//!
103//! Please see the benches, examples and tests for full details.
104//!
105//!
106//! # A personal note & the future of reactive-signals
107//!
108//! I have spent a lot of time on reactive-signals which have been entirely self-funded. Unfortunately,
109//! I cannot continue like that (I would love to, though!).
110//!
111//! The future of reactive-signals depends on you and if you want to fund the features listed with a <sup>TBC</sup>.
112//!
113//! I have created a [fundraiser](https://opencollective.com/human-solutions/projects/reactive-signals) for it.
114//!
115//! I'm open to any type of freelance contract work that would allow me to continue
116//! developing and maintaining the open-source projects I have and plan to do.
117//! See my [services](https://human.solutions/services/).
118//!
119//! See my other [open-source projects](https://human.solutions/opensource/).
120//!
121//! Feel free to reach out if you are interested!
122//!
123
124#[cfg(any(test, feature = "profile"))]
125pub mod tests;
126
127mod arena_tree;
128mod iter;
129mod macros;
130mod primitives;
131pub mod runtimes;
132mod scope;
133mod signals;
134
135#[doc(hidden)]
136pub use arena_tree::{Node, Tree};
137pub use scope::Scope;
138#[doc(hidden)]
139pub use signals::kinds::*;
140pub use signals::Signal;
141
142use runtimes::Runtime;
143use scope::ScopeInner;
144pub use signals::types;
145use std::cell;
146
147#[cfg(not(feature = "unsafe-cell"))]
148type CellType<T> = cell::RefCell<T>;
149#[cfg(feature = "unsafe-cell")]
150type CellType<T> = cell::UnsafeCell<T>;
151
152#[cfg(test)]
153#[test]
154fn update_readme() {
155    markdown_includes::update("src/readme.tpl.md", "../README.md").unwrap();
156}