Skip to main content

accent_sass_compiler/
fs.rs

1use std::{
2    io::{self, Error, ErrorKind},
3    path::{Path, PathBuf},
4};
5
6/// A trait to allow replacing the file system lookup mechanisms.
7///
8/// As it stands, this is imperfect: it’s still using the types and some operations from
9/// `std::path`, which constrain it to the target platform’s norms. This could be ameliorated by
10/// the use of associated types for `Path` and `PathBuf`, and putting all remaining methods on this
11/// trait (`is_absolute`, `parent`, `join`, *&c.*); but that would infect too many other APIs to be
12/// desirable, so we live with it as it is—which is also acceptable, because the motivating example
13/// use case is mostly using this as an optimisation over the real platform underneath.
14pub trait Fs: std::fmt::Debug {
15    /// Returns `true` if the path exists on disk and is pointing at a directory.
16    fn is_dir(&self, path: &Path) -> bool;
17    /// Returns `true` if the path exists on disk and is pointing at a regular file.
18    fn is_file(&self, path: &Path) -> bool;
19    /// Read the entire contents of a file into a bytes vector.
20    fn read(&self, path: &Path) -> io::Result<Vec<u8>>;
21
22    /// Canonicalize a file path
23    fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
24        Ok(path.to_path_buf())
25    }
26}
27
28/// Use [`std::fs`] to read any files from disk.
29///
30/// This is the default file system implementation.
31#[derive(Debug)]
32pub struct StdFs;
33
34impl Fs for StdFs {
35    #[inline]
36    fn is_file(&self, path: &Path) -> bool {
37        path.is_file()
38    }
39
40    #[inline]
41    fn is_dir(&self, path: &Path) -> bool {
42        path.is_dir()
43    }
44
45    #[inline]
46    fn read(&self, path: &Path) -> io::Result<Vec<u8>> {
47        std::fs::read(path)
48    }
49
50    #[inline]
51    fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
52        std::fs::canonicalize(path)
53    }
54}
55
56/// A file system implementation that acts like it’s completely empty.
57///
58/// This may be useful for security as it denies all access to the file system (so `@import` is
59/// prevented from leaking anything); you’ll need to use [`from_string`][crate::from_string] for
60/// this to make any sense (since [`from_path`][crate::from_path] would fail to find a file).
61#[derive(Debug)]
62pub struct NullFs;
63
64impl Fs for NullFs {
65    #[inline]
66    fn is_file(&self, _path: &Path) -> bool {
67        false
68    }
69
70    #[inline]
71    fn is_dir(&self, _path: &Path) -> bool {
72        false
73    }
74
75    #[inline]
76    fn read(&self, _path: &Path) -> io::Result<Vec<u8>> {
77        Err(Error::new(
78            ErrorKind::NotFound,
79            "NullFs, there is no file system",
80        ))
81    }
82}