1use crate::command::{ERR_NO_CONTEXT, ERR_PERM_PREFIX};
17
18#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
20pub enum CoreError {
21 #[error("{0}")]
25 Permission(String),
26 #[error("{0}")]
29 NoContext(String),
30 #[error("{0}")]
32 Other(String),
33}
34
35impl CoreError {
36 pub fn code(&self) -> &'static str {
38 match self {
39 CoreError::Permission(_) => "permission",
40 CoreError::NoContext(_) => "no_context",
41 CoreError::Other(_) => "other",
42 }
43 }
44
45 pub fn classify(msg: String) -> Self {
47 if msg.starts_with(ERR_PERM_PREFIX) {
48 CoreError::Permission(msg)
49 } else if msg.starts_with(ERR_NO_CONTEXT) {
50 CoreError::NoContext(msg)
51 } else {
52 CoreError::Other(msg)
53 }
54 }
55
56 pub fn message(&self) -> &str {
58 match self {
59 CoreError::Permission(m) | CoreError::NoContext(m) | CoreError::Other(m) => m,
60 }
61 }
62}
63
64impl From<String> for CoreError {
65 fn from(msg: String) -> Self {
66 Self::classify(msg)
67 }
68}
69
70impl From<&str> for CoreError {
71 fn from(msg: &str) -> Self {
72 Self::classify(msg.to_string())
73 }
74}
75
76pub type CoreResult<T> = Result<T, CoreError>;
78
79#[cfg(test)]
80mod tests {
81 use super::CoreError;
82 use crate::command::{
83 ERR_NO_BATCH_WRITE, ERR_NO_CONTEXT, ERR_NO_DELETE, ERR_NO_WRITE, ERR_PERMISSION,
84 };
85
86 #[test]
87 fn classify_maps_sentinels_to_variants() {
88 for m in [
90 ERR_PERMISSION,
91 ERR_NO_WRITE,
92 ERR_NO_DELETE,
93 ERR_NO_BATCH_WRITE,
94 ] {
95 let e = CoreError::classify(m.to_string());
96 assert_eq!(e, CoreError::Permission(m.to_string()));
97 assert_eq!(e.code(), "permission");
98 }
99 let e = CoreError::classify(ERR_NO_CONTEXT.to_string());
101 assert_eq!(e, CoreError::NoContext(ERR_NO_CONTEXT.to_string()));
102 assert_eq!(e.code(), "no_context");
103 let e = CoreError::classify("translate: 未知命令".to_string());
105 assert_eq!(e, CoreError::Other("translate: 未知命令".to_string()));
106 assert_eq!(e.code(), "other");
107 }
108
109 #[test]
110 fn display_preserves_message_verbatim() {
111 let e = CoreError::from(ERR_NO_WRITE);
113 assert_eq!(e.to_string(), ERR_NO_WRITE);
114 assert_eq!(e.message(), ERR_NO_WRITE);
115 }
116
117 #[test]
118 fn from_str_and_string_classify_identically() {
119 assert_eq!(
120 CoreError::from(ERR_PERMISSION),
121 CoreError::classify(ERR_PERMISSION.to_string())
122 );
123 }
124}