coded myself into yet another corner...
This commit is contained in:
		
							parent
							
								
									3f60887645
								
							
						
					
					
						commit
						70a96b79a2
					
				
					 1 changed files with 93 additions and 155 deletions
				
			
		| 
						 | 
					@ -1,198 +1,136 @@
 | 
				
			||||||
#![allow(unused)]
 | 
					 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    cell::RefCell,
 | 
					    cell::RefCell,
 | 
				
			||||||
    fmt::{Debug, Display},
 | 
					    collections::{hash_map, HashMap},
 | 
				
			||||||
    iter,
 | 
					 | 
				
			||||||
    ops::Deref,
 | 
					    ops::Deref,
 | 
				
			||||||
    rc::{Rc, Weak},
 | 
					    rc::{Rc, Weak},
 | 
				
			||||||
    slice::Iter,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//these cant be just a type, as methods need to be impl'd on them.
 | 
					pub type WeakDirRef = Weak<RefCell<Dir>>;
 | 
				
			||||||
pub struct FileRef(Rc<RefCell<File>>);
 | 
					
 | 
				
			||||||
 | 
					pub trait FileLike {
 | 
				
			||||||
 | 
					    fn get_parent(&self) -> Option<DirRef>;
 | 
				
			||||||
 | 
					    fn get_name(&self) -> String;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct DirRef(Rc<RefCell<Dir>>);
 | 
					pub struct DirRef(Rc<RefCell<Dir>>);
 | 
				
			||||||
pub struct WeakDirRef(Weak<RefCell<Dir>>);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub enum Node {
 | 
					impl Deref for DirRef {
 | 
				
			||||||
    Dir(DirRef),
 | 
					    type Target = Rc<RefCell<Dir>>;
 | 
				
			||||||
    File(FileRef),
 | 
					
 | 
				
			||||||
 | 
					    fn deref(&self) -> &Self::Target {
 | 
				
			||||||
 | 
					        &self.0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct File {
 | 
					 | 
				
			||||||
    parent: WeakDirRef,
 | 
					 | 
				
			||||||
    pub name: String,
 | 
					 | 
				
			||||||
    pub size: usize,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Default)]
 | 
					 | 
				
			||||||
pub struct Dir {
 | 
					 | 
				
			||||||
    parent: Option<WeakDirRef>,
 | 
					 | 
				
			||||||
    pub name: String,
 | 
					 | 
				
			||||||
    children: Vec<Node>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DirRef {
 | 
					impl DirRef {
 | 
				
			||||||
    //impling it on the ref makes the recursion a bit easier.
 | 
					    pub fn add_child_node(&mut self, mut node: Node) -> NodeRef {
 | 
				
			||||||
    fn total_size(&self) -> usize {
 | 
					        node.change_parent(self);
 | 
				
			||||||
        self.0
 | 
					        let node_ref = NodeRef(Rc::new(RefCell::new(node)));
 | 
				
			||||||
            .borrow()
 | 
					        Rc::clone(self)
 | 
				
			||||||
            .deref()
 | 
					            .borrow_mut()
 | 
				
			||||||
            .children
 | 
					            .children
 | 
				
			||||||
 | 
					            .push(NodeRef(Rc::clone(&node_ref)));
 | 
				
			||||||
 | 
					        node_ref
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn add_child_dir(&mut self, mut dir: Dir) -> DirRef {
 | 
				
			||||||
 | 
					        dir.parent = Some(Rc::downgrade(self));
 | 
				
			||||||
 | 
					        let dir_ref = DirRef(Rc::new(RefCell::new(dir)));
 | 
				
			||||||
 | 
					        Rc::clone(self).borrow_mut().children.push(
 | 
				
			||||||
 | 
					            Node::Dir(())
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        todo!()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct Dir {
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    parent: Option<WeakDirRef>,
 | 
				
			||||||
 | 
					    children: Vec<NodeRef>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Dir {
 | 
				
			||||||
 | 
					    pub fn get_total_size(&self) -> usize {
 | 
				
			||||||
 | 
					        self.children
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
            .map(|f| match f {
 | 
					            .map(|n| -> usize {
 | 
				
			||||||
                Node::Dir(dir) => dir.total_size(),
 | 
					                match Rc::clone(n).borrow().deref() {
 | 
				
			||||||
                Node::File(file) => file.0.borrow().size,
 | 
					                    Node::Dir(d) => d.get_total_size(),
 | 
				
			||||||
 | 
					                    Node::File(f) => f.size,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .sum()
 | 
					            .sum()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn new(name: String) -> Self {
 | 
					    pub fn get_children(&self) -> impl Iterator<Item = NodeRef> + '_ {
 | 
				
			||||||
        DirRef(Rc::new(RefCell::new(Dir {
 | 
					        self.children.iter().map(|n| NodeRef(Rc::clone(n)))
 | 
				
			||||||
            parent: None,
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            children: Vec::new(),
 | 
					 | 
				
			||||||
        })))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //needs to be impled on the ref because of the need to get a weak backreference to self.
 | 
					 | 
				
			||||||
    fn add(&self, node: Node) -> Node {
 | 
					 | 
				
			||||||
        let ret;
 | 
					 | 
				
			||||||
        match node {
 | 
					 | 
				
			||||||
            Node::Dir(ref dir) => {
 | 
					 | 
				
			||||||
                dir.0.borrow_mut().parent = Some(WeakDirRef(Rc::downgrade(&self.0)));
 | 
					 | 
				
			||||||
                ret = Node::Dir(DirRef(Rc::clone(&dir.0)));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Node::File(ref file) => {
 | 
					 | 
				
			||||||
                file.0.borrow_mut().parent = WeakDirRef(Rc::downgrade(&self.0));
 | 
					 | 
				
			||||||
                ret = Node::File(FileRef(Rc::clone(&file.0)));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.0.borrow_mut().children.push(node);
 | 
					 | 
				
			||||||
        ret
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //because a file always has a parent, it needs to be created off of a node.
 | 
					 | 
				
			||||||
    fn new_file(&self, name: String, size: usize) -> FileRef {
 | 
					 | 
				
			||||||
        let file = File {
 | 
					 | 
				
			||||||
            parent: WeakDirRef(Rc::downgrade(&self.0)),
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            size,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let file_ref = FileRef(Rc::new(RefCell::new(file)));
 | 
					 | 
				
			||||||
        //have to unpack and repack to make a copy.
 | 
					 | 
				
			||||||
        self.0
 | 
					 | 
				
			||||||
            .borrow_mut()
 | 
					 | 
				
			||||||
            .children
 | 
					 | 
				
			||||||
            .push(Node::File(FileRef(Rc::clone(&file_ref.0))));
 | 
					 | 
				
			||||||
        file_ref
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl File {
 | 
					impl FileLike for Dir {
 | 
				
			||||||
    fn get_parent(&self) -> &WeakDirRef {
 | 
					    fn get_parent(&self) -> Option<DirRef> {
 | 
				
			||||||
        &self.parent
 | 
					        Some(DirRef(self.parent.as_ref()?.upgrade()?))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn get_name(&self) -> String {
 | 
				
			||||||
 | 
					        self.name.clone()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Dir {
 | 
					#[derive(Debug)]
 | 
				
			||||||
    fn get_children(&self) -> &[Node] {
 | 
					pub struct NodeRef(Rc<RefCell<Node>>);
 | 
				
			||||||
        &self.children
 | 
					
 | 
				
			||||||
 | 
					impl Deref for NodeRef {
 | 
				
			||||||
 | 
					    type Target = Rc<RefCell<Node>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn deref(&self) -> &Self::Target {
 | 
				
			||||||
 | 
					        &self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_parent(&self) -> &Option<WeakDirRef> {
 | 
					#[derive(Debug)]
 | 
				
			||||||
        &self.parent
 | 
					pub enum Node {
 | 
				
			||||||
    }
 | 
					    Dir(Dir),
 | 
				
			||||||
 | 
					    File(File),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Node {
 | 
					impl Node {
 | 
				
			||||||
    fn get_dir(&self) -> Option<DirRef> {
 | 
					    fn change_parent(&mut self, new_parent: &DirRef) {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Node::Dir(dir) => Some(DirRef(Rc::clone(&dir.0))),
 | 
					            Node::Dir(d) => d.parent = Some(Rc::downgrade(new_parent)),
 | 
				
			||||||
            Node::File(_) => None,
 | 
					            Node::File(f) => f.parent = Rc::downgrade(new_parent),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//transparent
 | 
					impl FileLike for Node {
 | 
				
			||||||
impl Display for DirRef {
 | 
					    fn get_parent(&self) -> Option<DirRef> {
 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					 | 
				
			||||||
        // f.debug_tuple("DirRef").field(self.0.borrow().deref()).finish()
 | 
					 | 
				
			||||||
        let this = self.0.borrow();
 | 
					 | 
				
			||||||
        write!(f, "{}", this);
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//transparent
 | 
					 | 
				
			||||||
impl Display for FileRef {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					 | 
				
			||||||
        // f.debug_tuple("FileRef").field(self.0.borrow().deref()).finish()
 | 
					 | 
				
			||||||
        let this = self.0.borrow();
 | 
					 | 
				
			||||||
        write!(f, "{}", this);
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Display for File {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					 | 
				
			||||||
        // f.debug_struct("File")
 | 
					 | 
				
			||||||
        //     .field("name", &self.name)
 | 
					 | 
				
			||||||
        //     .field("size", &self.size)
 | 
					 | 
				
			||||||
        //     .finish()
 | 
					 | 
				
			||||||
        write!(f, "- {} (file, size = {})", self.name, self.size);
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Display for Node {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Node::Dir(dir) => write!(f, "{}", dir),
 | 
					            Node::Dir(d) => d.get_parent(),
 | 
				
			||||||
            Node::File(file) => write!(f, "{}", file),
 | 
					            Node::File(f) => f.get_parent(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn get_name(&self) -> String {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Node::Dir(d) => d.get_name(),
 | 
				
			||||||
 | 
					            Node::File(f) => f.get_name(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Display for Dir {
 | 
					#[derive(Debug)]
 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					pub struct File {
 | 
				
			||||||
        writeln!(f, "- {} (dir)", self.name);
 | 
					    name: String,
 | 
				
			||||||
        for node in &self.children {
 | 
					    parent: WeakDirRef,
 | 
				
			||||||
            //padding
 | 
					    pub size: usize,
 | 
				
			||||||
            for (index, line) in format!("{}", node).lines().enumerate() {
 | 
					 | 
				
			||||||
                writeln!(f, "  {line}")?;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					impl FileLike for File {
 | 
				
			||||||
mod tests {
 | 
					    fn get_parent(&self) -> Option<DirRef> {
 | 
				
			||||||
    use super::*;
 | 
					        Some(DirRef(self.parent.upgrade()?))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    #[test]
 | 
					    fn get_name(&self) -> String {
 | 
				
			||||||
    fn dir_tree_sizes() {
 | 
					        self.name.clone()
 | 
				
			||||||
        let root = DirRef::new("/".to_string());
 | 
					 | 
				
			||||||
        let a = root.add(Node::Dir(DirRef::new("a".to_string())));
 | 
					 | 
				
			||||||
        let e = a
 | 
					 | 
				
			||||||
            .get_dir()
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
            .add(Node::Dir(DirRef::new("e".to_string())));
 | 
					 | 
				
			||||||
        let i = e.get_dir().unwrap().new_file("i".to_string(), 584);
 | 
					 | 
				
			||||||
        let f = a.get_dir().unwrap().new_file("f".to_string(), 29116);
 | 
					 | 
				
			||||||
        let g = a.get_dir().unwrap().new_file("g".to_string(), 2557);
 | 
					 | 
				
			||||||
        let h = a.get_dir().unwrap().new_file("h.lst".to_string(), 62596);
 | 
					 | 
				
			||||||
        let b = root.new_file("b.txt".to_string(), 14848514);
 | 
					 | 
				
			||||||
        let c = root.new_file("c.txt".to_string(), 8504156);
 | 
					 | 
				
			||||||
        let d = root.add(Node::Dir(DirRef::new("a".to_string())));
 | 
					 | 
				
			||||||
        let j = d.get_dir().unwrap().new_file("j".to_string(), 4060174);
 | 
					 | 
				
			||||||
        let dlog = d.get_dir().unwrap().new_file("d.log".to_string(), 8033020);
 | 
					 | 
				
			||||||
        let dext = d.get_dir().unwrap().new_file("d.ext".to_string(), 5626152);
 | 
					 | 
				
			||||||
        let k = d.get_dir().unwrap().new_file("k".to_string(), 7214296);
 | 
					 | 
				
			||||||
        println!("{}", root);
 | 
					 | 
				
			||||||
        assert_eq!(e.get_dir().unwrap().total_size(), 584);
 | 
					 | 
				
			||||||
        assert_eq!(a.get_dir().unwrap().total_size(), 94853);
 | 
					 | 
				
			||||||
        assert_eq!(d.get_dir().unwrap().total_size(), 24933642);
 | 
					 | 
				
			||||||
        assert_eq!(root.total_size(), 48381165)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue