1use core::fmt;
2
3#[cfg(feature = "alloc")]
4use alloc::string::ToString;
5
6#[cfg(feature = "alloc")]
7use alloc::boxed::Box;
8
9#[derive(Debug)]
11pub struct Error<E> {
12 err: ErrorImpl<E>,
13 #[cfg(not(feature = "alloc"))]
14 msg: &'static str,
15 #[cfg(feature = "alloc")]
16 msg: alloc::string::String
17}
18
19impl<E> Error<E> {
20 #[cfg(not(feature = "alloc"))]
26 pub fn message(msg: &'static str) -> Self {
27 Error { err: ErrorImpl::Message, msg }
28 }
29
30 #[cfg(feature = "alloc")]
36 pub fn message<T: fmt::Display>(msg: T) -> Self {
37 Error { err: ErrorImpl::Message, msg: msg.to_string() }
38 }
39
40 pub fn write(e: E) -> Self {
42 Error { err: ErrorImpl::Write(e), msg: Default::default() }
43 }
44
45 #[cfg(feature = "alloc")]
49 pub fn custom<T: core::error::Error + Send + Sync + 'static>(err: T) -> Self {
50 Error { err: ErrorImpl::Custom(Box::new(err)), msg: Default::default() }
51 }
52
53 #[cfg(not(feature = "alloc"))]
59 pub fn with_message(mut self, msg: &'static str) -> Self {
60 self.msg = msg;
61 self
62 }
63
64 #[cfg(feature = "alloc")]
70 pub fn with_message<T: fmt::Display>(mut self, msg: T) -> Self {
71 self.msg = msg.to_string();
72 self
73 }
74
75 pub fn is_message(&self) -> bool {
76 matches!(self.err, ErrorImpl::Message)
77 }
78
79 pub fn is_write(&self) -> bool {
80 matches!(self.err, ErrorImpl::Write(_))
81 }
82
83 #[cfg(feature = "alloc")]
84 pub fn is_custom(&self) -> bool {
85 matches!(self.err, ErrorImpl::Custom(_))
86 }
87
88 pub fn as_write(&self) -> Option<&E> {
90 if let ErrorImpl::Write(e) = &self.err {
91 Some(e)
92 } else {
93 None
94 }
95 }
96
97 pub fn into_write(self) -> Option<E> {
99 if let ErrorImpl::Write(e) = self.err {
100 Some(e)
101 } else {
102 None
103 }
104 }
105}
106
107#[derive(Debug)]
109enum ErrorImpl<E> {
110 Write(E),
112 Message,
114 #[cfg(feature = "alloc")]
116 Custom(Box<dyn core::error::Error + Send + Sync>)
117}
118
119impl<E: fmt::Display> fmt::Display for Error<E> {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 match &self.err {
122 ErrorImpl::Message => write!(f, "{}", self.msg),
123 #[cfg(not(feature = "std"))]
124 ErrorImpl::Write(e) =>
125 if self.msg.is_empty() {
126 write!(f, "write error: {e}")
127 } else {
128 write!(f, "write error: {e}, {}", self.msg)
129 }
130 #[cfg(feature = "std")]
131 ErrorImpl::Write(_) =>
132 if self.msg.is_empty() {
133 write!(f, "write error")
134 } else {
135 write!(f, "write error: {}", self.msg)
136 }
137 #[cfg(feature = "alloc")]
138 ErrorImpl::Custom(_) =>
139 if self.msg.is_empty() {
140 write!(f, "encode error")
141 } else {
142 write!(f, "encode error: {}", self.msg)
143 }
144 }
145 }
146}
147
148impl<E: core::error::Error + 'static> core::error::Error for Error<E> {
149 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
150 match &self.err {
151 ErrorImpl::Message => None,
152 ErrorImpl::Write(e) => Some(e),
153 #[cfg(feature = "alloc")]
154 ErrorImpl::Custom(e) => Some(&**e)
155 }
156 }
157}