mod.rs (6190B)
1 use std::{ 2 cell::{BorrowError, BorrowMutError, RefCell}, 3 collections::BTreeMap, 4 path::{Path, PathBuf}, 5 rc::Rc, 6 }; 7 8 use indexmap::IndexMap; 9 use uuid::Uuid; 10 11 use crate::filetree::node::Node; 12 13 pub mod node; 14 15 pub type NodeRef<M> = Rc<RefCell<Node<M>>>; 16 17 pub struct Filetree<M> { 18 nodes: IndexMap<Uuid, NodeRef<M>>, 19 paths: BTreeMap<PathBuf, Uuid>, 20 root: Uuid, 21 } 22 23 impl<M> Filetree<M> { 24 pub fn new(root: Node<M>) -> Self { 25 // todo: check root better 26 assert!(root.is_leaf()); 27 let mut filetree = Filetree { 28 nodes: IndexMap::new(), 29 paths: BTreeMap::new(), 30 root: root.id(), 31 }; 32 filetree.insert_node(root, None).unwrap(); 33 filetree 34 } 35 36 pub fn root(&self) -> NodeRef<M> { 37 Rc::clone( 38 self.nodes 39 .get(&self.root) 40 .expect("Filetree should have root"), 41 ) 42 } 43 44 pub fn nodes(&self) -> impl Iterator<Item = NodeRef<M>> { 45 self.nodes.values().map(Rc::clone) 46 } 47 48 pub fn node(&self, node_id: Uuid) -> Option<NodeRef<M>> { 49 self.nodes.get(&node_id).map(Rc::clone) 50 } 51 52 pub fn node_by_path(&self, path: &Path) -> Option<NodeRef<M>> { 53 self.paths 54 .get(path) 55 .map(|node_id| self.nodes.get(node_id).expect("Filetree should have node")) 56 .map(Rc::clone) 57 } 58 59 /// Checks if a node with this path exists 60 pub fn check_path(&self, path: &Path) -> bool { 61 self.paths.get(path).is_some() 62 } 63 } 64 65 impl<M> Filetree<M> { 66 pub fn insert(&mut self, node: Node<M>) -> Result<(), Error> { 67 let mut path = node.path().to_owned(); 68 tracing::debug!("Trying to add node with path {path:?}"); 69 if path.ends_with("..") { 70 return Err(Error::ParentDir); 71 } 72 if path.ends_with(".") { 73 return Err(Error::CurrentDir); 74 } 75 if self.paths.get(&path).is_some() { 76 return Err(Error::NodeExists); 77 } 78 path.pop(); 79 tracing::trace!("Searching for node with path {path:?}"); 80 if let Some(parent) = self.paths.get(&path).copied() { 81 self.insert_node(node, Some(parent))?; 82 Ok(()) 83 } else { 84 Err(Error::MissingPath) 85 } 86 } 87 88 fn insert_node(&mut self, mut node: Node<M>, parent: Option<Uuid>) -> Result<(), Error> { 89 let node_id = node.id(); 90 if let Some(parent) = parent { 91 self.nodes 92 .get(&parent) 93 .expect("Should have parent node") 94 .try_borrow_mut()? 95 .add_child(node_id); 96 node.set_parent(parent); 97 } else { 98 node.unset_parent(); 99 } 100 self.paths.insert(node.path().to_owned(), node_id); 101 self.nodes.insert(node_id, Rc::new(RefCell::new(node))); 102 Ok(()) 103 } 104 } 105 106 impl<M> Filetree<M> { 107 pub fn print(&self) -> Result<(), Error> { 108 let mut print_buffer = Vec::new(); 109 print_buffer.push((0, self.root)); 110 while let Some((offset, node_id)) = print_buffer.pop() { 111 let node = self 112 .nodes 113 .get(&node_id) 114 .expect("Shold have the node") 115 .try_borrow()?; 116 println!( 117 "{}| {}", 118 " ".repeat(offset), 119 node.path() 120 .file_name() 121 .map(|name| name.to_str()) 122 .flatten() 123 .unwrap_or("UNKNOWN") 124 ); 125 print_buffer.extend(node.children().map(|child_id| (offset + 1, child_id))); 126 } 127 Ok(()) 128 } 129 } 130 131 #[derive(thiserror::Error, Debug)] 132 pub enum Error { 133 #[error("Error borrowing mutably: {0}")] 134 BorrowMutError(#[from] BorrowMutError), 135 #[error("Error borrowing: {0}")] 136 BorrowError(#[from] BorrowError), 137 #[error("Node already exists in the tree")] 138 NodeExists, 139 #[error("Node extends the path too much, directory does not exist")] 140 MissingPath, 141 #[error("Use of current dir is disallowed")] 142 CurrentDir, 143 #[error("Use of parent dir is disallowed")] 144 ParentDir, 145 } 146 147 #[cfg(test)] 148 mod tests { 149 use super::*; 150 151 #[test_log::test(test)] 152 fn cannot_insert_root() { 153 let root = Node::new("/".into(), ()); 154 let mut tree = Filetree::new(root); 155 assert!(dbg!(tree.insert(Node::new("/".into(), ()))).is_err()); 156 } 157 158 #[test_log::test(test)] 159 fn cannot_insert_relative() { 160 let root = Node::new("/".into(), ()); 161 let mut tree = Filetree::new(root); 162 assert!(dbg!(tree.insert(Node::new("dir".into(), ()))).is_err()); 163 } 164 165 #[test_log::test(test)] 166 fn cannot_insert_dots() { 167 let root = Node::new("/".into(), ()); 168 let mut tree = Filetree::new(root); 169 assert!(dbg!(tree.insert(Node::new("/.".into(), ()))).is_err()); 170 assert!(dbg!(tree.insert(Node::new("/..".into(), ()))).is_err()); 171 } 172 173 #[test_log::test(test)] 174 fn insert_one() { 175 let root = Node::new("/".into(), ()); 176 let mut tree = Filetree::new(root); 177 assert!(dbg!(tree.insert(Node::new("/dir".into(), ()))).is_ok()); 178 } 179 180 #[test_log::test(test)] 181 fn insert_exists() { 182 let root = Node::new("/".into(), ()); 183 let mut tree = Filetree::new(root); 184 assert!(dbg!(tree.insert(Node::new("/dir".into(), ()))).is_ok()); 185 assert!(dbg!(tree.insert(Node::new("/dir".into(), ()))).is_err()); 186 } 187 188 #[test_log::test(test)] 189 fn insert_many() { 190 let root = Node::new("/".into(), ()); 191 let mut tree = Filetree::new(root); 192 assert!(dbg!(tree.insert(Node::new("/dir".into(), ()))).is_ok()); 193 assert!(dbg!(tree.insert(Node::new("/dir/dir/dir".into(), ()))).is_err()); 194 assert!(dbg!(tree.insert(Node::new("/dir/dir".into(), ()))).is_ok()); 195 assert!(dbg!(tree.insert(Node::new("/dir/dir".into(), ()))).is_err()); 196 assert!(dbg!(tree.insert(Node::new("/dir/dir/dir".into(), ()))).is_ok()); 197 assert!(dbg!(tree.insert(Node::new("/dir2".into(), ()))).is_ok()); 198 assert!(dbg!(tree.insert(Node::new("/dir3".into(), ()))).is_ok()); 199 } 200 }