Skip to main content

arknet_common/
errors.rs

1//! Error hierarchy shared across the workspace.
2//!
3//! Pattern:
4//! - Each crate defines its own domain error enum via [`thiserror`].
5//! - Crate-level errors implement `From` into [`CommonError`] only where they
6//!   need to surface at public boundaries.
7//! - Never use `anyhow` inside libraries — reserve it for `main.rs`.
8
9use thiserror::Error;
10
11/// Top-level error type for the `arknet-common` crate.
12///
13/// This enum is intentionally small — most errors belong in a dedicated
14/// domain enum in the crate that owns the operation.
15#[derive(Debug, Error)]
16pub enum CommonError {
17    /// An invalid argument was passed to a protocol function.
18    #[error("invalid argument: {0}")]
19    InvalidArgument(String),
20
21    /// A value exceeded a protocol-defined limit.
22    #[error("value out of range: {0}")]
23    OutOfRange(String),
24
25    /// Borsh (de)serialization failed.
26    #[error("borsh (de)serialization error: {0}")]
27    Borsh(String),
28
29    /// JSON (de)serialization failed.
30    #[error("json (de)serialization error: {0}")]
31    Json(String),
32
33    /// TOML parse error.
34    #[error("toml parse error: {0}")]
35    Toml(String),
36
37    /// Config file could not be loaded or validated.
38    #[error("config error: {0}")]
39    Config(String),
40
41    /// I/O failure (file, disk, etc.).
42    #[error("io error: {0}")]
43    Io(#[from] std::io::Error),
44}
45
46// Note: `borsh::io::Error` is a re-export of `std::io::Error`, so the `#[from]`
47// on the `Io` variant already gives us `From<borsh::io::Error>`. See the
48// `Borsh` variant for the human-readable path used by the serialization helpers.
49
50impl From<serde_json::Error> for CommonError {
51    fn from(e: serde_json::Error) -> Self {
52        CommonError::Json(e.to_string())
53    }
54}
55
56/// Protocol-wide result type.
57pub type Result<T, E = CommonError> = std::result::Result<T, E>;
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn display_messages_include_context() {
65        let e = CommonError::InvalidArgument("x must be positive".into());
66        assert_eq!(e.to_string(), "invalid argument: x must be positive");
67    }
68
69    #[test]
70    fn out_of_range_formats() {
71        let e = CommonError::OutOfRange("height > u64::MAX".into());
72        assert!(e.to_string().contains("out of range"));
73    }
74
75    #[test]
76    fn io_error_conversion() {
77        let io = std::io::Error::new(std::io::ErrorKind::NotFound, "nope");
78        let e: CommonError = io.into();
79        assert!(matches!(e, CommonError::Io(_)));
80    }
81}