parcel_resolver/
fs.rs

1use std::{
2  io::Result,
3  path::{Path, PathBuf},
4};
5
6use bitflags::bitflags;
7
8bitflags! {
9  /// Bitflags that describe path metadata.
10  pub struct FileKind: u8 {
11    /// If set, the path is a file.
12    const IS_FILE = 1 << 0;
13    /// If set, the path is a directory.
14    const IS_DIR = 1 << 1;
15    /// If set, the path is a symbolic link.
16    const IS_SYMLINK = 1 << 2;
17  }
18}
19
20/// A trait that provides the functions needed to read files and retrieve metadata from a file system.
21pub trait FileSystem: Send + Sync {
22  /// Reads the given path as a string.
23  fn read_to_string(&self, path: &Path) -> Result<String>;
24  /// Returns the kind of file or directory that the given path represents.
25  fn kind(&self, path: &Path) -> FileKind;
26  /// Returns the resolution of a symbolic link.
27  fn read_link(&self, path: &Path) -> Result<PathBuf>;
28}
29
30/// Default operating system file system implementation.
31#[cfg(not(target_arch = "wasm32"))]
32#[derive(Default)]
33pub struct OsFileSystem;
34
35#[cfg(not(target_arch = "wasm32"))]
36impl FileSystem for OsFileSystem {
37  fn read_to_string(&self, path: &Path) -> Result<String> {
38    std::fs::read_to_string(path)
39  }
40
41  fn kind(&self, path: &Path) -> FileKind {
42    let mut flags = FileKind::empty();
43
44    // A majority of paths are not symlinks. symlink_metadata will tell us whether a path is a symlink,
45    // and if not, also whether the path is a file or directory. If it was a symlink we'll need to make
46    // another call to get the metadata of the underlying path, but this is rare.
47    if let Ok(metadata) = path.symlink_metadata() {
48      if metadata.is_symlink() {
49        flags.set(FileKind::IS_SYMLINK, true);
50        if let Ok(metadata) = path.metadata() {
51          flags.set(FileKind::IS_FILE, metadata.is_file());
52          flags.set(FileKind::IS_DIR, metadata.is_dir());
53        }
54      } else {
55        flags.set(FileKind::IS_FILE, metadata.is_file());
56        flags.set(FileKind::IS_DIR, metadata.is_dir());
57      }
58    }
59
60    flags
61  }
62
63  fn read_link(&self, path: &Path) -> Result<PathBuf> {
64    path.read_link()
65  }
66}