1use std::error::Error as StdError;
2use std::fmt;
3
4type Source = Box<dyn StdError + Send + Sync + 'static>;
5
6#[derive(Debug)]
7pub struct Error {
8 inner: Box<ErrorImpl>,
9}
10
11#[derive(Debug)]
12struct ErrorImpl {
13 kind: Kind,
14 cause: Option<Error>,
15}
16
17#[derive(Debug)]
18enum Kind {
19 AdHoc(AdHocError),
21 Crypto(CryptoError),
23 Transaction(TransactionError),
25 CoinSelect(CoinSelectError),
27 ArkAddress(ArkAddressError),
29}
30
31#[derive(Debug)]
32struct AdHocError {
33 source: Source,
34}
35
36#[derive(Debug)]
37struct CryptoError {
38 source: Source,
39}
40
41#[derive(Debug)]
42struct TransactionError {
43 source: Source,
44}
45
46#[derive(Debug)]
47struct CoinSelectError {
48 source: Source,
49}
50
51#[derive(Debug)]
52struct ArkAddressError {
53 source: Source,
54}
55
56impl Error {
57 fn new(kind: Kind) -> Self {
58 Self {
59 inner: Box::new(ErrorImpl { kind, cause: None }),
60 }
61 }
62
63 pub fn ad_hoc(source: impl Into<Source>) -> Self {
64 Error::new(Kind::AdHoc(AdHocError {
65 source: source.into(),
66 }))
67 }
68
69 pub(crate) fn crypto(source: impl Into<Source>) -> Self {
70 Error::new(Kind::Crypto(CryptoError {
71 source: source.into(),
72 }))
73 }
74
75 pub(crate) fn transaction(source: impl Into<Source>) -> Self {
76 Error::new(Kind::Transaction(TransactionError {
77 source: source.into(),
78 }))
79 }
80
81 pub(crate) fn coin_select(source: impl Into<Source>) -> Self {
82 Error::new(Kind::CoinSelect(CoinSelectError {
83 source: source.into(),
84 }))
85 }
86
87 pub(crate) fn address_format(source: impl Into<Source>) -> Self {
88 Error::new(Kind::ArkAddress(ArkAddressError {
89 source: source.into(),
90 }))
91 }
92}
93
94impl fmt::Display for Error {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 let mut err = self;
97 loop {
98 write!(f, "{}", err.inner.kind)?;
99 err = match err.inner.cause.as_ref() {
100 None => break,
101 Some(err) => err,
102 };
103 write!(f, ": ")?;
104 }
105 Ok(())
106 }
107}
108
109impl fmt::Display for Kind {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 match *self {
112 Kind::AdHoc(ref err) => err.fmt(f),
113 Kind::Crypto(ref err) => err.fmt(f),
114 Kind::Transaction(ref err) => err.fmt(f),
115 Kind::CoinSelect(ref err) => err.fmt(f),
116 Kind::ArkAddress(ref err) => err.fmt(f),
117 }
118 }
119}
120
121impl fmt::Display for AdHocError {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 self.source.fmt(f)
124 }
125}
126
127impl fmt::Display for CryptoError {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 self.source.fmt(f)
130 }
131}
132
133impl fmt::Display for TransactionError {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 self.source.fmt(f)
136 }
137}
138
139impl fmt::Display for CoinSelectError {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 self.source.fmt(f)
142 }
143}
144
145impl fmt::Display for ArkAddressError {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 self.source.fmt(f)
148 }
149}
150
151pub trait IntoError {
152 fn into_error(self) -> Error;
153}
154
155impl IntoError for Error {
156 fn into_error(self) -> Error {
157 self
158 }
159}
160
161impl IntoError for &'static str {
162 fn into_error(self) -> Error {
163 Error::ad_hoc(self)
164 }
165}
166
167impl IntoError for String {
168 fn into_error(self) -> Error {
169 Error::ad_hoc(self)
170 }
171}
172
173pub trait ErrorContext {
181 fn context(self, consequent: impl IntoError) -> Self;
190
191 fn with_context<E: IntoError>(self, consequent: impl FnOnce() -> E) -> Self;
201}
202
203impl ErrorContext for Error {
204 fn context(self, consequent: impl IntoError) -> Error {
205 let mut err = consequent.into_error();
206 assert!(
207 err.inner.cause.is_none(),
208 "cause of consequence must be `None`"
209 );
210
211 err.inner.cause = Some(self);
212 err
213 }
214
215 fn with_context<E: IntoError>(self, consequent: impl FnOnce() -> E) -> Error {
216 let mut err = consequent().into_error();
217 assert!(
218 err.inner.cause.is_none(),
219 "cause of consequence must be `None`"
220 );
221
222 err.inner.cause = Some(self);
223 err
224 }
225}
226
227impl<T> ErrorContext for Result<T, Error> {
228 fn context(self, consequent: impl IntoError) -> Result<T, Error> {
229 self.map_err(|err| err.context(consequent))
230 }
231
232 fn with_context<E: IntoError>(self, consequent: impl FnOnce() -> E) -> Result<T, Error> {
233 self.map_err(|err| err.with_context(consequent))
234 }
235}
236
237impl StdError for Error {}