x_core/
errors.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4use guppy::TargetSpecError;
5use hex::FromHexError;
6use serde::{de, ser};
7use std::{
8    borrow::Cow,
9    error, fmt, io,
10    path::{Path, PathBuf},
11    process::ExitStatus,
12    result,
13    str::Utf8Error,
14};
15
16/// Type alias for the return type for `run` methods.
17pub type Result<T, E = SystemError> = result::Result<T, E>;
18
19/// A system error that happened while running a lint.
20#[derive(Debug)]
21#[non_exhaustive]
22pub enum SystemError {
23    CwdNotInProjectRoot {
24        current_dir: PathBuf,
25        project_root: &'static Path,
26    },
27    Exec {
28        cmd: &'static str,
29        status: ExitStatus,
30    },
31    GitRoot(Cow<'static, str>),
32    FromHex {
33        context: Cow<'static, str>,
34        err: FromHexError,
35    },
36    Guppy {
37        context: Cow<'static, str>,
38        err: guppy::Error,
39    },
40    HakariCargoToml {
41        context: Cow<'static, str>,
42        err: hakari::CargoTomlError,
43    },
44    HakariTomlOut {
45        context: Cow<'static, str>,
46        err: hakari::TomlOutError,
47    },
48    Io {
49        context: Cow<'static, str>,
50        err: io::Error,
51    },
52    NonUtf8Path {
53        path: Vec<u8>,
54        err: Utf8Error,
55    },
56    Serde {
57        context: Cow<'static, str>,
58        err: Box<dyn error::Error + Send + Sync>,
59    },
60    TargetSpec {
61        context: Cow<'static, str>,
62        err: TargetSpecError,
63    },
64}
65
66impl SystemError {
67    pub fn io(context: impl Into<Cow<'static, str>>, err: io::Error) -> Self {
68        SystemError::Io {
69            context: context.into(),
70            err,
71        }
72    }
73
74    pub fn guppy(context: impl Into<Cow<'static, str>>, err: guppy::Error) -> Self {
75        SystemError::Guppy {
76            context: context.into(),
77            err,
78        }
79    }
80
81    pub fn git_root(msg: impl Into<Cow<'static, str>>) -> Self {
82        SystemError::GitRoot(msg.into())
83    }
84
85    pub fn from_hex(context: impl Into<Cow<'static, str>>, err: FromHexError) -> Self {
86        SystemError::FromHex {
87            context: context.into(),
88            err,
89        }
90    }
91
92    pub fn hakari_cargo_toml(
93        context: impl Into<Cow<'static, str>>,
94        err: hakari::CargoTomlError,
95    ) -> Self {
96        SystemError::HakariCargoToml {
97            context: context.into(),
98            err,
99        }
100    }
101
102    pub fn hakari_toml_out(
103        context: impl Into<Cow<'static, str>>,
104        err: hakari::TomlOutError,
105    ) -> Self {
106        SystemError::HakariTomlOut {
107            context: context.into(),
108            err,
109        }
110    }
111
112    pub fn de(
113        context: impl Into<Cow<'static, str>>,
114        err: impl de::Error + Send + Sync + 'static,
115    ) -> Self {
116        SystemError::Serde {
117            context: context.into(),
118            err: Box::new(err),
119        }
120    }
121
122    pub fn ser(
123        context: impl Into<Cow<'static, str>>,
124        err: impl ser::Error + Send + Sync + 'static,
125    ) -> Self {
126        SystemError::Serde {
127            context: context.into(),
128            err: Box::new(err),
129        }
130    }
131
132    pub fn target_spec(context: impl Into<Cow<'static, str>>, err: TargetSpecError) -> Self {
133        SystemError::TargetSpec {
134            context: context.into(),
135            err,
136        }
137    }
138}
139
140impl fmt::Display for SystemError {
141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142        match self {
143            SystemError::CwdNotInProjectRoot {
144                current_dir,
145                project_root,
146            } => write!(
147                f,
148                "current dir {} not in project root {}",
149                current_dir.display(),
150                project_root.display(),
151            ),
152            SystemError::Exec { cmd, status } => match status.code() {
153                Some(code) => write!(f, "'{}' failed with exit code {}", cmd, code),
154                None => write!(f, "'{}' terminated by signal", cmd),
155            },
156            SystemError::GitRoot(s) => write!(f, "git root error: {}", s),
157            SystemError::NonUtf8Path { path, .. } => {
158                write!(f, "non-UTF-8 path \"{}\"", String::from_utf8_lossy(path))
159            }
160            SystemError::FromHex { context, .. }
161            | SystemError::Io { context, .. }
162            | SystemError::Serde { context, .. }
163            | SystemError::Guppy { context, .. }
164            | SystemError::HakariCargoToml { context, .. }
165            | SystemError::HakariTomlOut { context, .. }
166            | SystemError::TargetSpec { context, .. } => write!(f, "while {}", context),
167        }
168    }
169}
170
171impl error::Error for SystemError {
172    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
173        match self {
174            SystemError::CwdNotInProjectRoot { .. }
175            | SystemError::Exec { .. }
176            | SystemError::GitRoot(_) => None,
177            SystemError::FromHex { err, .. } => Some(err),
178            SystemError::Io { err, .. } => Some(err),
179            SystemError::Guppy { err, .. } => Some(err),
180            SystemError::HakariCargoToml { err, .. } => Some(err),
181            SystemError::HakariTomlOut { err, .. } => Some(err),
182            SystemError::NonUtf8Path { err, .. } => Some(err),
183            SystemError::TargetSpec { err, .. } => Some(err),
184            SystemError::Serde { err, .. } => Some(err.as_ref()),
185        }
186    }
187}