pub struct Graph<NodeT, Arena = <NodeT as NodeEnum>::GenArena>{ /* private fields */ }Expand description
A graph with typed nodes
The graph can only by modified by commiting a transaction, which avoids mutable borrow of the graph
§Example:
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA{
link: NodeIndex,
data: usize,
}
#[derive(TypedNode, Debug)]
struct NodeB{
links: BTreeSet<NodeIndex>,
another_data: String,
}
node_enum!{
#[derive(Debug)]
enum Node{
A(NodeA),
B(NodeB)
}
}
let ctx = Context::new();
let mut graph = Graph::<Node>::new(&ctx);
let mut trans = Transaction::new(&ctx);
// Does some operations on the transaction
graph.commit(trans).unwrap();Implementations§
Source§impl<NodeT, Arena> Graph<NodeT, Arena>
impl<NodeT, Arena> Graph<NodeT, Arena>
Sourcepub fn get(&self, idx: NodeIndex) -> Option<&NodeT>
pub fn get(&self, idx: NodeIndex) -> Option<&NodeT>
Get the reference of a node. For convinience, if the type of the node is previously known, use get_node!() instead.
§Example
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA{
data: usize,
}
node_enum!{
#[derive(Debug)]
enum Node{
A(NodeA)
}
}
let ctx = Context::new();
let mut graph = Graph::<Node>::new(&ctx);
let mut trans = Transaction::new(&ctx);
let idx = trans.insert(Node::A(NodeA{
data: 1
}));
graph.commit(trans).unwrap();
// node: Option<&Node>
let node = graph.get(idx);
if let Some(Node::A(node)) = node {
assert_eq!(node.data, 1);
} else {
panic!();
}
assert!(graph.get(NodeIndex::empty()).is_none());Sourcepub fn iter(&self) -> Arena::Iter<'_>
pub fn iter(&self) -> Arena::Iter<'_>
Iterate all nodes in the graph following the order of NodeIndex.
If only a type of node is wanted, use iter_nodes! instead.
§Example
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA{
a: usize
}
#[derive(TypedNode, Debug)]
struct NodeB{
b: usize
}
node_enum!{
#[derive(Debug)]
enum Node{
A(NodeA),
B(NodeB),
}
}
let ctx = Context::new();
let mut graph = Graph::<Node>::new(&ctx);
let mut trans = Transaction::new(&ctx);
trans.insert(Node::A(NodeA{ a: 1 }));
trans.insert(Node::A(NodeA{ a: 2 }));
trans.insert(Node::B(NodeB{ b: 0 }));
graph.commit(trans).unwrap();
// iterator.next() returns Option<(NodeIndex, &Node)>
let iterator = graph.iter();
for (i, (_, node)) in (1..3).zip(iterator) {
if let Node::A(a) = node {
assert_eq!(i, a.a);
} else {
panic!();
}
}Sourcepub fn iter_type<'a>(
&'a self,
d: NodeT::Discriminant,
) -> NodeIterator<'a, NodeT, Iter<'a, usize, NodeT>> ⓘ
pub fn iter_type<'a>( &'a self, d: NodeT::Discriminant, ) -> NodeIterator<'a, NodeT, Iter<'a, usize, NodeT>> ⓘ
Iterate a certain type of nodes denote by the discriminant.
Time complexity is only related to the number of nodes of that kind. It is backed by ordermap::OrderMap so it should be fast.
§Example
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA{
a: usize
}
#[derive(TypedNode, Debug)]
struct NodeB{
b: usize
}
node_enum!{
#[derive(Debug)]
enum Node{
A(NodeA),
B(NodeB),
}
}
let ctx = Context::new();
let mut graph = Graph::<Node>::new(&ctx);
let mut trans = Transaction::new(&ctx);
trans.insert(Node::A(NodeA{ a: 1 }));
trans.insert(Node::A(NodeA{ a: 2 }));
trans.insert(Node::B(NodeB{ b: 0 }));
graph.commit(trans).unwrap();
for (_, node) in graph.iter_type(discriminant!(Node::A)){
if let Node::A(a) = node {
// Ok
} else {
panic!();
}
}Sourcepub fn iter_group(
&self,
name: &'static str,
) -> impl Iterator<Item = (NodeIndex, &NodeT)>
pub fn iter_group( &self, name: &'static str, ) -> impl Iterator<Item = (NodeIndex, &NodeT)>
Iterate all nodes within the named group
§Example
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA {
a: usize,
}
#[derive(TypedNode, Debug)]
struct NodeB {
b: usize,
}
#[derive(TypedNode, Debug)]
struct NodeC {
c: usize,
}
#[derive(TypedNode, Debug)]
struct NodeD {
d: usize,
}
node_enum! {
#[derive(Debug)]
enum MultiNodes{
A(NodeA),
B(NodeB),
C(NodeC),
D(NodeD),
}
group!{
first{A, B},
second{C, D},
third{A, D},
one{B},
all{A, B, C, D},
}
}
let ctx = Context::new();
let mut graph = Graph::<MultiNodes>::new(&ctx);
let mut trans = Transaction::new(&ctx);
let a = trans.insert(MultiNodes::A(NodeA { a: 1 }));
let b = trans.insert(MultiNodes::B(NodeB { b: 2 }));
let c = trans.insert(MultiNodes::C(NodeC { c: 3 }));
let d = trans.insert(MultiNodes::D(NodeD { d: 4 }));
graph.commit(trans).unwrap();
assert_eq!(Vec::from_iter(graph.iter_group("first").map(|(x, _)| x)), vec![a, b]);
assert_eq!(Vec::from_iter(graph.iter_group("second").map(|(x, _)| x)), vec![c, d]);
assert_eq!(Vec::from_iter(graph.iter_group("third").map(|(x, _)| x)), vec![a, d]);
assert_eq!(Vec::from_iter(graph.iter_group("one").map(|(x, _)| x)), vec![b]);
assert_eq!(Vec::from_iter(graph.iter_group("all").map(|(x, _)| x)), vec![a, b, c, d]);Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Get the number of nodes in a graph
§Example
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA{
data: usize,
}
node_enum!{
#[derive(Debug)]
enum Node{
A(NodeA)
}
}
let ctx = Context::new();
let mut graph = Graph::<Node>::new(&ctx);
assert_eq!(graph.len(), 0);
let mut trans = Transaction::new(&ctx);
trans.insert(Node::A(NodeA{data: 1}));
trans.insert(Node::A(NodeA{data: 1}));
trans.insert(Node::A(NodeA{data: 1}));
graph.commit(trans).unwrap();
assert_eq!(graph.len(), 3);Sourcepub fn commit(
&mut self,
t: Transaction<'_, NodeT, Arena>,
) -> Result<(), CommitError<NodeT>>
pub fn commit( &mut self, t: Transaction<'_, NodeT, Arena>, ) -> Result<(), CommitError<NodeT>>
Commit an Transaction to modify the graph
Operation order:
- Redirect nodes
- Insert new nodes
- Modify nodes
- Update nodes
- Redirect all nodes
- Remove nodes
- Add/Remove links due to bidirectional declaration
- Check link types
§Panics
Panics if:
- the transaction and the graph have different context
§Errors
- there are multiple choices to make a bidirectional link (i.e. a.x <-> {b.y, b.z}, found a.x, don’t know if b.y=x or b.z=x)
- type check failed
** Note that in current version, the contents in the graph is always changed after commit, even with an error occurs. In this case, the graph will be in an unstable state. **
§Example
use ttgraph::*;
#[derive(TypedNode, Debug)]
struct NodeA{
data: usize,
}
node_enum!{
#[derive(Debug)]
enum Node{
A(NodeA)
}
}
let ctx = Context::new();
let mut graph = Graph::<Node>::new(&ctx);
let mut trans = Transaction::new(&ctx);
trans.insert(Node::A(NodeA{data: 1}));
graph.commit(trans).unwrap();Sourcepub fn commit_checked(
&mut self,
t: Transaction<'_, NodeT, Arena>,
checks: &GraphCheck<NodeT>,
) -> Result<(), CommitError<NodeT>>
pub fn commit_checked( &mut self, t: Transaction<'_, NodeT, Arena>, checks: &GraphCheck<NodeT>, ) -> Result<(), CommitError<NodeT>>
Similar to commit(), but with additional checks on the changed nodes and links.
See GraphCheck for more information.
Sourcepub fn switch_context(
self,
new_ctx: &Context,
) -> Result<Self, CommitError<NodeT>>
pub fn switch_context( self, new_ctx: &Context, ) -> Result<Self, CommitError<NodeT>>
Switch the context and relabel the node ids.
§Usecase:
- Useful when there are a lot of removed
NodeIndex, and after context switching the indexes will be more concise. - Merge two graphs with different context. See
mergefor example.
§Warning:
- Please ensure there is no uncommitted transactions!
NodeIndexpointing to this graph is useless after context switching!
Sourcepub fn check_integrity(&self)
pub fn check_integrity(&self)
Check if all links are internal, just for debug