use std::sync::Arc;
use async_trait::async_trait;
use crate::filesystem::{Filesystem, FilesystemError};
pub struct FallbackFilesystem {
fallbacks: Vec<Arc<dyn Filesystem>>,
}
impl FallbackFilesystem {
#[inline]
pub fn new(fallbacks: Vec<Arc<dyn Filesystem>>) -> Self {
Self { fallbacks }
}
}
#[async_trait]
impl Filesystem for FallbackFilesystem {
async fn read_bytes(&self, asset_path: &str) -> Result<Vec<u8>, FilesystemError> {
for f in &self.fallbacks {
let r = f.read_bytes(asset_path).await;
if r.is_ok() {
return r;
}
}
Err(FilesystemError::NotFound(asset_path.to_string()))
}
async fn write_bytes(&self, asset_path: &str, data: &[u8]) -> Result<(), FilesystemError> {
for f in &self.fallbacks {
let r = f.write_bytes(asset_path, data).await;
if r.is_ok() {
return r;
}
}
Err(FilesystemError::WriteUnsupported)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::filesystem::NativeFilesystem;
use std::path::Path;
use std::sync::Arc;
#[test]
fn read_bytes() {
let tests_dir = Path::new(&env!("CARGO_MANIFEST_DIR")).join("tests");
let data_0_dir = tests_dir.join("test_data_0");
let data_1_dir = tests_dir.join("test_data_1");
let data_0: Arc<dyn Filesystem> = Arc::new(NativeFilesystem::new(data_0_dir));
let data_1: Arc<dyn Filesystem> = Arc::new(NativeFilesystem::new(data_1_dir));
let fs: Arc<dyn Filesystem> = Arc::new(FallbackFilesystem::new(vec![data_1, data_0]));
let hello = pollster::block_on(fs.read_bytes("hello.txt")).unwrap();
let goodbye = pollster::block_on(fs.read_bytes("goodbye.txt")).unwrap();
let word = pollster::block_on(fs.read_bytes("word.txt")).unwrap();
assert_eq!(hello, b"Hello earth\n");
assert_eq!(goodbye, b"Goodbye world\n");
assert_eq!(word, b"assets\n");
let missing = pollster::block_on(fs.read_bytes("MISSING"));
assert!(matches!(missing, Err(FilesystemError::NotFound(_))));
}
}