parity_scale_codec/
error.rs1use crate::alloc::borrow::Cow;
18#[cfg(feature = "chain-error")]
19use crate::alloc::boxed::Box;
20
21#[derive(PartialEq, Eq, Clone, Debug)]
26pub struct Error {
27 #[cfg(feature = "chain-error")]
28 cause: Option<Box<Error>>,
29 #[cfg(feature = "chain-error")]
30 desc: Cow<'static, str>,
31}
32
33impl Error {
34 pub fn chain(self, desc: impl Into<Cow<'static, str>>) -> Self {
39 #[cfg(feature = "chain-error")]
40 {
41 Self { desc: desc.into(), cause: Some(Box::new(self)) }
42 }
43
44 #[cfg(not(feature = "chain-error"))]
45 {
46 let _ = desc;
47 self
48 }
49 }
50
51 #[cfg(feature = "chain-error")]
53 fn display_with_indent(&self, indent: u32, f: &mut core::fmt::Formatter) -> core::fmt::Result {
54 for _ in 0..indent {
55 f.write_str("\t")?;
56 }
57 f.write_str(&self.desc)?;
58 if let Some(cause) = &self.cause {
59 f.write_str(":")?;
60 f.write_str("\n")?;
61 cause.display_with_indent(indent + 1, f)
62 } else {
63 if indent != 0 {
66 f.write_str("\n")?;
67 }
68 Ok(())
69 }
70 }
71}
72
73impl core::fmt::Display for Error {
74 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
75 #[cfg(feature = "chain-error")]
76 {
77 self.display_with_indent(0, f)
78 }
79
80 #[cfg(not(feature = "chain-error"))]
81 {
82 f.write_str("Codec error")
83 }
84 }
85}
86
87impl From<&'static str> for Error {
88 fn from(desc: &'static str) -> Error {
89 #[cfg(feature = "chain-error")]
90 {
91 Error { desc: desc.into(), cause: None }
92 }
93
94 #[cfg(not(feature = "chain-error"))]
95 {
96 let _ = desc;
97 Error {}
98 }
99 }
100}
101
102#[cfg(feature = "std")]
103impl std::error::Error for Error {
104 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
105 #[cfg(feature = "chain-error")]
106 {
107 self.cause.as_ref().map(|e| e as &(dyn std::error::Error + 'static))
108 }
109
110 #[cfg(not(feature = "chain-error"))]
111 {
112 None
113 }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use crate::Error;
120
121 #[test]
122 fn test_full_error() {
123 let msg: &str = "final type:\n\twrap cause:\n\t\troot cause\n";
124
125 let error = Error::from("root cause").chain("wrap cause").chain("final type");
126
127 assert_eq!(&error.to_string(), msg);
128 }
129
130 #[test]
131 fn impl_std_error() {
132 use std::error::Error as _;
133
134 let error = Error::from("root cause").chain("wrap cause").chain("final type");
135 let s = error.source().unwrap();
136
137 assert_eq!(&s.to_string(), "wrap cause:\n\troot cause\n");
138 }
139}