forester_rs/runtime/rtree/
analyzer.rs

1use crate::runtime::rtree::rnode::RNodeId;
2use crate::runtime::rtree::RNode;
3use crate::runtime::rtree::RuntimeTree;
4use std::collections::HashMap;
5
6/// Runtime tree analyzer
7/// Provides methods to analyze the runtime tree
8/// and find nodes by some criteria
9pub struct RtTreeAnalyzer<'a> {
10    tree: &'a RuntimeTree,
11    parents: HashMap<RNodeId, RNodeId>,
12}
13
14impl<'a> RtTreeAnalyzer<'a> {
15    pub fn new(tree: &'a RuntimeTree) -> Self {
16        let mut parents = HashMap::new();
17        for (id, node) in tree.iter() {
18            for child in node.children() {
19                parents.insert(child, id);
20            }
21        }
22
23        Self { tree, parents }
24    }
25    /// Returns the parent of the node with the given id
26    pub fn parent(&self, id: &RNodeId) -> Option<&RNodeId> {
27        self.parents.get(id)
28    }
29
30    /// Returns the node_id by filter
31    pub fn find_id_by<F>(&self, filter: F) -> Option<RNodeId>
32        where
33            F: Fn(&RNode) -> bool,
34    {
35        self.tree
36            .iter()
37            .find_map(|(id, node)| if filter(node) { Some(id) } else { None })
38    }
39    /// Returns the node by filter
40    pub fn find_node_by<F>(&self, filter: F) -> Option<(RNodeId, &RNode)>
41        where
42            F: Fn(&RNode) -> bool,
43    {
44        self.tree
45            .iter()
46            .find(|(_id, node)| filter(node))
47    }
48    /// Returns the node by filter
49    pub fn find_map_by<F, T>(&self, filter_map: F) -> Option<(RNodeId, T)>
50        where
51            F: Fn(&RNode) -> Option<T>,
52    {
53        self.tree
54            .iter()
55            .find_map(|(id, node)| filter_map(node).map(|v| (id, v)))
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use crate::runtime::args::RtArgs;
62    use crate::runtime::rtree::builder::RtNodeBuilder;
63    use crate::runtime::rtree::builder::RtTreeBuilder;
64    use crate::runtime::rtree::rnode::FlowType;
65    use crate::runtime::rtree::rnode::RNodeName;
66    use crate::*;
67
68    #[test]
69    fn find_and_parent() {
70        let mut rtb = RtTreeBuilder::new();
71
72        let flow = flow!(fallback node_name!("root"), args!();
73            flow!(sequence node_name!("seq"), args!();
74                 action!(node_name!("action1"))
75            ),
76           action!(node_name!("action2"))
77        );
78
79        rtb.add_as_root(flow);
80        let tree = rtb.build().unwrap().0;
81
82        let analyzer = tree.analyze();
83        let a1 = analyzer.find_id_by(|n| n.is_name("action1")).unwrap();
84        let a2 = analyzer.find_id_by(|n| n.is_name("action2")).unwrap();
85        let root = analyzer.find_id_by(|n| n.is_name("root")).unwrap();
86        let seq = analyzer.find_id_by(|n| n.is_name("seq")).unwrap();
87
88        assert_eq!(analyzer.parent(&a1), Some(&seq));
89        assert_eq!(analyzer.parent(&a2), Some(&root));
90        assert_eq!(analyzer.parent(&root), None);
91    }
92}