### 2 unstable releases

0.2.0 | Nov 14, 2023 |
---|---|

0.1.0 | May 4, 2023 |

#**1856** in Data structures

**MIT**license

295KB

7K
SLoC

# incremental-rs

A port of Jane Street's Incremental library.

- Pretty rigorous implementation of the basic Incr features, moderately well tested and benchmarked, performs very similarly to the original.
- Partial implementation of incremental-map

### Install

`cargo`` add incremental`

### Examples

Basic usage:

`use` `incremental``::`IncrState`;`
`let` state `=` `IncrState``::`new`(``)``;`
`let` variable `=` state`.``var``(``5``)``;`
`let` times_10 `=` variable`.``map``(``|``num``|` `num ``*` `10``)``;`
`let` observer `=` times_10`.``observe``(``)``;`
`//` stabilise will propagate any changes
state`.``stabilise``(``)``;`
`let` value `=` observer`.``value``(``)``;`
`assert_eq!``(`value`,` `50``)``;`
`//` now mutate
variable`.``set``(``10``)``;`
state`.``stabilise``(``)``;`
`//` watch as var was propagated through the tree, and reached our observer
`assert_eq!``(`observer`.``value``(``)``,` `100``)``;`

Subscriptions, and an illustration of how propagation stops when nodes produce the same value as last time:

`use` `incremental``::``{`IncrState`,` Update`}``;`
`//` A little system to compute the absolute value of an input
`//` Note that the input could change (e.g. 5 to -5), but the
`//` output may stay the same (5 both times).
`let` state `=` `IncrState``::`new`(``)``;`
`let` variable `=` state`.``var``(``5``i32``)``;`
`let` absolute `=` variable`.``map``(``|``num``|` `num``.``abs``(``)``)``;`
`let` observer `=` absolute`.``observe``(``)``;`
`//` set up a subscription.
`use` `std``::``{``cell``::`RefCell`,` `rc``::`Rc`}``;`
`let` latest `=` `Rc``::`new`(``RefCell``::`new`(``None``)``)``;`
`let` latest_clone `=` latest`.``clone``(``)``;`
`let` subscription_token `=` observer`.``subscribe``(``move` `|`update`|` `{`
`*`latest_clone`.``borrow_mut``(``)` `=` `Some``(`update`.``cloned``(``)``)``;`
`}``)``;`
`//` initial stabilisation
state`.``stabilise``(``)``;`
`assert_eq!``(`observer`.``value``(``)``,` `5``)``;`
`assert_eq!``(`latest`.``borrow``(``)``.``clone``(``)``,` `Some``(``Update``::`Initialised`(``5``)``)``)``;`
`//` now mutate, but such that the output of abs() won't change
variable`.``set``(``-``5``)``;`
state`.``stabilise``(``)``;`
`//` The subscription function was not called, because the `absolute` node
`//` produced the same value as last time we stabilised.
`assert_eq!``(`latest`.``borrow``(``)``.``clone``(``)``,` `Some``(``Update``::`Initialised`(``5``)``)``)``;`
`assert_eq!``(`observer`.``value``(``)``,` `5``)``;`
`//` now mutate such that the output changes too
variable`.``set``(``-``10``)``;`
state`.``stabilise``(``)``;`
`//` The observer did get a new value, and did call the subscription function
`assert_eq!``(`latest`.``borrow``(``)``.``clone``(``)``,` `Some``(``Update``::`Changed`(``10``)``)``)``;`
`assert_eq!``(`observer`.``value``(``)``,` `10``)``;`
`//` now unsubscribe. this also implicitly happens if you drop the observer,
`//` but you can individually unsubscribe particular subscriptions if you wish.
observer`.``unsubscribe``(`subscription_token`)``;`
`//` dropping the observer also unloads any part of the computation graph
`//` that was only running for the purposes of this particular observer
`drop``(`observer`)``;`
`//` now that the observer is dead, we can mutate the variable and nothing will
`//` happen, like, at all. The absolute value will not be computed.
variable`.``set``(``100000000``)``;`
`let` recomputed `=` state`.``stats``(``)``.`recomputed`;`
state`.``stabilise``(``)``;`
`assert_eq!``(`recomputed`,` state`.``stats``(``)``.`recomputed`)``;`

#### Dependencies

~385–710KB

~13K SLoC