camino_tempfile_ext/fixture/
errors.rs

1// Copyright (c) The camino-tempfile Contributors
2// Adapted from assert_fs: Copyright (c) The assert_fs Contributors
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5
6use std::{error::Error, fmt};
7
8pub(crate) trait ChainError {
9    fn chain<F>(self, cause: F) -> Self
10    where
11        F: Error + Send + Sync + 'static;
12}
13
14pub(crate) trait ResultChainExt<T> {
15    fn chain<C>(self, chainable: C) -> Result<T, C>
16    where
17        C: ChainError;
18}
19
20impl<T, E> ResultChainExt<T> for Result<T, E>
21where
22    E: Error + Send + Sync + 'static,
23{
24    fn chain<C>(self, chainable: C) -> Result<T, C>
25    where
26        C: ChainError,
27    {
28        self.map_err(|e| chainable.chain(e))
29    }
30}
31
32/// Fixture initialization cause.
33#[derive(Copy, Clone, Debug, PartialEq, Eq)]
34#[non_exhaustive]
35pub enum FixtureKind {
36    /// Failed when walking the source tree.
37    Walk,
38    /// Failed when copying a file.
39    CopyFile,
40    /// Failed when writing to a file.
41    WriteFile,
42    /// Failed when creating a directory.
43    CreateDir,
44    /// Failed to cleanup fixture.
45    Cleanup,
46    /// Failed to create symlink
47    Symlink,
48}
49
50impl fmt::Display for FixtureKind {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        match *self {
53            FixtureKind::Walk => write!(f, "error walking source tree"),
54            FixtureKind::CopyFile => write!(f, "error copying file"),
55            FixtureKind::WriteFile => write!(f, "error writing file"),
56            FixtureKind::CreateDir => write!(f, "error creating directory"),
57            FixtureKind::Cleanup => write!(f, "error cleaning up fixture"),
58            FixtureKind::Symlink => write!(f, "error creating symlink to target"),
59        }
60    }
61}
62
63/// Failure when initializing the fixture.
64#[derive(Debug)]
65pub struct FixtureError {
66    kind: FixtureKind,
67    cause: Option<Box<dyn Error + Send + Sync + 'static>>,
68}
69
70impl FixtureError {
71    /// Create a `FixtureError`.
72    pub fn new(kind: FixtureKind) -> Self {
73        Self { kind, cause: None }
74    }
75
76    /// Fixture initialization cause.
77    pub fn kind(&self) -> FixtureKind {
78        self.kind
79    }
80}
81
82impl Error for FixtureError {
83    fn description(&self) -> &str {
84        "Failed to initialize fixture"
85    }
86
87    fn cause(&self) -> Option<&dyn Error> {
88        self.cause.as_ref().map(|c| {
89            let c: &dyn Error = c.as_ref();
90            c
91        })
92    }
93}
94
95impl fmt::Display for FixtureError {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        match self.cause {
98            Some(ref cause) => write!(
99                f,
100                "Failed to initialize fixture: {}\nCause: {}",
101                self.kind, cause
102            ),
103            None => write!(f, "Failed to initialize fixture: {}", self.kind),
104        }
105    }
106}
107
108impl ChainError for FixtureError {
109    fn chain<F>(mut self, cause: F) -> Self
110    where
111        F: Error + Send + Sync + 'static,
112    {
113        self.cause = Some(Box::new(cause));
114        self
115    }
116}