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