vfs/async_vfs/impls/
altroot.rs1use crate::async_vfs::{AsyncFileSystem, AsyncVfsPath, SeekAndRead};
4use crate::{error::VfsErrorKind, VfsMetadata, VfsResult};
5use std::time::SystemTime;
6
7use async_std::io::Write;
8use async_trait::async_trait;
9use futures::stream::{Stream, StreamExt};
10
11#[derive(Debug, Clone)]
18pub struct AsyncAltrootFS {
19 root: AsyncVfsPath,
20}
21
22impl AsyncAltrootFS {
23 pub fn new(root: AsyncVfsPath) -> Self {
25 AsyncAltrootFS { root }
26 }
27}
28
29impl AsyncAltrootFS {
30 #[allow(clippy::manual_strip)] fn path(&self, path: &str) -> VfsResult<AsyncVfsPath> {
32 if path.is_empty() {
33 return Ok(self.root.clone());
34 }
35 if path.starts_with('/') {
36 return self.root.join(&path[1..]);
37 }
38 self.root.join(path)
39 }
40}
41
42#[async_trait]
43impl AsyncFileSystem for AsyncAltrootFS {
44 async fn read_dir(
45 &self,
46 path: &str,
47 ) -> VfsResult<Box<dyn Stream<Item = String> + Send + Unpin>> {
48 self.path(path)?
49 .read_dir()
50 .await
51 .map(|result| result.map(|path| path.filename()))
52 .map(|entries| Box::new(entries) as Box<dyn Stream<Item = String> + Send + Unpin>)
53 }
54
55 async fn create_dir(&self, path: &str) -> VfsResult<()> {
56 self.path(path)?.create_dir().await
57 }
58
59 async fn open_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndRead + Send + Unpin>> {
60 self.path(path)?.open_file().await
61 }
62
63 async fn create_file(&self, path: &str) -> VfsResult<Box<dyn Write + Send + Unpin>> {
64 self.path(path)?.create_file().await
65 }
66
67 async fn append_file(&self, path: &str) -> VfsResult<Box<dyn Write + Send + Unpin>> {
68 self.path(path)?.append_file().await
69 }
70
71 async fn metadata(&self, path: &str) -> VfsResult<VfsMetadata> {
72 self.path(path)?.metadata().await
73 }
74
75 async fn set_creation_time(&self, path: &str, time: SystemTime) -> VfsResult<()> {
76 self.path(path)?.set_creation_time(time).await
77 }
78
79 async fn set_modification_time(&self, path: &str, time: SystemTime) -> VfsResult<()> {
80 self.path(path)?.set_modification_time(time).await
81 }
82
83 async fn set_access_time(&self, path: &str, time: SystemTime) -> VfsResult<()> {
84 self.path(path)?.set_access_time(time).await
85 }
86
87 async fn exists(&self, path: &str) -> VfsResult<bool> {
88 match self.path(path) {
89 Ok(p) => p.exists().await,
90 Err(_) => Ok(false),
91 }
92 }
93
94 async fn remove_file(&self, path: &str) -> VfsResult<()> {
95 self.path(path)?.remove_file().await
96 }
97
98 async fn remove_dir(&self, path: &str) -> VfsResult<()> {
99 self.path(path)?.remove_dir().await
100 }
101
102 async fn copy_file(&self, src: &str, dest: &str) -> VfsResult<()> {
103 if dest.is_empty() {
104 return Err(VfsErrorKind::NotSupported.into());
105 }
106 self.path(src)?.copy_file(&self.path(dest)?).await
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use crate::async_vfs::AsyncMemoryFS;
114
115 test_async_vfs!(futures::executor::block_on(async {
116 let memory_root: AsyncVfsPath = AsyncMemoryFS::new().into();
117 let altroot_path = memory_root.join("altroot").unwrap();
118 altroot_path.create_dir().await.unwrap();
119 AsyncAltrootFS::new(altroot_path)
120 }));
121
122 #[tokio::test]
123 async fn parent() {
124 let memory_root: AsyncVfsPath = AsyncMemoryFS::new().into();
125 let altroot_path = memory_root.join("altroot").unwrap();
126 altroot_path.create_dir().await.unwrap();
127 let altroot: AsyncVfsPath = AsyncAltrootFS::new(altroot_path.clone()).into();
128 assert_eq!(altroot.parent(), altroot.root());
129 assert_eq!(altroot_path.parent(), memory_root);
130 }
131}
132
133#[cfg(test)]
134mod tests_physical {
135 use super::*;
136 use crate::async_vfs::AsyncPhysicalFS;
137
138 use async_std::io::ReadExt;
139
140 test_async_vfs!(futures::executor::block_on(async {
141 let temp_dir = std::env::temp_dir();
142 let dir = temp_dir.join(uuid::Uuid::new_v4().to_string());
143 std::fs::create_dir_all(&dir).unwrap();
144
145 let physical_root: AsyncVfsPath = AsyncPhysicalFS::new(dir).into();
146 let altroot_path = physical_root.join("altroot").unwrap();
147 altroot_path.create_dir().await.unwrap();
148 AsyncAltrootFS::new(altroot_path)
149 }));
150
151 test_async_vfs_readonly!({
152 let physical_root: AsyncVfsPath = AsyncPhysicalFS::new("test").into();
153 let altroot_path = physical_root.join("test_directory").unwrap();
154 AsyncAltrootFS::new(altroot_path)
155 });
156}