toggle/exit_codes.rs
1use std::fmt;
2
3/// Typed error for bad CLI input / range errors (maps to ExitCode::Usage).
4/// Use this instead of bare `anyhow!()` for usage errors so that
5/// `classify_error` can downcast instead of matching on message strings.
6#[derive(Debug)]
7pub struct UsageError(pub String);
8
9impl fmt::Display for UsageError {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 f.write_str(&self.0)
12 }
13}
14
15impl std::error::Error for UsageError {}
16
17/// Exit codes per Phase 0 PRD ยง0.8
18#[derive(Debug, Clone, Copy)]
19pub enum ExitCode {
20 /// EC00: Success
21 Success = 0,
22 /// EC01: Bad CLI / range
23 Usage = 1,
24 /// EC02: File R/W error
25 IoError = 2,
26 /// EC03: Toggle logic issue
27 ToggleError = 3,
28 /// EC04: Internal panic (reserved for future panic hook, not yet wired)
29 #[allow(dead_code)]
30 Internal = 4,
31}
32
33impl ExitCode {
34 /// Map to sysexits.h values for --posix-exit
35 pub fn posix(self) -> i32 {
36 match self {
37 Self::Success => 0, // EX_OK
38 Self::Usage => 64, // EX_USAGE
39 Self::IoError => 74, // EX_IOERR
40 Self::ToggleError => 70, // EX_SOFTWARE
41 Self::Internal => 71, // EX_OSERR
42 }
43 }
44
45 /// Get the numeric value
46 pub fn code(self) -> i32 {
47 self as i32
48 }
49}