1use std::fmt;
2#[derive(Debug)]
3pub enum AppError {
4 Usage(String),
5 Auth(String),
6 Config(String),
7 Network(String),
8 Api(String),
9 Output(String),
10}
11impl AppError {
12 pub fn usage(s: impl Into<String>) -> Self {
13 Self::Usage(s.into())
14 }
15 pub fn auth(s: impl Into<String>) -> Self {
16 Self::Auth(s.into())
17 }
18 pub fn config(s: impl Into<String>) -> Self {
19 Self::Config(s.into())
20 }
21 pub fn network(s: impl Into<String>) -> Self {
22 Self::Network(s.into())
23 }
24 pub fn api(s: impl Into<String>) -> Self {
25 Self::Api(s.into())
26 }
27 pub fn exit_code(&self) -> u8 {
28 match self {
29 Self::Usage(_) => 2,
30 Self::Auth(_) => 1,
31 Self::Config(_) => 1,
32 Self::Network(_) => 1,
33 Self::Api(_) => 1,
34 Self::Output(_) => 1,
35 }
36 }
37 fn kind(&self) -> &'static str {
38 match self {
39 Self::Usage(_) => "usage",
40 Self::Auth(_) => "auth",
41 Self::Config(_) => "config",
42 Self::Network(_) => "network",
43 Self::Api(_) => "api",
44 Self::Output(_) => "output",
45 }
46 }
47}
48impl fmt::Display for AppError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(
51 f,
52 "{}",
53 match self {
54 Self::Usage(x)
55 | Self::Auth(x)
56 | Self::Config(x)
57 | Self::Network(x)
58 | Self::Api(x)
59 | Self::Output(x) => x,
60 }
61 )
62 }
63}
64pub fn print(e: &AppError, format: &str) {
65 let value = serde_json::json!({"error": {"type": e.kind(), "code": e.exit_code(), "message": e.to_string()}});
66 let rendered = if format == "json" {
67 serde_json::to_string(&value)
68 .unwrap_or_else(|_| "{\"error\":{\"message\":\"output failure\"}}".into())
69 } else {
70 toon_format::encode(&value, &toon_format::EncodeOptions::default())
71 .unwrap_or_else(|_| "error: output failure".into())
72 };
73 println!("{rendered}");
74 eprintln!("error[type={}, code={}]: {}", e.kind(), e.exit_code(), e);
75}