Dependencies

In most real-world applications, you'll have nodes that depend on multiple other nodes. Depends allows you to define complex dependencies using Dependencies tuples.

Here's an example where an operation depends on two numbers and multiplies them:


impl UpdateDerived<DepRef2<'_, SomeNumber, SomeNumber>, Multiply> for SomeNumber {
    fn update(&mut self, deps: DepRef2<'_, SomeNumber, SomeNumber>) -> Result<(), EarlyExit> {
        self.value = deps.0.value * deps.1.value;
        Ok(())
    }
}

fn main() {
    // Define our inputs to the graph.
    let a = InputNode::new(SomeNumber { value: 7 });
    let b = InputNode::new(SomeNumber { value: 6 });
    // This type has a `Resolve::Output<'_> of 'DepRef2<'_, SomeNumber,
    // SomeNumber>`, so it's compatible with our implementation of `Multiply`
    // above.
    let dependencies = Dependencies2::new(a, Rc::clone(&b));
    let a_times_b = DerivedNode::new(dependencies, Multiply, SomeNumber::default());
    // Any node which holds `SomeNumber` can be used to create more dependencies in
    // this graph.
    let dependencies_2 = Dependencies2::new(a_times_b, b);
    let a_times_b_times_b = DerivedNode::new(dependencies_2, Multiply, SomeNumber::default());
}

You can connect up to 16 dependencies to a single node by using the approriate DependenciesN type.

Checking Specific Dependency State

There are situations where it's useful to know which specific dependencies have caused update_mut to be called. For this reason, the is_dirty method is available on each dependency reference.

#[derive(Value, Hash)]
pub struct StuffToBuy {
    amount: i32,
    last_purchase_time: i64,
}

#[derive(Operation)]
pub struct CheckBankBalance;

// A dependency of time and money.
impl UpdateDerived<DepRef2<'_, i64, i32>, CheckBankBalance> for StuffToBuy {
    fn update(&mut self, deps: DepRef2<'_, i64, i32>) -> Result<(), EarlyExit> {
        // Is dirty is a trait implemented on all dependencies to indicate
        // that the inner value of this node has changed since last observed.
        if !deps.1.is_dirty() {
            // Time's always changing, we don't need to check it.
            return Ok(());
        }
        // It's been a while since we've bought anything and we've just been
        // paid.
        if deps.0.value() - self.last_purchase_time > 24 * 60 * 60 {
            self.last_purchase_time = *deps.0.value();
            self.amount = deps.1.value() / 10;
        }
        Ok(())
    }
}

The most common is example is time. It's expected that no node uses methods such as Utc::now(), as this is a side-effect which will result in non-deterministic behaviour.

Instead, you should 'set' the time for the graph by providing it as an Input Node and creating edges to the nodes which require it.