use std::cell::RefCell; use std::error; use std::fs::File; use std::io::BufRead; use std::io::BufReader; use std::rc::{Rc, Weak}; enum FsEntry { Dir(Rc), File(FsFile) } struct FsDir { name: String, children: RefCell>, parent: Option> } impl FsDir { fn _compute_size(&self) -> u32 { let mut size: u32 = 0; let children = self.children.borrow_mut(); for child in children.iter() { match child { FsEntry::File(f) => size += f.size, FsEntry::Dir(d) => { size += d._compute_size(); }, }; } size } fn _show(&self, prefix: String) { println!("{}{}", &prefix, &self.name); let children = self.children.borrow_mut(); for child in children.iter() { match child { FsEntry::File(f) => println!("{}{}", &prefix, &f.size), FsEntry::Dir(d) => d._show(format!("{} ", &prefix)), }; } } fn get_dir_sizes(&self) -> Vec { let mut sizes = vec![]; let mut size: u32 = 0; let children = self.children.borrow_mut(); for child in children.iter() { match child { FsEntry::File(f) => size += f.size, FsEntry::Dir(d) => { let d_vec = d.get_dir_sizes(); size += d_vec[d_vec.len() - 1]; sizes.extend_from_slice(&d_vec); }, }; } sizes.push(size); sizes } } struct FsFile { size: u32 } fn main() -> Result<(), Box> { let f = File::open("input.txt")?; let reader = BufReader::new(f); let fs_tree: Rc = Rc::new(FsDir { children: RefCell::new(vec![]), parent: None, name: String::from("/") }); let mut current_dir = Rc::downgrade(&fs_tree); for line in reader.lines() { let line = line?; if &line[0..1] == "$" { // parse the command let mut cmd_iter = line[2..].split_whitespace(); match cmd_iter.next() { Some("cd") => { // println!("{}", &line); match cmd_iter.next() { Some("/") => current_dir = Rc::downgrade(&fs_tree), Some("..") => { let mut new_dir = None; let strong = current_dir.upgrade().unwrap(); match &strong.parent { Some(x) => { let strong_x = x.upgrade().unwrap(); let rc_c = Rc::clone(&strong_x); new_dir = Some(Rc::downgrade(&rc_c)); }, None => (), }; match new_dir { Some(d) => current_dir = d, None => panic!("Could not find parent dir in '{}'", current_dir.upgrade().unwrap().name), }; }, Some(x) => { let mut new_dir = None; let strong = current_dir.upgrade().unwrap(); let children = strong.children.borrow_mut(); for child in children.iter() { if let FsEntry::Dir(d) = child { if d.name == x { new_dir = Some(Rc::clone(&d)); break; } } } match new_dir { Some(d) => current_dir = Rc::downgrade(&d), None => panic!("Could not find dir '{x}' in '{}'", current_dir.upgrade().unwrap().name), } }, None => panic!("No argument to 'cd': {}", line), }; // println!("{}", current_dir.upgrade().unwrap().name); }, Some("ls") => { // we can ignore this, as we read everything not being a command into the // current directory anyways } Some(x) => panic!("Unsupported command: {}", x), None => panic!("Could not split into a command: {}", line), }; } else { // parse the list of fs entries let mut entry_iter = line.split_whitespace(); match entry_iter.next() { Some("dir") => { let new_dir = Rc::new(FsDir {name: String::from(entry_iter.next().unwrap()), children: RefCell::new(vec![]), parent: Some(current_dir.clone()) }); let strong = current_dir.upgrade().unwrap(); let mut children = strong.children.borrow_mut(); children.push(FsEntry::Dir(new_dir)); }, Some(size) => { let f = FsFile {size: size.parse().unwrap()}; let strong = current_dir.upgrade().unwrap(); let mut children = strong.children.borrow_mut(); children.push(FsEntry::File(f)); }, _ => panic!("Unknown fs entry: {line}"), }; } } drop(current_dir); // fs_tree.show(String::from("")); // compute sizes let sizes = fs_tree.get_dir_sizes(); println!("{}", sizes.iter().filter(|x| **x < 100000).sum::()); println!("Hello, world!"); Ok(()) }