rsconnect

Rust crate for fine-grained reactivity

⚠️ Experimental

This crate is in active early development. There may be undiscovered bugs and issues. It is possible there will be breaking changes to API and how it works under the hood.

Goal

This crate allows you to structure change propagation based on graph of data nodes that depend on each other in automatically tracked dependency graph.

Suppose in our system we have data on the number of produced items, the cost of production for each, the number of items we sold, and how much each item is priced for. We would like to calculate total cost and revenue, and then profit out of those. The dependency graph would look like this:

items_produced item_cost items_sold item_price ⬁ ⬀ ⬁ ⬀ total_cost revenue ⬁ ⬀ profit

Every single time items_produced, item_cost, items_sold or item_price is updated, we'd like to recalculate total_cost, revenue and, then, profit. In addition, when profit is updated, we would like to print it with a simple println!. This is what the code for this would look like with rsconnect:

```rust let mut c = Connect::new(); let mut my_effects: Vec = Vec::new();

let itemsproduced = c.observed(25); let itemssold = c.observed(20); let itemcost = c.observed(10.0); let itemprice = c.observed(13.0); let revenue = c.computed( clone!(move |c| *c.get(&itemprice) * *c.get(&itemssold) as f32) ); let totalcost = c.computed( clone!(move |c| *c.get(&itemcost) * *c.get(&itemsproduced) as f32) ); let profit = c.computed( clone!(move |c| *c.get(&revenue) - *c.get(&totalcost)) );

my_effects.push( c.effected( clone!(move |c| *c.get(&profit)), |profit| { println!("Profit: {}", profit) } ) ); ```

This immediately prints:

Profit: 10

In order to change value of any data node and thus trigger change propagation all the way to the underlying effects, one can simply call .set on any of the data nodes:

rust c.set(&items_sold, 25);

This propagates changes to the correct computed and effected nodes and prints:

Profit: 75

Multiple changes may also be batched together so that recalculations only happen once, after the entire batch of nodes change:

rust c.batch(|c| { c.set(&items_produced, 60); c.set(&items_sold, 55); });

Which will print:

Profit: 115

Effected

Effected node consist of 2 parts, computed part and an effect:

rust c.effected( clone!(move |c| *c.get(&profit)), // computed part |profit| { // effect println!("Profit: {}", profit) } )

Computed part subscribes to its dependencies, just like a computed node. Effect is called immediately after recalculation and does not play part in the dependency graph, so it can read values in the graph without being subscribed to them. The result from the computed node is passed to the effect.

Additional notes

TODO