Skip to main content

ito_common/
fs.rs

1//! File-system abstractions.
2//!
3//! This crate uses a narrow `FileSystem` trait to allow unit tests to inject
4//! fake implementations without touching the real disk.
5
6use std::io;
7use std::path::{Path, PathBuf};
8
9/// A minimal file-system interface.
10///
11/// Prefer accepting a `&dyn FileSystem` in code that performs I/O so it can be
12/// tested without relying on `std::fs`.
13pub trait FileSystem: Send + Sync {
14    /// Read the entire file at `path` into a UTF-8 string.
15    fn read_to_string(&self, path: &Path) -> io::Result<String>;
16
17    /// Write `contents` to `path`, creating or truncating the file.
18    fn write(&self, path: &Path, contents: &[u8]) -> io::Result<()>;
19
20    /// Return `true` if `path` exists.
21    fn exists(&self, path: &Path) -> bool;
22
23    /// Create all directories needed for `path`.
24    fn create_dir_all(&self, path: &Path) -> io::Result<()>;
25
26    /// Return the immediate children of `path`.
27    fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
28
29    /// Remove a file.
30    fn remove_file(&self, path: &Path) -> io::Result<()>;
31
32    /// Remove a directory and all of its contents.
33    fn remove_dir_all(&self, path: &Path) -> io::Result<()>;
34
35    /// Return `true` if `path` is a directory.
36    fn is_dir(&self, path: &Path) -> bool;
37
38    /// Return `true` if `path` is a file.
39    fn is_file(&self, path: &Path) -> bool;
40}
41
42#[derive(Debug, Clone, Copy, Default)]
43/// A `FileSystem` backed by the standard library's `std::fs`.
44pub struct StdFs;
45
46impl FileSystem for StdFs {
47    fn read_to_string(&self, path: &Path) -> io::Result<String> {
48        std::fs::read_to_string(path)
49    }
50
51    fn write(&self, path: &Path, contents: &[u8]) -> io::Result<()> {
52        std::fs::write(path, contents)
53    }
54
55    fn exists(&self, path: &Path) -> bool {
56        path.exists()
57    }
58
59    fn create_dir_all(&self, path: &Path) -> io::Result<()> {
60        std::fs::create_dir_all(path)
61    }
62
63    fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
64        let entries = std::fs::read_dir(path)?;
65        let mut out = Vec::new();
66        for entry in entries {
67            let entry = entry?;
68            out.push(entry.path());
69        }
70        Ok(out)
71    }
72
73    fn remove_file(&self, path: &Path) -> io::Result<()> {
74        std::fs::remove_file(path)
75    }
76
77    fn remove_dir_all(&self, path: &Path) -> io::Result<()> {
78        std::fs::remove_dir_all(path)
79    }
80
81    fn is_dir(&self, path: &Path) -> bool {
82        path.is_dir()
83    }
84
85    fn is_file(&self, path: &Path) -> bool {
86        path.is_file()
87    }
88}