1use std::fmt;
17use std::process;
18
19#[derive(Debug)]
21pub struct CtlError {
22 pub kind: ErrorKind,
23 pub message: String,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum ErrorKind {
28 Usage = 1,
30 Api = 2,
32 Validation = 3,
34}
35
36impl ErrorKind {
37 pub fn code(self) -> i32 {
38 self as i32
39 }
40}
41
42impl fmt::Display for ErrorKind {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 Self::Usage => f.write_str("usage"),
46 Self::Api => f.write_str("api"),
47 Self::Validation => f.write_str("validation"),
48 }
49 }
50}
51
52impl CtlError {
53 pub fn usage(msg: impl Into<String>) -> Self {
54 Self {
55 kind: ErrorKind::Usage,
56 message: msg.into(),
57 }
58 }
59 pub fn api(msg: impl Into<String>) -> Self {
60 Self {
61 kind: ErrorKind::Api,
62 message: msg.into(),
63 }
64 }
65 pub fn validation(msg: impl Into<String>) -> Self {
66 Self {
67 kind: ErrorKind::Validation,
68 message: msg.into(),
69 }
70 }
71
72 pub fn exit(&self) -> ! {
75 eprintln!("cellctl: {}: {}", self.kind, self.message);
76 process::exit(self.kind.code())
77 }
78}
79
80impl fmt::Display for CtlError {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "{}: {}", self.kind, self.message)
83 }
84}
85
86impl std::error::Error for CtlError {}
87
88impl From<anyhow::Error> for CtlError {
90 fn from(e: anyhow::Error) -> Self {
91 Self::api(e.to_string())
92 }
93}
94
95impl From<reqwest::Error> for CtlError {
96 fn from(e: reqwest::Error) -> Self {
97 Self::api(format!("http: {e}"))
98 }
99}
100
101impl From<std::io::Error> for CtlError {
102 fn from(e: std::io::Error) -> Self {
103 Self::usage(format!("io: {e}"))
104 }
105}
106
107impl From<serde_yaml::Error> for CtlError {
108 fn from(e: serde_yaml::Error) -> Self {
109 Self::validation(format!("yaml: {e}"))
110 }
111}
112
113impl From<serde_json::Error> for CtlError {
114 fn from(e: serde_json::Error) -> Self {
115 Self::api(format!("json: {e}"))
116 }
117}
118
119pub type CtlResult<T> = Result<T, CtlError>;