virtual_fs/
passthru_fs.rs

1//! Wraps a boxed file system with an implemented trait VirtualSystem - this is
2//! needed so that a `Box<dyn VirtualFileSystem>` can be wrapped in an Arc and
3//! shared - some of the interfaces pass around a `Box<dyn VirtualFileSystem>`
4
5use std::{path::Path, sync::Arc};
6
7use crate::*;
8
9#[derive(Debug)]
10pub struct PassthruFileSystem {
11    fs: Arc<dyn FileSystem + Send + Sync + 'static>,
12}
13
14impl PassthruFileSystem {
15    /// Creates a new PassthruFileSystem that wraps the given FileSystem.
16    // NOTE: only kept for backwards compatibility.
17    // TODO: change to only accept Arc, and remove Self::new_arc in the next breaking API change!
18    pub fn new(inner: Box<dyn FileSystem + Send + Sync + 'static>) -> Self {
19        Self { fs: inner.into() }
20    }
21
22    pub fn new_arc(inner: Arc<dyn FileSystem + Send + Sync + 'static>) -> Self {
23        Self { fs: inner }
24    }
25}
26
27impl FileSystem for PassthruFileSystem {
28    fn readlink(&self, path: &Path) -> Result<PathBuf> {
29        self.fs.readlink(path)
30    }
31
32    fn read_dir(&self, path: &Path) -> Result<ReadDir> {
33        self.fs.read_dir(path)
34    }
35
36    fn create_dir(&self, path: &Path) -> Result<()> {
37        self.fs.create_dir(path)
38    }
39
40    fn create_symlink(&self, source: &Path, target: &Path) -> Result<()> {
41        self.fs.create_symlink(source, target)
42    }
43
44    fn hard_link(&self, source: &Path, target: &Path) -> Result<()> {
45        self.fs.hard_link(source, target)
46    }
47
48    fn remove_dir(&self, path: &Path) -> Result<()> {
49        self.fs.remove_dir(path)
50    }
51
52    fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> {
53        Box::pin(async { self.fs.rename(from, to).await })
54    }
55
56    fn metadata(&self, path: &Path) -> Result<Metadata> {
57        self.fs.metadata(path)
58    }
59
60    fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
61        self.fs.symlink_metadata(path)
62    }
63
64    fn remove_file(&self, path: &Path) -> Result<()> {
65        self.fs.remove_file(path)
66    }
67
68    fn new_open_options(&self) -> OpenOptions<'_> {
69        self.fs.new_open_options()
70    }
71}
72
73#[cfg(test)]
74mod test_builder {
75    use std::sync::Arc;
76
77    use tokio::io::{AsyncReadExt, AsyncWriteExt};
78
79    use crate::{FileSystem, PassthruFileSystem};
80
81    #[tokio::test]
82    async fn test_passthru_fs_2() {
83        let mem_fs = crate::mem_fs::FileSystem::default();
84
85        mem_fs
86            .new_open_options()
87            .read(true)
88            .write(true)
89            .create(true)
90            .open("/foo.txt")
91            .unwrap()
92            .write_all(b"hello")
93            .await
94            .unwrap();
95
96        let mut buf = Vec::new();
97        mem_fs
98            .new_open_options()
99            .read(true)
100            .open("/foo.txt")
101            .unwrap()
102            .read_to_end(&mut buf)
103            .await
104            .unwrap();
105        assert_eq!(buf, b"hello");
106
107        let passthru_fs = PassthruFileSystem::new_arc(Arc::new(mem_fs.clone()));
108        let mut buf = Vec::new();
109        passthru_fs
110            .new_open_options()
111            .read(true)
112            .open("/foo.txt")
113            .unwrap()
114            .read_to_end(&mut buf)
115            .await
116            .unwrap();
117        assert_eq!(buf, b"hello");
118    }
119}