1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! # Depends
//!
//! A library for ergonomic, performant, incremental computation between
//! arbitrary types.
//!
//! ## Why would I want that
//!
//! Most applications rely on some core logic which must respond to external
//! events. Often, the logic to transform each event in to an action is
//! straightforward, but as the application scales, many hard to reason-with
//! situations emerge from the combinatorial explosion of states.
//!
//! Dependency graphs are an excellent code architecture to tame complexity in
//! such scenarios.
//!
//! ```
//! use std::{collections::HashSet, hash::Hash, rc::Rc};
//!
//! use depends::{
//! core::{
//! Dependency, Depends, HashValue, LeafNode, NodeHash, Resolve, UpdateDependee, UpdateLeaf,
//! },
//! derives::{dependencies, Dependee, Leaf},
//! };
//!
//! // A `Leaf` is a node which takes new values from outside the graph. Nodes must currently
//! // implement `Hash`, attribute a hashable field as `#[depends(hash)]` or specify `#[depends(unhashable)]`.
//! #[derive(Leaf, Default, Hash)]
//! pub struct NumberInput {
//! value: i32,
//! }
//!
//! // `Leaf` types must provide a way for code outside to update their internal state.
//! // This is just a simple replace for now.
//! impl UpdateLeaf for NumberInput {
//! type Input = i32;
//!
//! fn update_mut(&mut self, input: Self::Input) {
//! self.value = input;
//! }
//! }
//!
//! // `dependencies` are derived to state what references `Dependee` nodes need to
//! // calculate their state on-demand. These could be any number of other `Dependee`s
//! // or `Leaf`s.
//! #[dependencies]
//! pub struct Components {
//! left: LeafNode<NumberInput>,
//! right: LeafNode<NumberInput>,
//! }
//!
//! // A `Dependee` i.e. its state is a pure transformation of other nodes
//! #[derive(Dependee, Default, Hash)]
//! #[depends(dependencies = Components)]
//! pub struct Sum {
//! value: i32,
//! }
//!
//! // This trait specifies how a `Dependee` updates its internal state given its dependencies.
//! impl UpdateDependee for Sum {
//! fn update_mut(&mut self, input: <Self as Depends>::Input<'_>) {
//! // `ComponentsRef` is auto-generated by `dependencies`. It's a read-reference
//! // to each field of `Components`
//! let ComponentsRef { left, right } = input;
//! self.value = left.value + right.value;
//! }
//! }
//!
//! struct MyGraph {
//! left: Rc<LeafNode<NumberInput>>,
//! right: Rc<LeafNode<NumberInput>>,
//! // `SumNode` is auto-generated by `Dependee`.
//! sum: Rc<SumNode>,
//! }
//!
//! // Compose a graph!
//! let left = NumberInput::default().into_leaf();
//! let right = NumberInput::default().into_leaf();
//! let sum = Sum::default().into_node(Components::new(Rc::clone(&left), Rc::clone(&right)));
//!
//! let graph = MyGraph { left, right, sum };
//!
//! // A `Visitor` is a collection which tracks which nodes have been visited each run.
//! let mut visitor = HashSet::<usize>::new();
//!
//! // Resolving the graph from any node will traverse via Depth First Search, prompting
//! // recalculation for any node whos dependencies have changed since last resolved.
//! assert_eq!(graph.sum.resolve_root(&mut visitor).value, 0);
//!
//! // update the leaves
//! graph.left.update(2);
//! graph.right.update(2);
//!
//! // We've successfully implemented simple addition! Only nodes which have dirty parents
//! // will be recalculated.
//! assert_eq!(graph.sum.resolve_root(&mut visitor).value, 4);
//! ```
//!
//! Clearly, to implement a simple addition problem, a dependency graph is
//! overkill. However, for more complex problems, where many inputs can change
//! and the output is a combination of many transformations on that input (and
//! derivations of it), `depends` can help you produce scalable, performant,
//! testable code out of the box.
#![cfg_attr(doc_cfg, feature(doc_cfg, doc_auto_cfg))]
pub mod core {
pub use depends_core::execution::*;
}
pub mod derives {
pub use depends_derives::*;
}
/// Visualisation tool for graphs.
#[cfg(feature = "graphviz")]
pub mod graphviz;