mecomp_tui/ui/widgets/tree/
item.rs1use std::collections::HashSet;
2
3use ratatui::text::Text;
4
5#[derive(Debug, Clone)]
24#[allow(clippy::module_name_repetitions)]
25pub struct CheckTreeItem<'text, Identifier> {
26 pub(super) identifier: Identifier,
27 pub(super) text: Text<'text>,
28 pub(super) children: Vec<Self>,
29}
30
31impl<'text, Identifier> CheckTreeItem<'text, Identifier>
32where
33 Identifier: Clone + PartialEq + Eq + core::hash::Hash,
34{
35 #[must_use]
37 pub fn new_leaf<T>(identifier: Identifier, text: T) -> Self
38 where
39 T: Into<Text<'text>>,
40 {
41 Self {
42 identifier,
43 text: text.into(),
44 children: Vec::new(),
45 }
46 }
47
48 pub fn new<T>(identifier: Identifier, text: T, children: Vec<Self>) -> std::io::Result<Self>
54 where
55 T: Into<Text<'text>>,
56 {
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 Ok(Self {
69 identifier,
70 text: text.into(),
71 children,
72 })
73 }
74
75 #[must_use]
77 pub const fn identifier(&self) -> &Identifier {
78 &self.identifier
79 }
80
81 #[must_use]
82 pub fn children(&self) -> &[Self] {
83 &self.children
84 }
85
86 #[must_use]
88 pub fn child(&self, index: usize) -> Option<&Self> {
89 self.children.get(index)
90 }
91
92 #[must_use]
96 pub fn child_mut(&mut self, index: usize) -> Option<&mut Self> {
97 self.children.get_mut(index)
98 }
99
100 #[must_use]
101 pub fn height(&self) -> usize {
102 self.text.height()
103 }
104
105 pub fn add_child(&mut self, child: Self) -> std::io::Result<()> {
111 let existing = self
112 .children
113 .iter()
114 .map(|item| &item.identifier)
115 .collect::<HashSet<_>>();
116 if existing.contains(&child.identifier) {
117 return Err(std::io::Error::new(
118 std::io::ErrorKind::AlreadyExists,
119 "identifier already exists in the children",
120 ));
121 }
122
123 self.children.push(child);
124 Ok(())
125 }
126}
127
128#[cfg(test)]
129impl CheckTreeItem<'static, &'static str> {
130 #[must_use]
131 pub(crate) fn example() -> Vec<Self> {
132 vec![
133 Self::new_leaf("a", "Alfa"),
134 Self::new(
135 "b",
136 "Bravo",
137 vec![
138 Self::new_leaf("c", "Charlie"),
139 Self::new(
140 "d",
141 "Delta",
142 vec![Self::new_leaf("e", "Echo"), Self::new_leaf("f", "Foxtrot")],
143 )
144 .expect("all item identifiers are unique"),
145 Self::new_leaf("g", "Golf"),
146 ],
147 )
148 .expect("all item identifiers are unique"),
149 Self::new_leaf("h", "Hotel"),
150 ]
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 #[should_panic = "duplicate identifiers"]
160 fn tree_item_new_errors_with_duplicate_identifiers() {
161 let item = CheckTreeItem::new_leaf("same", "text");
162 let another = item.clone();
163 CheckTreeItem::new("root", "Root", vec![item, another]).unwrap();
164 }
165
166 #[test]
167 #[should_panic = "identifier already exists"]
168 fn tree_item_add_child_errors_with_duplicate_identifiers() {
169 let item = CheckTreeItem::new_leaf("same", "text");
170 let another = item.clone();
171 let mut root = CheckTreeItem::new("root", "Root", vec![item]).unwrap();
172 root.add_child(another).unwrap();
173 }
174}