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
use std::io;
use std::path::{Path, PathBuf};
pub trait FileSystem {
/// Reads the entire contents of a file into a string.
///
/// # Errors
///
/// Returns an error if the file does not exist, cannot be read, or contains invalid UTF-8.
fn read_to_string(&self, path: &Path) -> io::Result<String>;
/// Writes a slice of bytes to a file, creating the file if it does not exist.
///
/// # Errors
///
/// Returns an error if the file cannot be written to or created.
fn write_all(&self, path: &Path, contents: &[u8]) -> io::Result<()>;
/// Creates a directory and all of its parent components if they are missing.
///
/// # Errors
///
/// Returns an error if the directory cannot be created.
fn create_dir_all(&self, path: &Path) -> io::Result<()>;
/// Removes a file from the filesystem.
///
/// # Errors
///
/// Returns an error if the file does not exist or cannot be removed.
fn remove_file(&self, path: &Path) -> io::Result<()>;
/// Removes a directory and all of its contents.
///
/// # Errors
///
/// Returns an error if the directory does not exist or cannot be removed.
fn remove_dir_all(&self, path: &Path) -> io::Result<()>;
/// Returns `true` if the path points to an existing entity.
fn exists(&self, path: &Path) -> bool;
/// Returns `true` if the path exists and is pointing at a directory.
fn is_dir(&self, path: &Path) -> bool;
/// Returns `true` if the path exists and is pointing at a regular file.
fn is_file(&self, path: &Path) -> bool;
/// Returns the canonical, absolute form of the path with all intermediate components normalized.
///
/// # Errors
///
/// Returns an error if the path does not exist or cannot be canonicalized.
fn canonicalize(&self, path: &Path) -> io::Result<PathBuf>;
/// Returns a vector of all entries in a directory.
///
/// # Errors
///
/// Returns an error if the directory does not exist or cannot be read.
fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
/// Writes data to a file atomically using a temp-file + rename strategy.
///
/// The default implementation delegates to [`crate::atomic::atomic_write_sync`].
/// Test doubles may override this to use a simpler (non-atomic) write.
///
/// # Errors
///
/// Returns an error if the write or rename fails.
fn atomic_write(&self, path: &Path, contents: &[u8]) -> io::Result<()> {
crate::atomic::atomic_write_sync(path, contents)
}
}
pub struct OsFileSystem;
impl FileSystem for OsFileSystem {
fn read_to_string(&self, path: &Path) -> io::Result<String> {
std::fs::read_to_string(path)
}
fn write_all(&self, path: &Path, contents: &[u8]) -> io::Result<()> {
std::fs::write(path, contents)
}
fn create_dir_all(&self, path: &Path) -> io::Result<()> {
std::fs::create_dir_all(path)
}
fn remove_file(&self, path: &Path) -> io::Result<()> {
std::fs::remove_file(path)
}
fn remove_dir_all(&self, path: &Path) -> io::Result<()> {
std::fs::remove_dir_all(path)
}
fn exists(&self, path: &Path) -> bool {
path.exists()
}
fn is_dir(&self, path: &Path) -> bool {
path.is_dir()
}
fn is_file(&self, path: &Path) -> bool {
path.is_file()
}
fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
path.canonicalize()
}
fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
Ok(std::fs::read_dir(path)?
.filter_map(std::result::Result::ok)
.map(|entry| entry.path())
.collect())
}
}