managarr_tree_widget/
tree_item.rs1use ratatui::text::ToText;
2use std::collections::HashSet;
3use std::fmt::Display;
4use std::hash::{DefaultHasher, Hash, Hasher};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct TreeItem<T>
39where
40 T: ToText + Clone + Default + Display + Hash + PartialEq + Eq,
41{
42 pub(super) identifier: u64,
43 pub(super) content: T,
44 pub(super) children: Vec<Self>,
45}
46
47impl<T> TreeItem<T>
48where
49 T: ToText + Clone + Default + Display + Hash + PartialEq + Eq,
50{
51 pub fn new(content: T, children: Vec<Self>) -> std::io::Result<Self> {
57 let identifiers = children
58 .iter()
59 .map(|item| &item.identifier)
60 .collect::<HashSet<_>>();
61 if identifiers.len() != children.len() {
62 return Err(std::io::Error::new(
63 std::io::ErrorKind::AlreadyExists,
64 "The children contain duplicate identifiers",
65 ));
66 }
67
68 let mut hasher = DefaultHasher::new();
69 content.hash(&mut hasher);
70
71 Ok(Self {
72 identifier: hasher.finish(),
73 content,
74 children,
75 })
76 }
77
78 #[must_use]
80 pub fn new_leaf(content: T) -> Self {
81 let mut hasher = DefaultHasher::new();
82 content.hash(&mut hasher);
83
84 Self {
85 identifier: hasher.finish(),
86 content,
87 children: Vec::new(),
88 }
89 }
90
91 #[must_use]
93 pub const fn identifier(&self) -> u64 {
94 self.identifier
95 }
96
97 #[must_use]
99 pub const fn content(&self) -> &T {
100 &self.content
101 }
102
103 #[must_use]
104 pub fn children(&self) -> &[Self] {
105 &self.children
106 }
107
108 #[must_use]
110 pub fn child(&self, index: usize) -> Option<&Self> {
111 self.children.get(index)
112 }
113
114 #[must_use]
118 pub fn child_mut(&mut self, index: usize) -> Option<&mut Self> {
119 self.children.get_mut(index)
120 }
121
122 #[must_use]
123 pub fn height(&self) -> usize {
124 self.content.clone().to_text().height()
125 }
126
127 pub fn add_child(&mut self, child: Self) -> std::io::Result<()> {
133 let existing = self
134 .children
135 .iter()
136 .map(|item| &item.identifier)
137 .collect::<HashSet<_>>();
138 if existing.contains(&child.identifier) {
139 return Err(std::io::Error::new(
140 std::io::ErrorKind::AlreadyExists,
141 "identifier already exists in the children",
142 ));
143 }
144
145 self.children.push(child);
146 Ok(())
147 }
148}
149
150impl TreeItem<&'static str> {
151 #[cfg(test)]
152 #[must_use]
153 pub(crate) fn example() -> Vec<Self> {
154 vec![
155 Self::new_leaf("Alfa"),
156 Self::new(
157 "Bravo",
158 vec![
159 Self::new_leaf("Charlie"),
160 Self::new(
161 "Delta",
162 vec![Self::new_leaf("Echo"), Self::new_leaf("Foxtrot")],
163 )
164 .expect("all item identifiers are unique"),
165 Self::new_leaf("Golf"),
166 ],
167 )
168 .expect("all item identifiers are unique"),
169 Self::new_leaf("Hotel"),
170 ]
171 }
172}
173
174#[test]
175#[should_panic = "duplicate identifiers"]
176fn tree_item_new_errors_with_duplicate_identifiers() {
177 let item = TreeItem::new_leaf("text");
178 let another = item.clone();
179 TreeItem::new("Root", vec![item, another]).unwrap();
180}
181
182#[test]
183#[should_panic = "identifier already exists"]
184fn tree_item_add_child_errors_with_duplicate_identifiers() {
185 let item = TreeItem::new_leaf("text");
186 let another = item.clone();
187 let mut root = TreeItem::new("Root", vec![item]).unwrap();
188 root.add_child(another).unwrap();
189}