Struct RxDAG

Source
pub struct RxDAG<'c>(/* private fields */);
Expand description

The centralized structure which contains all your interconnected reactive values.

This structure is a directed-acyclic-graph (DAG), hence why its called RxDAG. We don’t support computed values recursively depending on each other, which is why it’s acyclic. At the root/top of the DAG are your variables (Var), which you can explicitly set. All other values are CRxs, which are computed. CRx incoming edges are inputs, which are Vars and other CRxs. CRx outgoing edges are outputs, which are more CRxs, but there are also “edges” which just go nowhere, those are side-effects.

§Performance notes

Currently no nodes (Vars or CRxs) are deallocated until the entire DAG is deallocated, so if you keep creating and discarding nodes you will leak memory (TODO fix this?)

§Implementation

Internally this is a vector of interspersed nodes and edges. The edges refer to other nodes relative to their own position. Later Rxs must depend on earlier Rxs. “edges” can have zero outputs, those are side-effects as mentioned above.

When the DAG recomputes, it simply iterates through each node and edge in order and calls [RxDAGElem::recompute]. If the nodes were changed (directly or as edge output), they set their new value, and mark that they got recomputed. The edges will recompute and change their output nodes if any of their inputs got recomputed.

The DAG has interior mutability, in that it can add nodes without a mutable borrow. See elsa crate for why this is sound (though actually the soundness argument is contested). Internally we use a modified version of elsa and stable-deref-trait. which lets us return lifetime-parameterized values instead of references among other things.

Setting Vars is also interior mutability, and OK because we don’t use those values until [RxDAGElem::recompute].

The DAG and refs have an ID so that you can’t use one ref on another DAG, however this is checked at runtime. The lifetimes are checked at compile-time though.

Implementations§

Source§

impl<'c> RxDAG<'c>

Source

pub fn new() -> Self

Create an empty DAG

Source

pub fn new_var<T: 'c>(&self, init: T) -> Var<'c, T>

Create a variable (Var) in this DAG.

Source

pub fn run_crx<F: FnMut(RxInput<'_, 'c>) + 'c>(&self, compute: F)

Run a closure when inputs change, without creating any outputs (for side-effects).

Source

pub fn new_crx<T: 'c, F: FnMut(RxInput<'_, 'c>) -> T + 'c>( &self, compute: F, ) -> CRx<'c, T>

Create a computed value (CRx) in this DAG.

Source

pub fn new_crx2<T1: 'c, T2: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2) + 'c>( &self, compute: F, ) -> (CRx<'c, T1>, CRx<'c, T2>)

Create 2 computed values (CRxs) in this DAG which are created from the same function.

Source

pub fn new_crx3<T1: 'c, T2: 'c, T3: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2, T3) + 'c>( &self, compute: F, ) -> (CRx<'c, T1>, CRx<'c, T2>, CRx<'c, T3>)

Create 3 computed values (CRxs) in this DAG which are created from the same function.

Source

pub fn new_crx4<T1: 'c, T2: 'c, T3: 'c, T4: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2, T3, T4) + 'c>( &self, compute: F, ) -> (CRx<'c, T1>, CRx<'c, T2>, CRx<'c, T3>, CRx<'c, T4>)

Create 4 computed values (CRxs) in this DAG which are created from the same function.

Source

pub fn new_crx5<T1: 'c, T2: 'c, T3: 'c, T4: 'c, T5: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2, T3, T4, T5) + 'c>( &self, compute: F, ) -> (CRx<'c, T1>, CRx<'c, T2>, CRx<'c, T3>, CRx<'c, T4>, CRx<'c, T5>)

Create 5 computed values (CRxs) in this DAG which are created from the same function.

Source

pub fn recompute(&mut self)

Update all Vars with their new values and recompute CRxs.

This requires a shared reference and actually does the “reactive updates”.

Source

pub fn now(&mut self) -> RxDAGSnapshot<'_, 'c>

Recomputes if necessary and then returns an RxContext you can use to get the current value.

Source

pub fn stale(&self) -> RxDAGSnapshot<'_, 'c>

Returns an RxContext you can use to get the current value. However any newly-set values or computations will not be returned until RxDAG::recompute is called.

Trait Implementations§

Source§

impl<'c> Debug for RxDAG<'c>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a, 'c: 'a> MutRxContext<'a, 'c> for &'a RxDAG<'c>

Source§

fn sub_dag(self) -> RxSubDAG<'a, 'c>

Auto Trait Implementations§

§

impl<'c> !Freeze for RxDAG<'c>

§

impl<'c> !RefUnwindSafe for RxDAG<'c>

§

impl<'c> !Send for RxDAG<'c>

§

impl<'c> !Sync for RxDAG<'c>

§

impl<'c> Unpin for RxDAG<'c>

§

impl<'c> !UnwindSafe for RxDAG<'c>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.