1use 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
16pub type Result<T, E = SystemError> = result::Result<T, E>;
18
19#[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}