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
use std;
use std::fmt;
use std::fs::File;
use std::io::Read;
#[derive(Debug)]
pub enum FileLoadError {
FileLoadFailure(String, std::io::Error),
Utf8Error(String, std::string::FromUtf8Error)
}
#[derive(Debug,Eq,PartialEq,Ord,PartialOrd,Hash,Copy,Clone)]
pub struct FileID {
value: usize
}
impl FileID {
pub fn new(value: usize) -> FileID { FileID { value: value } }
}
impl fmt::Display for FileID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FileID({})", self.value)
}
}
pub struct SourceFile {
id: FileID,
name: String,
contents: String
}
impl SourceFile {
pub fn id(&self) -> FileID {
self.id
}
pub fn name(&self) -> &str {
&self.name
}
pub fn contents(&self) -> &str {
&self.contents
}
}
pub struct SourceFiles {
working_dir: String,
files: Vec<SourceFile>
}
pub fn load_bytes(path: &str) -> Result<Vec<u8>, FileLoadError> {
let mut file = File::open(path).map_err(|err| FileLoadError::FileLoadFailure(path.to_string(), err))?;
let mut bytes = vec![];
file.read_to_end(&mut bytes).map_err(|err| FileLoadError::FileLoadFailure(path.to_string(), err))?;
Ok(bytes)
}
pub fn load_file(path: &str) -> Result<String, FileLoadError> {
let bytes = load_bytes(path)?;
let text = String::from_utf8(bytes).map_err(|err| FileLoadError::Utf8Error(path.to_string(), err))?;
Ok(text)
}
impl SourceFiles {
pub fn new(working_dir: String) -> SourceFiles {
SourceFiles {
working_dir: working_dir,
files: vec![]
}
}
pub fn for_id(&self, id: FileID) -> Option<&SourceFile> {
if id.value < self.files.len() {
Some(&self.files[id.value])
} else {
None
}
}
pub fn get_id(&self, filename: &str) -> Option<FileID> {
for (idx, file) in self.files.iter().enumerate() {
if &file.name == filename {
return Some(FileID { value: idx })
}
}
None
}
pub fn get(&self, filename: &str) -> Option<&str> {
match self.get_id(filename) {
Some(id) => Some(&self.files[id.value].contents),
None => None
}
}
pub fn path(&self, filename: &str) -> String {
if self.working_dir.is_empty() {
filename.to_owned()
} else {
format!("{}/{}", self.working_dir, filename)
}
}
pub fn load(&mut self, filename: &str) -> Result<&SourceFile,FileLoadError> {
let path = self.path(filename);
match self.get_id(&path) {
Some(id) => Ok(&self.files[id.value]),
None => {
let contents = load_file(&path)?;
let id_value = self.files.len();
let file = SourceFile {
id: FileID { value: id_value },
name: filename.to_owned(),
contents: contents
};
self.files.push(file);
Ok(&self.files[id_value])
}
}
}
}