1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub struct NodeId(pub usize);
8
9impl NodeId {
10 pub const ROOT: NodeId = NodeId(0);
11
12 pub fn index(&self) -> usize {
13 self.0
14 }
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
19pub enum NodeKind {
20 Directory,
21 File,
22 Symlink,
23 Error,
24}
25
26impl NodeKind {
27 pub fn icon(&self) -> &'static str {
28 match self {
29 NodeKind::Directory => "📁",
30 NodeKind::File => "📄",
31 NodeKind::Symlink => "🔗",
32 NodeKind::Error => "⚠️",
33 }
34 }
35
36 pub fn is_directory(&self) -> bool {
37 matches!(self, NodeKind::Directory)
38 }
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct TreeNode {
44 pub id: NodeId,
45 pub name: String,
46 pub kind: NodeKind,
47 pub size: u64,
49 pub file_count: u64,
51 pub parent: Option<NodeId>,
53 pub children: Vec<NodeId>,
55 pub depth: u16,
57 #[serde(skip)]
59 pub is_expanded: bool,
60 #[serde(skip)]
62 pub path: PathBuf,
63}
64
65impl TreeNode {
66 pub fn new(
67 id: NodeId,
68 name: String,
69 kind: NodeKind,
70 path: PathBuf,
71 parent: Option<NodeId>,
72 depth: u16,
73 ) -> Self {
74 Self {
75 id,
76 name,
77 kind,
78 size: 0,
79 file_count: if kind == NodeKind::File { 1 } else { 0 },
80 parent,
81 children: Vec::new(),
82 depth,
83 is_expanded: depth == 0, path,
85 }
86 }
87
88 pub fn has_children(&self) -> bool {
89 !self.children.is_empty()
90 }
91
92 pub fn is_expandable(&self) -> bool {
93 self.kind.is_directory() && !self.children.is_empty()
94 }
95}