Skip to main content

async_fs_io/
temp.rs

1//! Explicitly asynchronous temporary files and directories.
2
3use std::path::{
4    Path,
5    PathBuf,
6};
7
8use crate::{
9    AsyncFile,
10    FsError,
11    Operation,
12};
13
14/// An asynchronously created temporary directory.
15pub struct TempDir {
16    path: PathBuf,
17}
18
19impl TempDir {
20    /// Create a uniquely named directory below `root`.
21    pub async fn create(root: impl AsRef<Path>) -> Result<Self, FsError> {
22        let root = root.as_ref().to_owned();
23        tokio::fs::create_dir_all(&root)
24            .await
25            .map_err(|error| FsError::io(Operation::Directory, &root, error))?;
26        let path = root.join(format!("tmp-{}", uuid::Uuid::new_v4()));
27        tokio::fs::create_dir(&path)
28            .await
29            .map_err(|error| FsError::io(Operation::Directory, &path, error))?;
30        Ok(Self { path })
31    }
32
33    /// Return the directory path.
34    #[must_use]
35    pub fn path(&self) -> &Path {
36        &self.path
37    }
38
39    /// Remove the directory and all its contents asynchronously.
40    pub async fn remove(self) -> Result<(), FsError> {
41        crate::directory::remove_dir_all(&self.path).await
42    }
43}
44
45/// An asynchronously created temporary file with explicit cleanup.
46pub struct TempFile {
47    path: PathBuf,
48    file: Option<AsyncFile>,
49}
50
51impl TempFile {
52    /// Create a uniquely named temporary file below `root`.
53    pub async fn create(root: impl AsRef<Path>) -> Result<Self, FsError> {
54        let root = root.as_ref().to_owned();
55        tokio::fs::create_dir_all(&root)
56            .await
57            .map_err(|error| FsError::io(Operation::Directory, &root, error))?;
58        let path = root.join(format!("tmp-file-{}", uuid::Uuid::new_v4()));
59        let file = AsyncFile::create_new(&path).await?;
60        Ok(Self {
61            path,
62            file: Some(file),
63        })
64    }
65
66    /// Return the temporary file path.
67    #[must_use]
68    pub fn path(&self) -> &Path {
69        &self.path
70    }
71
72    /// Borrow the open async file.
73    pub fn file_mut(&mut self) -> Result<&mut AsyncFile, FsError> {
74        self.file.as_mut().ok_or_else(|| {
75            FsError::InvalidRequest("temporary file handle was already closed".to_owned())
76        })
77    }
78
79    /// Close the handle and remove the file asynchronously.
80    pub async fn remove(mut self) -> Result<(), FsError> {
81        self.file.take();
82        tokio::fs::remove_file(&self.path)
83            .await
84            .map_err(|error| FsError::io(Operation::Write, &self.path, error))
85    }
86
87    /// Close the handle while retaining the file on disk.
88    pub fn persist(mut self) -> PathBuf {
89        self.file.take();
90        self.path
91    }
92}