Skip to main content

arui_core/tree/
node.rs

1//! # 项目树节点
2//! 维护节点层级的特性,包含数据获取等等各类节点级操作。
3//! 注意!项目树节点一般由 tree 代理,而不应该由用户手动控制,某些情况下可以对节点进行数据获取操作,但应该仅限于此。
4pub mod count;
5pub mod file;
6use crate::{tree::summary::NodeSummary, utils::check_path};
7use std::fmt::Display;
8
9/// 目录树节点
10/// - 节点为文件时,无子树
11/// - 节点为目录时,有子树
12#[derive(Debug, Clone)]
13pub struct TreeNode {
14    /// 当前节点所处路径
15    pub path: String,
16    /// 是否是目录
17    /// TODO:后续应该改为自动检测
18    pub is_dir: bool,
19    /// 如果是目录,那么遍历他的子节点;如果为文件,则为空
20    pub children: Option<Vec<TreeNode>>,
21    /// 节点总结信息
22    /// - 文件:当前文件的总结信息
23    /// - 目录:当前目录下所有文件的总结信息的加合
24    pub summary: NodeSummary,
25}
26
27/// 为节点实现 Display
28impl Display for TreeNode {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        write!(
31            f,
32            "\n----- TreeNode -----\n\n- path: {}\n- is_dir: {}\n- children: {}\n- summary: {}\n\n--------------------",
33            self.path,
34            self.is_dir,
35            self.children.as_ref().unwrap_or(&Vec::new()).len(),
36            self.summary
37        )
38    }
39}
40
41/// 节点配置相关
42impl TreeNode {
43    /// 创建一个项目树节点
44    ///
45    /// # Examples
46    ///
47    /// ```rust
48    /// use arui_core::tree::node::TreeNode;
49    /// let node = TreeNode::new("./src", true);
50    /// ```
51    pub fn new<P>(path: P, is_dir: bool) -> Self
52    where
53        P: Into<String>,
54    {
55        TreeNode {
56            is_dir,
57            path: path.into(),
58            children: if is_dir { Some(Vec::new()) } else { None },
59            summary: NodeSummary::new(),
60        }
61    }
62
63    /// 检测节点路径是否合法
64    ///
65    /// # Examples
66    ///
67    /// ```rust
68    /// use arui_core::tree::node::TreeNode;
69    ///
70    /// let valid = TreeNode::new("./src", true).is_valid();
71    /// assert_eq!(valid, true);
72    ///
73    /// let in_valid = TreeNode::new("/not_exist", true).is_valid();
74    /// assert_eq!(in_valid, false);
75    /// ```
76    pub fn is_valid(&self) -> bool {
77        check_path(&self.path).is_ok()
78    }
79}
80
81/// 为节点实现总结信息相关操作
82impl TreeNode {
83    /// 初次调用为获取节点总结信息
84    /// 重复调用为更新节点总结信息,覆盖式更新当前节点的总结信息
85    ///
86    /// # Examples
87    ///
88    /// ```rust
89    /// use arui_core::tree::node::TreeNode;
90    ///
91    /// // 初始化目录节点,无子节点
92    /// let mut folder_node = TreeNode::new("./src", true);
93    /// // 初始获取总结信息
94    /// folder_node.upsert_summary();
95    /// assert_eq!(folder_node.summary.size, 0);
96    /// assert_eq!(folder_node.summary.count, 0);
97    ///
98    /// // 加入子节点
99    /// let sub_node = TreeNode::new("./src/lib.rs", false);
100    /// folder_node.children = Some(vec![sub_node]);
101    /// // 重复调用,覆盖式更新节点总结信息
102    /// folder_node.upsert_summary();
103    /// assert_eq!(folder_node.summary.size > 0, true);
104    /// assert_eq!(folder_node.summary.count > 0, true);
105    ///
106    /// // 初始化文件节点
107    /// let mut file_node = TreeNode::new("./src/lib.rs", false);
108    /// file_node.upsert_summary();
109    /// assert_eq!(file_node.summary.size > 0, true);
110    /// assert_eq!(file_node.summary.count > 0, true);
111    /// ```
112    pub fn upsert_summary(&mut self) {
113        let summary = NodeSummary::update(self);
114        self.summary = summary;
115    }
116}
117
118// --------------------- 单元测试 ---------------------
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_display() {
126        let node = TreeNode::new("./tests/examples/tree/summary".to_string(), true);
127        println!("{}", node);
128    }
129
130    #[test]
131    /// 测试节点创建
132    fn test_new() {
133        let node = TreeNode::new("./tests/examples/tree/summary".to_string(), true);
134        assert_eq!(node.path, "./tests/examples/tree/summary");
135        assert_eq!(node.is_dir, true);
136        assert!(node.children.is_some());
137        // 检查总结信息
138        assert_eq!(node.summary.size, 0);
139        assert_eq!(node.summary.count, 0);
140    }
141
142    #[test]
143    /// 在测试中调用
144    fn test_summary_update() {
145        let mut node = TreeNode::new("./tests/examples/tree/summary", true);
146        node.upsert_summary();
147        println!("{}", node);
148    }
149}