common.rs (3474B)
1 use std::ops; 2 3 pub enum FileType { 4 File(usize), 5 Directory(Vec<usize>) 6 } 7 8 pub struct File { 9 pub kind: FileType, 10 name: String 11 } 12 13 impl File { 14 pub fn real_size(&self, fs: &FileSystem) -> usize { 15 match &self.kind { 16 FileType::File(s) => *s, 17 FileType::Directory(c) => 18 c.iter().map(|x: &usize| fs[*x].real_size(&fs)).sum() 19 } 20 } 21 } 22 23 pub struct FileSystem { 24 files: Vec<File> 25 } 26 27 impl FileSystem { 28 fn new() -> Self { 29 Self { 30 files: vec![File { 31 kind: FileType::Directory(Vec::<usize>::new()), 32 name: String::from("/") 33 }] 34 } 35 } 36 37 pub fn build_from_stdin() -> Self { 38 let mut fs = FileSystem::new(); 39 let mut path = Path::new(); 40 let mut line = String::new(); 41 while std::io::stdin().read_line(&mut line).unwrap() > 0 { 42 if &line[..5] == "$ cd " { 43 exec_cd(&line[5..], &mut path, &fs); 44 } else if &line[..3] == "dir" { 45 fs.add_dir(&line[4..line.len()-1], path.last()); 46 } else if line.as_bytes()[0] != '$' as u8 { 47 let i = line.find(' ').unwrap(); 48 let size = line[0..i].parse::<usize>().unwrap(); 49 fs.add_file(&line[i+1..line.len()-1], size, path.last()); 50 } 51 line.clear(); 52 } 53 fs 54 } 55 56 fn make_parent(&mut self, id: usize, parent: usize) { 57 let p = &mut self.files[parent]; 58 if let FileType::Directory(v) = &mut p.kind { 59 v.push(id); 60 } else { 61 panic!("Parent is not a directory"); 62 } 63 } 64 65 fn add_dir(&mut self, name: &str, parent: usize) { 66 let id = self.files.len(); 67 self.files.push( 68 File { 69 kind: FileType::Directory(Vec::<usize>::new()), 70 name: String::from(name) 71 } 72 ); 73 self.make_parent(id, parent); 74 } 75 76 fn add_file(&mut self, name: &str, size: usize, parent: usize) { 77 let id = self.files.len(); 78 self.files.push( 79 File { 80 kind: FileType::File(size), 81 name: String::from(name) 82 } 83 ); 84 self.make_parent(id, parent); 85 } 86 87 pub fn iter(&self) -> impl Iterator<Item = &File>{ 88 self.files.iter() 89 } 90 } 91 92 impl ops::Index<usize> for FileSystem { 93 type Output = File; 94 fn index(&self, i: usize) -> &File { 95 &self.files[i] 96 } 97 } 98 99 struct Path { 100 stack: Vec<usize> 101 } 102 103 impl Path { 104 fn new() -> Self { Self { stack: vec![0] } } // 0 is the id of "/" 105 fn last(&self) -> usize { *self.stack.last().unwrap() } 106 fn clear(&mut self) { self.stack.drain(1..); } 107 fn pop(&mut self) { self.stack.pop(); } 108 fn push(&mut self, dir_id: usize) { self.stack.push(dir_id); } 109 } 110 111 fn exec_cd(line: &str, path: &mut Path, fs: &FileSystem) { 112 if line.as_bytes()[0] == '/' as u8 { 113 path.clear(); 114 } else if &line[..2] == ".." { 115 path.pop(); 116 } else { 117 let current_dir = &fs[path.last()]; 118 if let FileType::Directory(children) = ¤t_dir.kind { 119 for c in children { 120 if fs[*c].name == &line[..line.len()-1] { 121 path.push(*c); 122 return; 123 } 124 } 125 } else { 126 panic!("Non-directory in path"); 127 } 128 panic!("Directory not found in current path"); 129 } 130 }