qubit_fs/temp/
async_temp_directory.rs1use crate::AsyncFileSystem;
12use crate::error::FsResult;
13use crate::path::Path;
14use crate::path::PathComponent;
15use crate::path::RelativePath;
16use crate::spi::AsyncTempResourceSpi;
17use crate::spi::SpiFuture;
18use crate::temp::AsyncTempFile;
19use crate::temp::PersistFailure;
20use crate::temp::PersistOptions;
21use crate::temp::PersistOutcome;
22use crate::temp::TempResourceState;
23
24pub struct AsyncTempDirectory(
42 AsyncTempFile,
44);
45
46impl AsyncTempDirectory {
47 #[inline]
57 pub(crate) fn new(file_system: AsyncFileSystem, path: Path, session: Box<dyn AsyncTempResourceSpi>) -> Self {
58 Self(AsyncTempFile::new(file_system, path, session, "temporary directory"))
59 }
60
61 #[inline]
66 #[must_use]
67 pub const fn path(&self) -> &Path {
68 self.0.path()
69 }
70
71 #[inline]
76 #[must_use]
77 pub const fn state(&self) -> TempResourceState {
78 self.0.state()
79 }
80
81 #[inline]
83 #[must_use]
84 pub fn child(&self, component: &PathComponent) -> Path {
85 self.0.child(component)
86 }
87
88 #[inline]
90 #[must_use]
91 pub fn descendant(&self, relative: &RelativePath) -> Path {
92 self.0.descendant(relative)
93 }
94
95 #[inline]
104 pub fn cleanup(&mut self) -> SpiFuture<'_, FsResult<()>> {
105 self.0.cleanup()
106 }
107
108 #[inline]
117 pub fn keep(&mut self) -> SpiFuture<'_, Result<PersistOutcome, PersistFailure>> {
118 self.0.keep()
119 }
120
121 #[inline]
134 pub fn persist<'a>(
135 &'a mut self,
136 target: &'a Path,
137 options: PersistOptions,
138 ) -> SpiFuture<'a, Result<PersistOutcome, PersistFailure>> {
139 self.0.persist(target, options)
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use std::pin::Pin;
146
147 use super::AsyncTempDirectory;
148 use crate::AsyncFileSystem;
149 use crate::error::FsResult;
150 use crate::metadata::FileKind;
151 use crate::metadata::FileSystemCapabilities;
152 use crate::metadata::FileSystemCapability;
153 use crate::metadata::FileSystemId;
154 use crate::metadata::FileSystemInfo;
155 use crate::metadata::FileSystemLimits;
156 use crate::metadata::SymlinkPolicy;
157 use crate::path::Path;
158 use crate::path::PathComponent;
159 use crate::path::PathConstraints;
160 use crate::path::PathSemantics;
161 use crate::path::RelativePath;
162 use crate::spi::AsyncFileSystemSpi;
163 use crate::spi::AsyncTempResourceSpi;
164 use crate::spi::PersistRequest;
165 use crate::spi::ProviderProperties;
166 use crate::spi::SpiFuture;
167 use crate::spi::SpiPersistFailure;
168 use crate::spi::StatRequest;
169 use crate::spi::StatResponse;
170 use crate::temp::PersistOptions;
171 use crate::temp::PersistOutcome;
172 use crate::temp::TempResourceState;
173
174 struct Session;
175
176 impl AsyncTempResourceSpi for Session {
177 fn cleanup<'a>(self: Pin<&'a mut Self>) -> SpiFuture<'a, FsResult<()>> {
178 Box::pin(async { panic!("test future is not polled") })
179 }
180
181 fn keep<'a>(self: Pin<&'a mut Self>) -> SpiFuture<'a, Result<PersistOutcome, SpiPersistFailure>> {
182 Box::pin(async { panic!("test future is not polled") })
183 }
184
185 fn persist<'a>(
186 self: Pin<&'a mut Self>,
187 _: PersistRequest<'a>,
188 ) -> SpiFuture<'a, Result<PersistOutcome, SpiPersistFailure>> {
189 Box::pin(async { panic!("test future is not polled") })
190 }
191 }
192
193 struct Provider {
194 properties: ProviderProperties,
195 }
196
197 impl AsyncFileSystemSpi for Provider {
198 fn properties(&self) -> ProviderProperties {
199 self.properties.clone()
200 }
201
202 fn stat<'a>(&'a self, _: StatRequest<'a>) -> SpiFuture<'a, FsResult<StatResponse>> {
203 Box::pin(async {
204 Ok(StatResponse::new(
205 Path::parse("/tmp/recording").expect("valid path"),
206 crate::metadata::FileMetadata::new(FileKind::Directory),
207 ))
208 })
209 }
210 }
211
212 fn filesystem() -> AsyncFileSystem {
213 let properties = ProviderProperties::new(
214 FileSystemInfo::new(
215 FileSystemId::new("async-temp-directory-test").expect("valid id"),
216 "test",
217 PathSemantics::Hierarchical,
218 ),
219 crate::spi::ProviderOperations::new().with(crate::spi::ProviderOperation::CreateTempDirectory),
220 FileSystemCapabilities::new().with_guaranteed(FileSystemCapability::TempDirectory),
221 FileSystemLimits::unknown(),
222 PathConstraints::absolute(),
223 SymlinkPolicy::Reject,
224 )
225 .expect("valid properties");
226 AsyncFileSystem::from_spi(Provider { properties }).expect("valid filesystem")
227 }
228
229 #[test]
230 fn forwarding_methods_are_executed_at_runtime() {
231 let file_system = filesystem();
232 let mut directory = AsyncTempDirectory::new(
233 file_system,
234 Path::parse("/tmp/recording").expect("valid path"),
235 Box::new(Session),
236 );
237 let component = PathComponent::parse("child").expect("valid component");
238 let relative = RelativePath::parse("nested/item").expect("valid relative path");
239
240 assert_eq!(directory.path().as_str(), "/tmp/recording");
241 assert_eq!(directory.state(), TempResourceState::Owned);
242 assert_eq!(directory.child(&component).as_str(), "/tmp/recording/child");
243 assert_eq!(directory.descendant(&relative).as_str(), "/tmp/recording/nested/item");
244 drop(directory.cleanup());
245 drop(directory.keep());
246 drop(directory.persist(&Path::parse("/target").expect("valid path"), PersistOptions::default()));
247 }
248}