rspack_binding_api 0.100.7

Rspack shared binding API
Documentation
use std::{
  fmt::Debug,
  sync::{Arc, RwLock},
};

use rspack_fs::{FileMetadata, FilePermissions, ReadableFileSystem, Result};
use rspack_paths::{Utf8Path, Utf8PathBuf};

use crate::virtual_modules::VirtualFileStore;

pub struct VirtualFileSystem {
  real_fs: Arc<dyn ReadableFileSystem>,
  virtual_file_store: Arc<RwLock<dyn VirtualFileStore>>,
}

impl VirtualFileSystem {
  pub fn new(
    real_fs: Arc<dyn ReadableFileSystem>,
    virtual_file_store: Arc<RwLock<dyn VirtualFileStore>>,
  ) -> Self {
    Self {
      real_fs,
      virtual_file_store,
    }
  }
}

impl Debug for VirtualFileSystem {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("VirtualFileSystem")
      .field("virtual_file_store", &"<VirtualFileStore>")
      .field("real_fs", &"<ReadableFileSystem>")
      .finish()
  }
}

#[async_trait::async_trait]
impl ReadableFileSystem for VirtualFileSystem {
  async fn read(&self, path: &Utf8Path) -> Result<Vec<u8>> {
    if let Ok(store) = self.virtual_file_store.read()
      && let Some(content) = store.get_file_content(path)
    {
      return Ok(content.clone());
    }

    self.real_fs.read(path).await
  }

  fn read_sync(&self, path: &Utf8Path) -> Result<Vec<u8>> {
    if let Ok(store) = self.virtual_file_store.read()
      && let Some(content) = store.get_file_content(path)
    {
      return Ok(content.clone());
    }

    self.real_fs.read_sync(path)
  }

  async fn metadata(&self, path: &Utf8Path) -> Result<FileMetadata> {
    if let Ok(store) = self.virtual_file_store.read()
      && let Some(metadata) = store.get_file_metadata(path)
    {
      return Ok(metadata);
    }

    self.real_fs.metadata(path).await
  }

  fn metadata_sync(&self, path: &Utf8Path) -> Result<FileMetadata> {
    if let Ok(store) = self.virtual_file_store.read()
      && let Some(metadata) = store.get_file_metadata(path)
    {
      return Ok(metadata);
    }

    self.real_fs.metadata_sync(path)
  }

  async fn symlink_metadata(&self, path: &Utf8Path) -> Result<FileMetadata> {
    if let Ok(store) = self.virtual_file_store.read()
      && let Some(metadata) = store.get_file_metadata(path)
    {
      return Ok(metadata);
    }

    self.real_fs.symlink_metadata(path).await
  }

  async fn canonicalize(&self, path: &Utf8Path) -> Result<Utf8PathBuf> {
    if let Ok(store) = self.virtual_file_store.read()
      && store.contains(path)
    {
      return Ok(path.to_path_buf());
    }

    self.real_fs.canonicalize(path).await
  }

  async fn read_dir(&self, dir: &Utf8Path) -> Result<Vec<String>> {
    if let Some(mut vlist) = self
      .virtual_file_store
      .read()
      .ok()
      .and_then(|store| store.read_dir(dir))
    {
      let mut list = self.real_fs.read_dir(dir).await.unwrap_or_default();
      list.append(&mut vlist);
      Ok(list)
    } else {
      self.real_fs.read_dir(dir).await
    }
  }

  fn read_dir_sync(&self, dir: &Utf8Path) -> Result<Vec<String>> {
    if let Some(mut vlist) = self
      .virtual_file_store
      .read()
      .ok()
      .and_then(|store| store.read_dir(dir))
    {
      let mut list = self.real_fs.read_dir_sync(dir).unwrap_or_default();
      list.append(&mut vlist);
      Ok(list)
    } else {
      self.real_fs.read_dir_sync(dir)
    }
  }

  async fn permissions(&self, path: &Utf8Path) -> Result<Option<FilePermissions>> {
    if let Ok(store) = self.virtual_file_store.read()
      && store.contains(path)
    {
      return Ok(Some(FilePermissions::from_mode(0o700)));
    }

    self.real_fs.permissions(path).await
  }
}