Skip to main content

async_tempfile/
errors.rs

1use std::fmt::{Display, Formatter};
2use std::path::PathBuf;
3
4#[derive(Debug)]
5pub enum Error {
6    /// An invalid or missing directory was specified.
7    InvalidDirectory,
8    /// An invalid or missing file was specified.
9    InvalidFile,
10    /// A name affix (prefix or suffix) contained a path separator.
11    ///
12    /// Affixes are composed into a single path component
13    /// (`{prefix}{random}{suffix}`); a separator would let the name escape the
14    /// target directory, so such affixes are rejected before any filesystem
15    /// access. The target directory itself is unaffected (and still valid).
16    InvalidAffix,
17    /// An I/O error occurred.
18    Io(std::io::Error),
19}
20
21impl Display for Error {
22    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23        match self {
24            Self::InvalidDirectory => write!(f, "An invalid directory was specified"),
25            Self::InvalidFile => write!(f, "An invalid file name was specified"),
26            Self::InvalidAffix => {
27                write!(f, "A name prefix or suffix contained a path separator")
28            }
29            Self::Io(e) => Display::fmt(e, f),
30        }
31    }
32}
33
34impl std::error::Error for Error {}
35
36impl From<std::io::Error> for Error {
37    fn from(e: std::io::Error) -> Self {
38        Self::Io(e)
39    }
40}
41
42/// The error returned by [`crate::TempFile::persist`] and
43/// [`crate::TempDir::persist`] when the move to the target path fails.
44///
45/// On failure the temporary file or directory is **not** deleted: it is left in
46/// place at [`PersistError::path`] so the caller can recover the data instead of
47/// losing it. To restore automatic cleanup, re-wrap that path with
48/// `from_existing(path, Ownership::Owned)`.
49///
50/// There is intentionally no `From<PersistError> for Error` conversion: a
51/// blanket `?` would silently drop [`PersistError::path`], the one piece of
52/// information that makes recovery possible. Handle the two fields explicitly,
53/// or use `map_err(|e| e.error)` if you only care about the underlying error.
54#[derive(Debug)]
55pub struct PersistError {
56    /// The underlying error that prevented the move (for example a cross-device
57    /// rename, a permission error, or a missing target directory).
58    pub error: Error,
59    /// The path at which the temporary file or directory still resides.
60    pub path: PathBuf,
61}
62
63impl Display for PersistError {
64    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
65        write!(
66            f,
67            "failed to persist temporary at {:?}: {}",
68            self.path, self.error
69        )
70    }
71}
72
73impl std::error::Error for PersistError {
74    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
75        Some(&self.error)
76    }
77}