1use std::{error::Error, fmt, rc::Rc};
2
3use ntex_bytes::ByteString;
4
5pub fn fmt_err_string(e: &dyn Error) -> String {
6 let mut buf = String::new();
7 _ = fmt_err(&mut buf, e);
8 buf
9}
10
11pub fn fmt_err(f: &mut dyn fmt::Write, e: &dyn Error) -> fmt::Result {
12 let mut current = Some(e);
13 while let Some(std_err) = current {
14 writeln!(f, "{std_err}")?;
15 current = std_err.source();
16 }
17 Ok(())
18}
19
20#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
21pub struct ErrorMessage(ByteString);
22
23#[derive(Debug, Clone, thiserror::Error)]
24#[error("{msg}")]
25pub struct ErrorMessageChained {
26 msg: ByteString,
27 #[source]
28 source: Option<Rc<dyn Error>>,
29}
30
31impl ErrorMessageChained {
32 pub fn new<M, E>(ctx: M, source: E) -> Self
33 where
34 M: Into<ErrorMessage>,
35 E: Error + 'static,
36 {
37 ErrorMessageChained {
38 msg: ctx.into().into_string(),
39 source: Some(Rc::new(source)),
40 }
41 }
42
43 pub const fn from_bstr(msg: ByteString) -> Self {
45 Self { msg, source: None }
46 }
47
48 pub fn msg(&self) -> &ByteString {
49 &self.msg
50 }
51
52 pub fn source(&self) -> &Option<Rc<dyn Error>> {
53 &self.source
54 }
55}
56
57impl ErrorMessage {
58 pub const fn empty() -> Self {
60 Self(ByteString::from_static(""))
61 }
62
63 pub const fn from_bstr(msg: ByteString) -> ErrorMessage {
65 ErrorMessage(msg)
66 }
67
68 pub const fn from_static(msg: &'static str) -> Self {
70 ErrorMessage(ByteString::from_static(msg))
71 }
72
73 pub fn is_empty(&self) -> bool {
74 self.0.is_empty()
75 }
76
77 pub fn as_str(&self) -> &str {
78 &self.0
79 }
80
81 pub fn as_bstr(&self) -> &ByteString {
82 &self.0
83 }
84
85 pub fn into_string(self) -> ByteString {
86 self.0
87 }
88
89 pub fn with_source<E: Error + 'static>(self, source: E) -> ErrorMessageChained {
90 ErrorMessageChained::new(self, source)
91 }
92}
93
94impl From<String> for ErrorMessage {
95 fn from(value: String) -> Self {
96 Self(ByteString::from(value))
97 }
98}
99
100impl From<ByteString> for ErrorMessage {
101 fn from(value: ByteString) -> Self {
102 Self(value)
103 }
104}
105
106impl From<&'static str> for ErrorMessage {
107 fn from(value: &'static str) -> Self {
108 Self(ByteString::from_static(value))
109 }
110}
111
112impl fmt::Display for ErrorMessage {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.0.fmt(f)
115 }
116}
117
118impl From<ErrorMessage> for ByteString {
119 fn from(msg: ErrorMessage) -> Self {
120 msg.0
121 }
122}
123
124impl<'a> From<&'a ErrorMessage> for ByteString {
125 fn from(msg: &'a ErrorMessage) -> Self {
126 msg.0.clone()
127 }
128}
129
130impl<M: Into<ErrorMessage>> From<M> for ErrorMessageChained {
131 fn from(value: M) -> Self {
132 ErrorMessageChained {
133 msg: value.into().0,
134 source: None,
135 }
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn error_message() {
145 let msg = ErrorMessage::empty();
146 assert!(msg.is_empty());
147 assert_eq!(msg.as_str(), "");
148 assert_eq!(msg.as_bstr(), ByteString::new());
149 assert_eq!(ByteString::new(), msg.as_bstr());
150 assert_eq!(ByteString::new(), msg.into_string());
151
152 let msg = ErrorMessage::from("test");
153 assert!(!msg.is_empty());
154 assert_eq!(msg.as_str(), "test");
155 assert_eq!(msg.as_bstr(), ByteString::from("test"));
156
157 let msg = ErrorMessage::from("test".to_string());
158 assert!(!msg.is_empty());
159 assert_eq!(msg.as_str(), "test");
160 assert_eq!(msg.as_bstr(), ByteString::from("test"));
161
162 let msg = ErrorMessage::from_bstr(ByteString::from("test"));
163 assert!(!msg.is_empty());
164 assert_eq!(msg.as_str(), "test");
165 assert_eq!(msg.as_bstr(), ByteString::from("test"));
166
167 let msg = ErrorMessage::from(ByteString::from("test"));
168 assert!(!msg.is_empty());
169 assert_eq!(msg.as_str(), "test");
170 assert_eq!(msg.as_bstr(), ByteString::from("test"));
171
172 let msg = ErrorMessage::from_static("test");
173 assert!(!msg.is_empty());
174 assert_eq!(msg.as_str(), "test");
175 assert_eq!(msg.as_bstr(), ByteString::from("test"));
176
177 assert_eq!(ByteString::from(&msg), "test");
178 assert_eq!(ByteString::from(msg), "test");
179 }
180
181 #[test]
182 fn error_message_chained() {
183 let chained = ErrorMessageChained::from(ByteString::from("test"));
184 assert_eq!(chained.msg(), "test");
185 assert!(chained.source().is_none());
186
187 let chained = ErrorMessageChained::from_bstr(ByteString::from("test"));
188 assert_eq!(chained.msg(), "test");
189 assert!(chained.source().is_none());
190 }
191}