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