arch_toolkit/error.rs
1//! Unified error type for arch-toolkit.
2
3use thiserror::Error;
4
5/// Unified error type for all arch-toolkit operations.
6///
7/// This error type covers all possible failure modes across different modules,
8/// providing clear, actionable error messages.
9#[derive(Error, Debug)]
10pub enum ArchToolkitError {
11 /// Network or HTTP request error.
12 ///
13 /// Note: For AUR operations, prefer using operation-specific error variants
14 /// (`SearchFailed`, `InfoFailed`, `CommentsFailed`, `PkgbuildFailed`) to preserve context.
15 /// This variant is retained for client initialization and non-AUR operations.
16 #[error("Network error: {0}")]
17 Network(reqwest::Error),
18
19 /// AUR search operation failed.
20 #[error("AUR search failed for query '{query}': {source}")]
21 SearchFailed {
22 /// The search query that failed.
23 query: String,
24 /// The underlying network error.
25 #[source]
26 source: reqwest::Error,
27 },
28
29 /// AUR info fetch operation failed.
30 #[error("AUR info fetch failed for packages [{packages}]: {source}")]
31 InfoFailed {
32 /// Comma-separated list of package names that failed.
33 packages: String,
34 /// The underlying network error.
35 #[source]
36 source: reqwest::Error,
37 },
38
39 /// AUR comments fetch operation failed.
40 #[error("AUR comments fetch failed for package '{package}': {source}")]
41 CommentsFailed {
42 /// The package name that failed.
43 package: String,
44 /// The underlying network error.
45 #[source]
46 source: reqwest::Error,
47 },
48
49 /// PKGBUILD fetch operation failed.
50 #[error("PKGBUILD fetch failed for package '{package}': {source}")]
51 PkgbuildFailed {
52 /// The package name that failed.
53 package: String,
54 /// The underlying network error.
55 #[source]
56 source: reqwest::Error,
57 },
58
59 /// JSON parsing error.
60 #[error("JSON parsing error: {0}")]
61 Json(#[from] serde_json::Error),
62
63 /// Custom parsing error with message.
64 #[error("Parse error: {0}")]
65 Parse(String),
66
67 /// Rate limiting error with optional retry-after information.
68 #[error("Rate limited by server{0}", .retry_after.map(|s| format!(" (retry after {s}s)")).unwrap_or_default())]
69 RateLimited {
70 /// Optional retry-after value in seconds from server.
71 retry_after: Option<u64>,
72 },
73
74 /// Package not found (enhanced with package name).
75 #[error("Package '{package}' not found")]
76 PackageNotFound {
77 /// The package name that was not found.
78 package: String,
79 },
80
81 /// Invalid input parameter.
82 #[error("Invalid input: {0}")]
83 InvalidInput(String),
84
85 /// Empty input provided where a value is required.
86 #[error("Empty {field}: {message}")]
87 EmptyInput {
88 /// The field name that is empty.
89 field: String,
90 /// Detailed message about why the field cannot be empty.
91 message: String,
92 },
93
94 /// Package name contains invalid characters or format.
95 #[error("Invalid package name '{name}': {reason}")]
96 InvalidPackageName {
97 /// The invalid package name.
98 name: String,
99 /// Reason why the package name is invalid.
100 reason: String,
101 },
102
103 /// Search query validation failed.
104 #[error("Invalid search query: {reason}")]
105 InvalidSearchQuery {
106 /// Reason why the search query is invalid.
107 reason: String,
108 },
109
110 /// Input exceeds maximum length.
111 #[error("{field} exceeds maximum length of {max_length} characters (got {actual_length})")]
112 InputTooLong {
113 /// The field name that is too long.
114 field: String,
115 /// Maximum allowed length.
116 max_length: usize,
117 /// Actual length of the input.
118 actual_length: usize,
119 },
120}
121
122impl ArchToolkitError {
123 /// What: Create a `SearchFailed` error with query context.
124 ///
125 /// Inputs:
126 /// - `query`: The search query that failed
127 /// - `source`: The underlying network error
128 ///
129 /// Output:
130 /// - `ArchToolkitError::SearchFailed` variant
131 ///
132 /// Details:
133 /// - Convenience constructor for search operation errors
134 /// - Preserves both the query and the underlying error
135 #[must_use]
136 pub fn search_failed(query: impl Into<String>, source: reqwest::Error) -> Self {
137 Self::SearchFailed {
138 query: query.into(),
139 source,
140 }
141 }
142
143 /// What: Create an `InfoFailed` error with package names context.
144 ///
145 /// Inputs:
146 /// - `packages`: Slice of package names that failed
147 /// - `source`: The underlying network error
148 ///
149 /// Output:
150 /// - `ArchToolkitError::InfoFailed` variant
151 ///
152 /// Details:
153 /// - Convenience constructor for info operation errors
154 /// - Formats package names as comma-separated string
155 /// - Preserves both the package names and the underlying error
156 #[must_use]
157 pub fn info_failed(packages: &[&str], source: reqwest::Error) -> Self {
158 Self::InfoFailed {
159 packages: packages.join(", "),
160 source,
161 }
162 }
163
164 /// What: Create a `CommentsFailed` error with package name context.
165 ///
166 /// Inputs:
167 /// - `package`: The package name that failed
168 /// - `source`: The underlying network error
169 ///
170 /// Output:
171 /// - `ArchToolkitError::CommentsFailed` variant
172 ///
173 /// Details:
174 /// - Convenience constructor for comments operation errors
175 /// - Preserves both the package name and the underlying error
176 #[must_use]
177 pub fn comments_failed(package: impl Into<String>, source: reqwest::Error) -> Self {
178 Self::CommentsFailed {
179 package: package.into(),
180 source,
181 }
182 }
183
184 /// What: Create a `PkgbuildFailed` error with package name context.
185 ///
186 /// Inputs:
187 /// - `package`: The package name that failed
188 /// - `source`: The underlying network error
189 ///
190 /// Output:
191 /// - `ArchToolkitError::PkgbuildFailed` variant
192 ///
193 /// Details:
194 /// - Convenience constructor for pkgbuild operation errors
195 /// - Preserves both the package name and the underlying error
196 #[must_use]
197 pub fn pkgbuild_failed(package: impl Into<String>, source: reqwest::Error) -> Self {
198 Self::PkgbuildFailed {
199 package: package.into(),
200 source,
201 }
202 }
203}
204
205/// Result type alias for arch-toolkit operations.
206pub type Result<T> = std::result::Result<T, ArchToolkitError>;