jannie

jannie (mirror)
Log | Files | Refs | README | LICENSE

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 }