ryo_source/generator/
tree.rs1use crate::pure::{PureAttribute, PureItem, PureUse, PureVis};
12
13#[derive(Debug, Clone, Default)]
33pub struct ModuleTree {
34 pub name: String,
36 pub vis: PureVis,
38 pub uses: Vec<PureUse>,
40 pub inner_attrs: Vec<PureAttribute>,
42 pub items: Vec<PureItem>,
44 pub children: Vec<ModuleTree>,
46}
47
48impl ModuleTree {
49 pub fn new(name: impl Into<String>) -> Self {
53 Self {
54 name: name.into(),
55 vis: PureVis::Private,
56 uses: Vec::new(),
57 inner_attrs: Vec::new(),
58 items: Vec::new(),
59 children: Vec::new(),
60 }
61 }
62
63 pub fn crate_root() -> Self {
65 Self::new("")
66 }
67
68 pub fn with_vis(mut self, vis: PureVis) -> Self {
70 self.vis = vis;
71 self
72 }
73
74 pub fn with_use(mut self, use_stmt: PureUse) -> Self {
76 self.uses.push(use_stmt);
77 self
78 }
79
80 pub fn with_uses(mut self, uses: impl IntoIterator<Item = PureUse>) -> Self {
82 self.uses.extend(uses);
83 self
84 }
85
86 pub fn with_inner_attr(mut self, attr: PureAttribute) -> Self {
88 self.inner_attrs.push(attr);
89 self
90 }
91
92 pub fn with_item(mut self, item: PureItem) -> Self {
94 self.items.push(item);
95 self
96 }
97
98 pub fn with_items(mut self, items: impl IntoIterator<Item = PureItem>) -> Self {
100 self.items.extend(items);
101 self
102 }
103
104 pub fn with_child(mut self, child: ModuleTree) -> Self {
106 self.children.push(child);
107 self
108 }
109
110 pub fn with_children(mut self, children: impl IntoIterator<Item = ModuleTree>) -> Self {
112 self.children.extend(children);
113 self
114 }
115
116 pub fn is_crate_root(&self) -> bool {
118 self.name.is_empty() || self.name == "crate"
119 }
120
121 pub fn total_items(&self) -> usize {
123 self.items.len() + self.children.iter().map(|c| c.total_items()).sum::<usize>()
124 }
125
126 pub fn total_modules(&self) -> usize {
128 1 + self
129 .children
130 .iter()
131 .map(|c| c.total_modules())
132 .sum::<usize>()
133 }
134
135 pub fn find_child(&self, name: &str) -> Option<&ModuleTree> {
137 self.children.iter().find(|c| c.name == name)
138 }
139
140 pub fn find_child_mut(&mut self, name: &str) -> Option<&mut ModuleTree> {
142 self.children.iter_mut().find(|c| c.name == name)
143 }
144
145 pub fn get_or_create_child(&mut self, name: &str) -> &mut ModuleTree {
150 if !self.children.iter().any(|c| c.name == name) {
151 self.children.push(ModuleTree::new(name));
152 }
153 self.find_child_mut(name)
154 .expect("child with matching name was pushed above when absent")
155 }
156
157 pub fn navigate(&self, path: &[&str]) -> Option<&ModuleTree> {
161 if path.is_empty() {
162 return Some(self);
163 }
164 self.find_child(path[0])?.navigate(&path[1..])
165 }
166
167 pub fn navigate_mut(&mut self, path: &[&str]) -> Option<&mut ModuleTree> {
169 if path.is_empty() {
170 return Some(self);
171 }
172 self.find_child_mut(path[0])?.navigate_mut(&path[1..])
173 }
174
175 pub fn get_or_create_path(&mut self, path: &[&str]) -> &mut ModuleTree {
179 if path.is_empty() {
180 return self;
181 }
182 let child = self.get_or_create_child(path[0]);
183 child.get_or_create_path(&path[1..])
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::pure::{PureBlock, PureFields, PureFn, PureGenerics, PureStruct, PureVis};
191
192 fn make_struct(name: &str) -> PureItem {
193 PureItem::Struct(PureStruct {
194 attrs: vec![],
195 vis: PureVis::Public,
196 name: name.to_string(),
197 generics: PureGenerics::default(),
198 fields: PureFields::Unit,
199 })
200 }
201
202 fn make_fn(name: &str) -> PureItem {
203 PureItem::Fn(PureFn {
204 attrs: vec![],
205 vis: PureVis::Public,
206 is_async: false,
207 is_async_inferred: false,
208 is_const: false,
209 is_unsafe: false,
210 abi: None,
211 name: name.to_string(),
212 generics: PureGenerics::default(),
213 params: vec![],
214 ret: None,
215 body: PureBlock::default(),
216 })
217 }
218
219 #[test]
220 fn test_module_tree_basic() {
221 let tree = ModuleTree::new("utils")
222 .with_vis(PureVis::Public)
223 .with_item(make_fn("helper"));
224
225 assert_eq!(tree.name, "utils");
226 assert_eq!(tree.vis, PureVis::Public);
227 assert_eq!(tree.items.len(), 1);
228 assert_eq!(tree.total_items(), 1);
229 assert_eq!(tree.total_modules(), 1);
230 }
231
232 #[test]
233 fn test_module_tree_nested() {
234 let tree = ModuleTree::crate_root()
235 .with_item(make_struct("Config"))
236 .with_child(
237 ModuleTree::new("models")
238 .with_item(make_struct("User"))
239 .with_child(ModuleTree::new("nested").with_item(make_struct("Deep"))),
240 );
241
242 assert!(tree.is_crate_root());
243 assert_eq!(tree.total_items(), 3);
244 assert_eq!(tree.total_modules(), 3);
245
246 let models = tree.find_child("models").unwrap();
247 assert_eq!(models.items.len(), 1);
248 assert_eq!(models.children.len(), 1);
249 }
250
251 #[test]
252 fn test_navigate() {
253 let tree = ModuleTree::crate_root().with_child(
254 ModuleTree::new("foo").with_child(ModuleTree::new("bar").with_item(make_struct("Baz"))),
255 );
256
257 let bar = tree.navigate(&["foo", "bar"]).unwrap();
258 assert_eq!(bar.name, "bar");
259 assert_eq!(bar.items.len(), 1);
260
261 assert!(tree.navigate(&["nonexistent"]).is_none());
262 }
263
264 #[test]
265 fn test_get_or_create_path() {
266 let mut tree = ModuleTree::crate_root();
267
268 let nested = tree.get_or_create_path(&["a", "b", "c"]);
269 nested.items.push(make_struct("Deep"));
270
271 assert!(tree.navigate(&["a", "b", "c"]).is_some());
272 assert_eq!(tree.total_modules(), 4); }
274}