ITS WORKING!!
This commit is contained in:
		
							parent
							
								
									824321c660
								
							
						
					
					
						commit
						35a5c043a0
					
				
					 1 changed files with 154 additions and 1 deletions
				
			
		| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    cell::RefCell,
 | 
					    cell::RefCell,
 | 
				
			||||||
 | 
					    fmt::Display,
 | 
				
			||||||
    ops::Deref,
 | 
					    ops::Deref,
 | 
				
			||||||
    rc::{Rc, Weak},
 | 
					    rc::{Rc, Weak},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -12,6 +13,10 @@ pub enum FileTreeError {
 | 
				
			||||||
    IsFile,
 | 
					    IsFile,
 | 
				
			||||||
    #[error("File operation on directory")]
 | 
					    #[error("File operation on directory")]
 | 
				
			||||||
    IsDir,
 | 
					    IsDir,
 | 
				
			||||||
 | 
					    #[error("File not found")]
 | 
				
			||||||
 | 
					    FileNotFound,
 | 
				
			||||||
 | 
					    #[error("File already exists")]
 | 
				
			||||||
 | 
					    FileAlreadyExists,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type WeakNodeRef = Weak<RefCell<Node>>;
 | 
					type WeakNodeRef = Weak<RefCell<Node>>;
 | 
				
			||||||
| 
						 | 
					@ -39,6 +44,19 @@ impl From<NodeRef> for Rc<RefCell<Node>> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for NodeRef{
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "{}", self.borrow())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl NodeRef {
 | 
				
			||||||
 | 
					    pub fn add_node(&mut self, mut node: Node) -> Result<NodeRef, FileTreeError> {
 | 
				
			||||||
 | 
					        node.set_parent(self);
 | 
				
			||||||
 | 
					        self.borrow_mut().add_children(node)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Node {
 | 
					pub struct Node {
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: String,
 | 
				
			||||||
| 
						 | 
					@ -47,11 +65,62 @@ pub struct Node {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Node {
 | 
					impl Node {
 | 
				
			||||||
 | 
					    pub fn new_dir(name: String) -> Node {
 | 
				
			||||||
 | 
					        Node {
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            parent: None,
 | 
				
			||||||
 | 
					            contents: Contents::Children(Vec::new()),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn new_file(name: String, size: usize) -> Node {
 | 
				
			||||||
 | 
					        Node {
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            parent: None,
 | 
				
			||||||
 | 
					            contents: Contents::Size(size),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn get_total_size(&self) -> usize {
 | 
				
			||||||
 | 
					        match &self.contents {
 | 
				
			||||||
 | 
					            Contents::Size(s) => *s,
 | 
				
			||||||
 | 
					            Contents::Children(c) => c.iter().map(|f| f.borrow().get_total_size()).sum(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fn set_parent(&mut self, newparent: &NodeRef) {
 | 
					    fn set_parent(&mut self, newparent: &NodeRef) {
 | 
				
			||||||
        self.parent = Some(Rc::downgrade(newparent));
 | 
					        self.parent = Some(Rc::downgrade(newparent));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // does not set the parent, needs to be done on the NodeRef. (this is why this func isnt pub).
 | 
				
			||||||
 | 
					    // takes onwership of the node to make sure its not owned by another tree.
 | 
				
			||||||
 | 
					    fn add_children(&mut self, node: Node) -> Result<NodeRef, FileTreeError> {
 | 
				
			||||||
 | 
					        match self.contents {
 | 
				
			||||||
 | 
					            Contents::Size(_) => Err(FileTreeError::IsFile),
 | 
				
			||||||
 | 
					            Contents::Children(ref mut c) => {
 | 
				
			||||||
 | 
					                for file in c.iter() {
 | 
				
			||||||
 | 
					                    if file.borrow().name == node.name {
 | 
				
			||||||
 | 
					                        return Err(FileTreeError::FileAlreadyExists);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                let rc = Rc::new(RefCell::new(node));
 | 
				
			||||||
 | 
					                c.push(NodeRef(Rc::clone(&rc)));
 | 
				
			||||||
 | 
					                Ok(NodeRef(Rc::clone(&rc)))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn remove_child_by_name(&mut self, name: &str) -> Result<(), FileTreeError> {
 | 
				
			||||||
 | 
					        match self.contents {
 | 
				
			||||||
 | 
					            Contents::Size(_) => Err(FileTreeError::IsFile),
 | 
				
			||||||
 | 
					            Contents::Children(ref mut c) => {
 | 
				
			||||||
 | 
					                for (i, file) in c.iter().enumerate() {
 | 
				
			||||||
 | 
					                    if file.borrow().name == name {
 | 
				
			||||||
 | 
					                        c.remove(i);
 | 
				
			||||||
 | 
					                        return Ok(());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Err(FileTreeError::FileNotFound)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn get_parent(&self) -> Option<NodeRef> {
 | 
					    pub fn get_parent(&self) -> Option<NodeRef> {
 | 
				
			||||||
        match &self.parent{
 | 
					        match &self.parent {
 | 
				
			||||||
            Some(w) => Some(NodeRef(w.clone().upgrade()?)),
 | 
					            Some(w) => Some(NodeRef(w.clone().upgrade()?)),
 | 
				
			||||||
            None => None,
 | 
					            None => None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -77,6 +146,25 @@ impl Node {
 | 
				
			||||||
            Contents::Children(c) => Ok(c.iter().map(|n| NodeRef(Rc::clone(n)))),
 | 
					            Contents::Children(c) => Ok(c.iter().map(|n| NodeRef(Rc::clone(n)))),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn get_child_by_name(&self, name: &str) -> Result<NodeRef, FileTreeError> {
 | 
				
			||||||
 | 
					        match &self.contents {
 | 
				
			||||||
 | 
					            Contents::Size(_) => Err(FileTreeError::IsFile),
 | 
				
			||||||
 | 
					            Contents::Children(c) => {
 | 
				
			||||||
 | 
					                for file in c.iter() {
 | 
				
			||||||
 | 
					                    if file.borrow().name == name {
 | 
				
			||||||
 | 
					                        return Ok(NodeRef(Rc::clone(file)));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Err(FileTreeError::FileNotFound)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for Node{
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "- {} {}", self.name, self.contents)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
| 
						 | 
					@ -84,3 +172,68 @@ pub enum Contents {
 | 
				
			||||||
    Size(usize),
 | 
					    Size(usize),
 | 
				
			||||||
    Children(Vec<NodeRef>),
 | 
					    Children(Vec<NodeRef>),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for Contents {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Contents::Size(s) => write!(f, "(file, size = {})", s),
 | 
				
			||||||
 | 
					            Contents::Children(c) => {
 | 
				
			||||||
 | 
					                writeln!(f, "(dir)").expect("I have no clue how this could fail");
 | 
				
			||||||
 | 
					                for node in c {
 | 
				
			||||||
 | 
					                    //padding
 | 
				
			||||||
 | 
					                    for line in format!("{}", node).lines() {
 | 
				
			||||||
 | 
					                        writeln!(f, " {line}")?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Ok(())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_dir_construction() {
 | 
				
			||||||
 | 
					        let mut root = NodeRef(Rc::new(RefCell::new(Node::new_dir("/".to_string()))));
 | 
				
			||||||
 | 
					        let mut cursor = root.add_node(Node::new_dir("a".to_string())).unwrap();
 | 
				
			||||||
 | 
					        cursor = cursor.add_node(Node::new_dir("e".to_string())).unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("i".to_string(), 584))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("f".to_string(), 29116))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("g".to_string(), 2557))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("h.lst".to_string(), 62596))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("b.txt".to_string(), 14848514))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("c.dat".to_string(), 8504156))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor = cursor.add_node(Node::new_dir("d".to_string())).unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("j".to_string(), 4060174))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("d.log".to_string(), 8033020))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("d.ext".to_string(), 5626152))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        cursor
 | 
				
			||||||
 | 
					            .add_node(Node::new_file("k".to_string(), 7214296))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        assert_eq!(Rc::clone(root.deref()).borrow().get_total_size(), 48381165);
 | 
				
			||||||
 | 
					        println!("{}", root);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue