Skip to main content

cardanowall_cli/util/
error.rs

1//! The CLI error type that drives the process exit code.
2//!
3//! Every subcommand handler returns `Result<(), CliError>`. A `CliError` carries
4//! the numeric exit code and an optional diagnostic message; `main` prints the
5//! message to stderr (prefixed `cardanowall: `) and exits with the code.
6//!
7//! Exit-code contract (the public UX, identical to the reference CLI):
8//!
9//! - `0` — success (verdict valid, or a non-verdict happy path).
10//! - `1` — integrity-class failure (verdict invalid, service-independence
11//!   violation, server rejection).
12//! - `2` — network-class failure (unrecoverable runtime / IO / unparseable
13//!   response).
14//! - `3` — pending (insufficient confirmations / unconfirmed tx).
15//! - `4` — CLI input error (bad args, malformed positional, conflicting modes).
16
17use std::fmt;
18
19/// A subcommand failure carrying its process exit code and a diagnostic.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct CliError {
22    /// The process exit code (`1`–`4`; `0` never travels as an error).
23    pub code: i32,
24    /// The diagnostic written to stderr. Empty for a silent non-zero exit.
25    pub message: String,
26}
27
28impl CliError {
29    /// Build an error with an explicit code and message.
30    pub fn new(code: i32, message: impl Into<String>) -> Self {
31        Self {
32            code,
33            message: message.into(),
34        }
35    }
36
37    /// A CLI input error (`4`): bad args, malformed positional, conflicting modes.
38    pub fn input(message: impl Into<String>) -> Self {
39        Self::new(4, message)
40    }
41
42    /// An integrity-class error (`1`): invalid verdict, server rejection.
43    pub fn integrity(message: impl Into<String>) -> Self {
44        Self::new(1, message)
45    }
46
47    /// A network-class error (`2`): IO / transport / unparseable response.
48    pub fn network(message: impl Into<String>) -> Self {
49        Self::new(2, message)
50    }
51}
52
53impl fmt::Display for CliError {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        write!(f, "{}", self.message)
56    }
57}
58
59impl std::error::Error for CliError {}