tui_tree_widget/
tree_item.rs1use std::collections::HashSet;
2
3use ratatui::text::Text;
4
5#[derive(Debug, Clone)]
37pub struct TreeItem<'text, Identifier> {
38 pub(super) identifier: Identifier,
39 pub(super) text: Text<'text>,
40 pub(super) children: Vec<Self>,
41}
42
43impl<'text, Identifier> TreeItem<'text, Identifier>
44where
45 Identifier: Clone + PartialEq + Eq + core::hash::Hash,
46{
47 #[must_use]
49 pub fn new_leaf<T>(identifier: Identifier, text: T) -> Self
50 where
51 T: Into<Text<'text>>,
52 {
53 Self {
54 identifier,
55 text: text.into(),
56 children: Vec::new(),
57 }
58 }
59
60 pub fn new<T>(identifier: Identifier, text: T, children: Vec<Self>) -> std::io::Result<Self>
66 where
67 T: Into<Text<'text>>,
68 {
69 let identifiers = children
70 .iter()
71 .map(|item| &item.identifier)
72 .collect::<HashSet<_>>();
73 if identifiers.len() != children.len() {
74 return Err(std::io::Error::new(
75 std::io::ErrorKind::AlreadyExists,
76 "The children contain duplicate identifiers",
77 ));
78 }
79
80 Ok(Self {
81 identifier,
82 text: text.into(),
83 children,
84 })
85 }
86
87 #[must_use]
89 pub const fn identifier(&self) -> &Identifier {
90 &self.identifier
91 }
92
93 #[allow(clippy::missing_const_for_fn)] #[must_use]
95 pub fn children(&self) -> &[Self] {
96 &self.children
97 }
98
99 #[must_use]
101 pub fn child(&self, index: usize) -> Option<&Self> {
102 self.children.get(index)
103 }
104
105 #[must_use]
109 pub fn child_mut(&mut self, index: usize) -> Option<&mut Self> {
110 self.children.get_mut(index)
111 }
112
113 #[must_use]
114 pub fn height(&self) -> usize {
115 self.text.height()
116 }
117
118 pub fn add_child(&mut self, child: Self) -> std::io::Result<()> {
124 let existing = self
125 .children
126 .iter()
127 .map(|item| &item.identifier)
128 .collect::<HashSet<_>>();
129 if existing.contains(&child.identifier) {
130 return Err(std::io::Error::new(
131 std::io::ErrorKind::AlreadyExists,
132 "identifier already exists in the children",
133 ));
134 }
135
136 self.children.push(child);
137 Ok(())
138 }
139}
140
141impl TreeItem<'static, &'static str> {
142 #[cfg(test)]
143 #[must_use]
144 pub(crate) fn example() -> Vec<Self> {
145 vec![
146 Self::new_leaf("a", "Alfa"),
147 Self::new(
148 "b",
149 "Bravo",
150 vec![
151 Self::new_leaf("c", "Charlie"),
152 Self::new(
153 "d",
154 "Delta",
155 vec![Self::new_leaf("e", "Echo"), Self::new_leaf("f", "Foxtrot")],
156 )
157 .expect("all item identifiers are unique"),
158 Self::new_leaf("g", "Golf"),
159 ],
160 )
161 .expect("all item identifiers are unique"),
162 Self::new_leaf("h", "Hotel"),
163 ]
164 }
165}
166
167#[test]
168#[should_panic = "duplicate identifiers"]
169fn tree_item_new_errors_with_duplicate_identifiers() {
170 let item = TreeItem::new_leaf("same", "text");
171 let another = item.clone();
172 TreeItem::new("root", "Root", vec![item, another]).unwrap();
173}
174
175#[test]
176#[should_panic = "identifier already exists"]
177fn tree_item_add_child_errors_with_duplicate_identifiers() {
178 let item = TreeItem::new_leaf("same", "text");
179 let another = item.clone();
180 let mut root = TreeItem::new("root", "Root", vec![item]).unwrap();
181 root.add_child(another).unwrap();
182}