Skip to main content

ferrous_forge/
error.rs

1//! Error handling for Ferrous Forge
2//!
3//! This module provides a unified error handling system for all Ferrous Forge operations.
4
5/// Ferrous Forge specific errors
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8    /// IO errors (file operations, etc.)
9    #[error("IO error: {0}")]
10    Io(#[from] std::io::Error),
11
12    /// Configuration errors
13    #[error("Configuration error: {0}")]
14    Config(String),
15
16    /// Validation errors
17    #[error("Validation error: {0}")]
18    Validation(String),
19
20    /// Template errors
21    #[error("Template error: {0}")]
22    Template(String),
23
24    /// Update system errors
25    #[error("Update error: {0}")]
26    Update(String),
27
28    /// Standards enforcement errors
29    #[error("Standards violation: {0}")]
30    Standards(String),
31
32    /// CLI argument errors
33    #[error("CLI error: {0}")]
34    Cli(String),
35
36    /// External process errors
37    #[error("Process error: {0}")]
38    Process(String),
39
40    /// Serialization errors
41    #[error("Serialization error: {0}")]
42    Serialization(#[from] serde_json::Error),
43
44    /// TOML parsing errors
45    #[error("TOML error: {0}")]
46    Toml(#[from] toml::de::Error),
47
48    /// Network/HTTP errors
49    #[error("Network error: {0}")]
50    Network(String),
51
52    /// Semver parsing errors
53    #[error("Version error: {0}")]
54    Version(#[from] semver::Error),
55
56    /// Parse errors
57    #[error("Parse error: {0}")]
58    Parse(String),
59
60    /// Rust not found
61    #[error("Rust not found: {0}")]
62    RustNotFound(String),
63
64    /// Command execution error
65    #[error("Command error: {0}")]
66    Command(String),
67
68    /// File not found
69    #[error("File not found: {0}")]
70    FileNotFound(String),
71
72    /// Rate limited
73    #[error("Rate limited: retry after {0} seconds")]
74    RateLimited(u64),
75
76    /// Migration error
77    #[error("Migration error: {0}")]
78    Migration(String),
79
80    /// Regex error
81    #[error("Regex error: {0}")]
82    Regex(#[from] regex::Error),
83
84    /// UTF-8 conversion error
85    #[error("UTF-8 error: {0}")]
86    Utf8(#[from] std::str::Utf8Error),
87
88    /// Safety pipeline error
89    #[error("Safety error: {0}")]
90    Safety(String),
91
92    /// Safety pipeline blocked operation
93    #[error("Safety blocked: {0}")]
94    SafetyBlocked(String),
95}
96
97/// Result type alias for Ferrous Forge operations
98pub type Result<T> = std::result::Result<T, Error>;
99
100impl Error {
101    /// Create a new configuration error
102    ///
103    /// # Examples
104    ///
105    /// ```rust
106    /// # use ferrous_forge::Error;
107    /// let err = Error::config("missing config key");
108    /// assert!(err.to_string().contains("missing config key"));
109    /// ```
110    pub fn config(msg: impl Into<String>) -> Self {
111        Self::Config(msg.into())
112    }
113
114    /// Create a new validation error
115    ///
116    /// # Examples
117    ///
118    /// ```rust
119    /// # use ferrous_forge::Error;
120    /// let err = Error::validation("invalid field value");
121    /// assert!(err.to_string().contains("invalid field value"));
122    /// ```
123    pub fn validation(msg: impl Into<String>) -> Self {
124        Self::Validation(msg.into())
125    }
126
127    /// Create a new template error
128    pub fn template(msg: impl Into<String>) -> Self {
129        Self::Template(msg.into())
130    }
131
132    /// Create a new update error
133    pub fn update(msg: impl Into<String>) -> Self {
134        Self::Update(msg.into())
135    }
136
137    /// Create a new standards error
138    pub fn standards(msg: impl Into<String>) -> Self {
139        Self::Standards(msg.into())
140    }
141
142    /// Create a new CLI error
143    pub fn cli(msg: impl Into<String>) -> Self {
144        Self::Cli(msg.into())
145    }
146
147    /// Create a new process error
148    ///
149    /// # Examples
150    ///
151    /// ```rust
152    /// # use ferrous_forge::Error;
153    /// let err = Error::process("cargo build failed");
154    /// assert!(err.to_string().contains("cargo build failed"));
155    /// ```
156    pub fn process(msg: impl Into<String>) -> Self {
157        Self::Process(msg.into())
158    }
159
160    /// Create a new parse error
161    pub fn parse(msg: impl Into<String>) -> Self {
162        Self::Parse(msg.into())
163    }
164
165    /// Create a new rust not found error
166    pub fn rust_not_found(msg: impl Into<String>) -> Self {
167        Self::RustNotFound(msg.into())
168    }
169
170    /// Create a new command error
171    pub fn command(msg: impl Into<String>) -> Self {
172        Self::Command(msg.into())
173    }
174
175    /// Create a new file not found error
176    pub fn file_not_found(msg: impl Into<String>) -> Self {
177        Self::FileNotFound(msg.into())
178    }
179
180    /// Create a new rate limited error
181    pub fn rate_limited(retry_after: u64) -> Self {
182        Self::RateLimited(retry_after)
183    }
184
185    /// Create a new IO error from a string
186    pub fn io(msg: impl Into<String>) -> Self {
187        Self::Io(std::io::Error::other(msg.into()))
188    }
189
190    /// Create a new security error
191    pub fn security(msg: impl Into<String>) -> Self {
192        Self::Validation(format!("Security: {}", msg.into()))
193    }
194
195    /// Create a new migration error
196    pub fn migration(msg: impl Into<String>) -> Self {
197        Self::Migration(msg.into())
198    }
199
200    /// Create a new network error
201    pub fn network(msg: impl Into<String>) -> Self {
202        Self::Network(msg.into())
203    }
204
205    /// Create a new safety error
206    pub fn safety(msg: impl Into<String>) -> Self {
207        Self::Safety(msg.into())
208    }
209
210    /// Create a new safety blocked error
211    pub fn safety_blocked(msg: impl Into<String>) -> Self {
212        Self::SafetyBlocked(msg.into())
213    }
214
215    /// Create a new tool not found error
216    pub fn tool_not_found(tool: impl Into<String>) -> Self {
217        Self::Process(format!("Tool not found: {}", tool.into()))
218    }
219}
220
221/// Convert anyhow errors to our error type
222impl From<anyhow::Error> for Error {
223    fn from(err: anyhow::Error) -> Self {
224        Self::Process(err.to_string())
225    }
226}
227
228/// Convert reqwest errors to our error type
229impl From<reqwest::Error> for Error {
230    fn from(err: reqwest::Error) -> Self {
231        Self::Network(err.to_string())
232    }
233}