capability-skeleton 0.1.0

A Rust library for managing and building complex hierarchical tree structures such as skill trees. Supports serialization, error handling, and deep tree metrics.
Documentation
// ---------------- [ File: capability-skeleton/src/tree_level_specific_measurer.rs ]
crate::ix!();

impl TreeLevelSpecificMeasurer for Skeleton {
    fn measure_tree_level_stats(&self) -> HashMap<u8, TreeLevelAggregate> {
        let level_map = build_node_level_map(self);

        #[derive(Default)]
        struct TempLevelStats {
            node_count: u64,
            child_count: u64,
            leaf_count: u64,
        }
        let mut accum = HashMap::<u8, TempLevelStats>::new();

        for node in self.nodes() {
            if let Some(&lvl) = level_map.get(&node.id()) {
                let entry = accum.entry(lvl).or_insert_with(TempLevelStats::default);
                entry.node_count += 1;
                entry.child_count += node.child_ids().len() as u64;
                if node.child_ids().is_empty() {
                    entry.leaf_count += node.leaf_count() as u64;
                }
            }
        }

        let mut result = HashMap::new();
        for (lvl, tmp) in accum {
            let built = TreeLevelAggregateBuilder::default()
                .total_node_count(tmp.node_count)
                .total_child_count(tmp.child_count)
                .total_leaf_count(tmp.leaf_count)
                .build()
                .unwrap();
            result.insert(lvl, built);
        }
        result
    }
}

#[cfg(test)]
mod skeleton_level_specific_measurer_assessment {
    use super::*;

    #[traced_test]
    fn check_level_stats_with_branching() {
        // root->(childA, childB), childA->(childC), childB->leaf_count=2, childC=3
        let root = SkeletonNodeBuilder::default()
            .id(0_u16)
            .child_ids(vec![1,2])
            .name("root")
            .original_key("root")
            .build(NodeKind::Dispatch)
            .unwrap();
        let child_a = SkeletonNodeBuilder::default()
            .id(1_u16)
            .child_ids(vec![3])
            .name("childA")
            .original_key("childA")
            .build(NodeKind::Dispatch)
            .unwrap();
        let child_b = SkeletonNodeBuilder::default()
            .id(2_u16)
            .leaf_count(2_u16)
            .name("childB")
            .original_key("childB")
            .build(NodeKind::LeafHolder)
            .unwrap();
        let child_c = SkeletonNodeBuilder::default()
            .id(3_u16)
            .leaf_count(3_u16)
            .name("childC")
            .original_key("childC")
            .build(NodeKind::LeafHolder)
            .unwrap();

        let skel = SkeletonBuilder::default()
            .nodes(vec![root, child_a, child_b, child_c])
            .root_id(Some(0))
            .build()
            .unwrap();

        let level_stats = skel.measure_tree_level_stats();

        // level0 => node_count=1, child_count=2, leaf_count=0
        // level1 => node_count=2 => (childA has 1 child, childB=leaf), leaf_count=2
        // level2 => node_count=1 => childC => leaf_count=3

        let agg0 = level_stats.get(&0).unwrap();
        assert_eq!(*agg0.total_node_count(), 1);
        assert_eq!(*agg0.total_child_count(), 2);
        assert_eq!(*agg0.total_leaf_count(), 0);

        let agg1 = level_stats.get(&1).unwrap();
        assert_eq!(*agg1.total_node_count(), 2);
        assert_eq!(*agg1.total_child_count(), 1);  // childA->(3), childB->(none)
        assert_eq!(*agg1.total_leaf_count(), 2);

        let agg2 = level_stats.get(&2).unwrap();
        assert_eq!(*agg2.total_node_count(), 1);
        assert_eq!(*agg2.total_child_count(), 0);
        assert_eq!(*agg2.total_leaf_count(), 3);
    }

    #[traced_test]
    fn check_level_stats_in_linear_chain() {
        // 0->1->2 => BFS => level0=>0, level1=>1, level2=>2
        // node(2) => leaf_count=4
        let n0 = SkeletonNodeBuilder::default()
            .id(0u16)
            .child_ids(vec![1u16])
            .name("root")
            .original_key("root")
            .build(NodeKind::Dispatch)
            .unwrap();
        let n1 = SkeletonNodeBuilder::default()
            .id(1u16)
            .child_ids(vec![2u16])
            .name("child")
            .original_key("child")
            .build(NodeKind::Dispatch)
            .unwrap();
        let n2 = SkeletonNodeBuilder::default()
            .id(2u16)
            .leaf_count(4u16)
            .name("grandchild")
            .original_key("grandchild")
            .build(NodeKind::LeafHolder)
            .unwrap();

        let skel = SkeletonBuilder::default()
            .nodes(vec![n0, n1, n2])
            .root_id(Some(0u16))
            .build()
            .unwrap();

        let level_stats = skel.measure_tree_level_stats();

        // level0 => node_count=1, child_count=1, leaf_count=0
        // level1 => node_count=1, child_count=1, leaf_count=0
        // level2 => node_count=1, child_count=0, leaf_count=4
        let agg0 = level_stats.get(&0).unwrap();
        assert_eq!(*agg0.total_node_count(), 1);
        assert_eq!(*agg0.total_child_count(), 1);
        assert_eq!(*agg0.total_leaf_count(), 0);

        let agg1 = level_stats.get(&1).unwrap();
        assert_eq!(*agg1.total_node_count(), 1);
        assert_eq!(*agg1.total_child_count(), 1);
        assert_eq!(*agg1.total_leaf_count(), 0);

        let agg2 = level_stats.get(&2).unwrap();
        assert_eq!(*agg2.total_node_count(), 1);
        assert_eq!(*agg2.total_child_count(), 0);
        assert_eq!(*agg2.total_leaf_count(), 4);
    }
}