Expand description
§Depends
A library for ergonomic, performant, incremental computation between arbitrary types.
For more information, see:
§Motivation
Many applications which respond to changes from multiple input sources benefit from the use of dependency graphs as code structure. By breaking complex states down in to small pieces of testable, composable logic, scaling and maintaining applications becomes much easier over time. Additionally, incremental computation allows results of previous calculations to be reused where possible, improving overall efficiency and performance.
Depends aims to present the smallest possible API surface for building minimal runtime-overhead dependency graphs in Rust, whilst leveraging the compile-time guarantees of the type-system.
// Below are input nodes, which are nodes which take new values from
// outside the graph.
// It's not common to use primitives, but they make for a simple example.
let a = InputNode::new(7_i64);
let b = InputNode::new(6_i32);
// Derived nodes take their value from other nodes (either input or
// derived). Note that we can combine _any_ type of node, providing
// they're compatible with the dependencies (`TwoNumbers`) and operation
// (`Multiply`).
let c = DerivedNode::new(
Dependencies2::new(Rc::clone(&a), Rc::clone(&b)),
Multiply,
0_i64,
);
// A visitor tracks which nodes have been visited during a resolve.
let mut visitor = HashSetVisitor::new();
// Resolve the graph!
// `resolve_root` will clear the visitor before returning, readying it
// for the next resolution.
// This can fail if there are cycles in the graph or an existing read
// reference is being held.
assert_eq!(c.resolve_root(&mut visitor).unwrap().value().clone(), 42);
// Nodes which have an edge to dependencies which are updated between
// resolves will recalculate their state on-demand. Others will return
// a cached value. This is known as incremental computation, and can
// vastly improve performance of complex calculations.
a.update(70).unwrap();
// Any dependent values will be updated next time the graph is resolved.
assert_eq!(c.resolve_root(&mut visitor).unwrap().value().clone(), 420);
Modules§
Structs§
- Dependencies2
- Dependencies3
- Dependencies4
- Dependencies5
- Dependencies6
- Dependencies7
- Dependencies8
- Dependencies9
- Dependencies10
- Dependencies11
- Dependencies12
- Dependencies13
- Dependencies14
- Dependencies15
- Dependencies16
- Dependency
- Wraps a dependency and tracks the hashed value each time it’s resolved. This allows the resolver to know if a dependency is ‘dirty’ from the perspective of the Dependee.
- Dependency
Edge - A read reference to the resolved state of a Dependency. This is an edge in the dependency graph.
- Dependency
Reference2 - Dependency
Reference3 - Dependency
Reference4 - Dependency
Reference5 - Dependency
Reference6 - Dependency
Reference7 - Dependency
Reference8 - Dependency
Reference9 - Dependency
Reference10 - Dependency
Reference11 - Dependency
Reference12 - Dependency
Reference13 - Dependency
Reference14 - Dependency
Reference15 - Dependency
Reference16 - Derived
Node - Derived Node
- Input
Node - Input Node
- Node
State - A wrapper for some value
T
, tracking some context around the value’s computation state.
Enums§
- Dependency
State - Whether this dependency has a hash value which is different to the one previously observed (if any).
- Input
State - Used to ensure that pending data is resolved at most once between calls to
update
. - Node
Hash - A Hash of the current node state used to signal whether a dependent node needs to update its internal state.
Traits§
- Clean
- For the majority of cases, this trait can be ignored, and a default implementation (no-op) can be used.
- Graph
Create - Convenience so that types which derive
Graph
can be easily accessed. - Hash
Value - A unique number derived from the internal state of a node.
- Identifiable
- A unique integer value assigned to each node created in a particular runtime, allowing a Visitor to track visited nodes when resolving graphs.
- IsDirty
- For any dependee’s dependencies (or single Dependency), this is used to check whether previously observed values have changed, indicating its stored value needs to be recomputed.
- Named
- A string name for each graph node, useful for rendering graph visualisations.
- Resolve
- A Depth-first search resolver, used to recursively pass a Visitor through a graph, updating dependencies.
- Update
Derived - Update
Input - Describe how to update an InputNode value, and how that mutates the internal state. Correct implementation of this trait requires that any temporary state tracked is cleared up when implementing Clean.
- Visitor
- A collection passed in to a graph, tracking the identifiers of each nodes to avoid traversing