1use std::path::PathBuf;
2
3use fluent_i18n::t;
4
5use crate::Architecture;
6
7#[derive(Debug, thiserror::Error, PartialEq)]
17pub enum Error {
18 #[error("{msg}", msg = t!("error-invalid-architectures", {
20 "architectures" => format!("{architectures:?}"),
21 "context" => context
22 }))]
23 InvalidArchitectures {
24 architectures: Vec<Architecture>,
26 context: &'static str,
28 },
29
30 #[error("{msg}", msg = t!("error-invalid-integer", { "kind" => format!("{kind:?}") }))]
32 InvalidInteger {
33 kind: std::num::IntErrorKind,
35 },
36
37 #[error("{msg}", msg = t!("error-invalid-variant", { "error" => .0.to_string() }))]
39 InvalidVariant(#[from] strum::ParseError),
40
41 #[error("{msg}", msg = t!("error-invalid-email", { "error" => .0.to_string() }))]
43 InvalidEmail(#[from] email_address::Error),
44
45 #[error("{msg}", msg = t!("error-invalid-url", { "error" => .0.to_string() }))]
47 InvalidUrl(#[from] url::ParseError),
48
49 #[error("{msg}", msg = t!("error-invalid-license", { "error" => .0.to_string() }))]
51 InvalidLicense(#[from] spdx::ParseError),
52
53 #[error("{msg}", msg = t!("error-invalid-semver", { "kind" => kind }))]
61 InvalidSemver {
62 kind: String,
64 },
65
66 #[error("{msg}", msg = t!("error-invalid-chars", { "invalid_char" => invalid_char.to_string() }))]
68 ValueContainsInvalidChars {
69 invalid_char: char,
71 },
72
73 #[error("{msg}", msg = t!("error-incorrect-length", { "length" => length, "expected" => expected }))]
75 IncorrectLength {
76 length: usize,
78 expected: usize,
80 },
81
82 #[error("{msg}", msg = t!("error-delimiter-not-found", { "delimiter" => delimiter.to_string() }))]
84 DelimiterNotFound {
85 delimiter: char,
87 },
88
89 #[error("{msg}", msg = t!("error-restrictions-not-met", {
91 "restrictions" => format!("{restrictions:?}")
92 }))]
93 ValueDoesNotMatchRestrictions {
94 restrictions: Vec<String>,
96 },
97
98 #[error("{msg}", msg = t!("error-regex-mismatch", {
100 "value" => value,
101 "regex_type" => regex_type,
102 "regex" => regex
103 }))]
104 RegexDoesNotMatch {
105 value: String,
107 regex_type: String,
109 regex: String,
111 },
112
113 #[error("{msg}", msg = t!("error-parse", { "error" => .0 }))]
115 ParseError(String),
116
117 #[error("{msg}", msg = t!("error-missing-component", { "component" => component }))]
119 MissingComponent {
120 component: &'static str,
122 },
123
124 #[error("{msg}", msg = t!("error-path-not-absolute", { "path" => .0 }))]
126 PathNotAbsolute(PathBuf),
127
128 #[error("{msg}", msg = t!("error-path-not-relative", { "path" => .0 }))]
130 PathNotRelative(PathBuf),
131
132 #[error("{msg}", msg = t!("error-path-not-file", { "path" => .0 }))]
134 PathIsNotAFile(PathBuf),
135
136 #[error("{msg}", msg = t!("error-filename-invalid-chars", {
138 "path" => .0,
139 "invalid_char" => .1.to_string()
140 }))]
141 FileNameContainsInvalidChars(PathBuf, char),
142
143 #[error("{msg}", msg = t!("error-filename-empty"))]
145 FileNameIsEmpty,
146
147 #[error("{msg}", msg = t!("error-deprecated-license", { "license" => .0 }))]
149 DeprecatedLicense(String),
150
151 #[error("{msg}", msg = t!("error-invalid-component", {
153 "component" => component,
154 "context" => context
155 }))]
156 InvalidComponent {
157 component: &'static str,
159 context: String,
164 },
165
166 #[error("{msg}", msg = t!("error-invalid-pgp-fingerprint"))]
168 InvalidOpenPGPv4Fingerprint,
169
170 #[error("{msg}", msg = t!("error-invalid-pgp-keyid", { "keyid" => .0 }))]
172 InvalidOpenPGPKeyId(String),
173
174 #[error("{msg}", msg = t!("error-invalid-soname-v1", { "name" => .0 }))]
176 InvalidSonameV1(&'static str),
177
178 #[error("{msg}", msg = t!("error-package", { "error" => .0.to_string() }))]
180 Package(#[from] crate::PackageError),
181
182 #[error("{msg}", msg = t!("error-unknown-compression", { "value" => value }))]
184 UnknownCompressionAlgorithmFileExtension {
185 value: String,
187 },
188
189 #[error("{msg}", msg = t!("error-unknown-filetype", { "value" => value }))]
191 UnknownFileTypeIdentifier {
192 value: String,
194 },
195}
196
197impl From<std::num::ParseIntError> for crate::error::Error {
198 fn from(e: std::num::ParseIntError) -> Self {
200 Self::InvalidInteger { kind: *e.kind() }
201 }
202}
203
204impl<'a> From<winnow::error::ParseError<&'a str, winnow::error::ContextError>>
205 for crate::error::Error
206{
207 fn from(value: winnow::error::ParseError<&'a str, winnow::error::ContextError>) -> Self {
209 Self::ParseError(value.to_string())
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use std::num::IntErrorKind;
216
217 use rstest::rstest;
218
219 use super::*;
220
221 #[rstest]
222 #[case(
223 "Invalid integer (caused by InvalidDigit)",
224 Error::InvalidInteger {
225 kind: IntErrorKind::InvalidDigit
226 }
227 )]
228 #[case(
229 "Invalid integer (caused by InvalidDigit)",
230 Error::InvalidInteger {
231 kind: IntErrorKind::InvalidDigit
232 }
233 )]
234 #[case(
235 "Invalid integer (caused by PosOverflow)",
236 Error::InvalidInteger {
237 kind: IntErrorKind::PosOverflow
238 }
239 )]
240 #[allow(deprecated)]
241 #[case(
242 "Invalid integer (caused by InvalidDigit)",
243 Error::InvalidInteger {
244 kind: IntErrorKind::InvalidDigit
245 }
246 )]
247 #[case(
248 "Invalid e-mail (Missing separator character '@'.)",
249 email_address::Error::MissingSeparator.into()
250 )]
251 #[case(
252 "Invalid integer (caused by InvalidDigit)",
253 Error::InvalidInteger {
254 kind: IntErrorKind::InvalidDigit
255 }
256 )]
257 fn error_format_string(#[case] error_str: &str, #[case] error: Error) {
258 assert_eq!(error_str, format!("{error}"));
259 }
260}