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 ArkServer(ArkServerError),
23 Core(CoreError),
25 CoinSelect(CoinSelectError),
27 Wallet(WalletError),
29 Consumer(ConsumerError),
31}
32
33#[derive(Debug)]
34struct AdHocError {
35 source: Source,
36}
37
38#[derive(Debug)]
39struct ArkServerError {
40 source: Source,
41}
42
43#[derive(Debug)]
44struct CoreError {
45 source: ark_core::Error,
46}
47
48#[derive(Debug)]
49struct CoinSelectError {
50 source: Source,
51}
52
53#[derive(Debug)]
54struct WalletError {
55 source: Source,
56}
57
58#[derive(Debug)]
59struct ConsumerError {
60 source: Source,
61}
62
63impl Error {
64 fn new(kind: Kind) -> Self {
65 Self {
66 inner: Box::new(ErrorImpl { kind, cause: None }),
67 }
68 }
69
70 pub(crate) fn ad_hoc(source: impl Into<Source>) -> Self {
71 Error::new(Kind::AdHoc(AdHocError {
72 source: source.into(),
73 }))
74 }
75
76 pub(crate) fn ark_server(source: impl Into<Source>) -> Self {
77 Error::new(Kind::ArkServer(ArkServerError {
78 source: source.into(),
79 }))
80 }
81
82 pub(crate) fn coin_select(source: impl Into<Source>) -> Self {
83 Error::new(Kind::CoinSelect(CoinSelectError {
84 source: source.into(),
85 }))
86 }
87
88 pub fn wallet(source: impl Into<Source>) -> Self {
89 Error::new(Kind::Wallet(WalletError {
90 source: source.into(),
91 }))
92 }
93
94 pub fn consumer(source: impl Into<Source>) -> Self {
95 Error::new(Kind::Consumer(ConsumerError {
96 source: source.into(),
97 }))
98 }
99}
100
101impl fmt::Display for Error {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 let mut err = self;
104 loop {
105 write!(f, "{}", err.inner.kind)?;
106 err = match err.inner.cause.as_ref() {
107 None => break,
108 Some(err) => err,
109 };
110 write!(f, ": ")?;
111 }
112 Ok(())
113 }
114}
115
116impl fmt::Display for Kind {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 match *self {
119 Kind::AdHoc(ref err) => err.fmt(f),
120 Kind::ArkServer(ref err) => err.fmt(f),
121 Kind::Core(ref err) => err.fmt(f),
122 Kind::CoinSelect(ref err) => err.fmt(f),
123 Kind::Wallet(ref err) => err.fmt(f),
124 Kind::Consumer(ref err) => err.fmt(f),
125 }
126 }
127}
128
129impl fmt::Display for AdHocError {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 self.source.fmt(f)
132 }
133}
134
135impl fmt::Display for ArkServerError {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 self.source.fmt(f)
138 }
139}
140
141impl fmt::Display for CoreError {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 self.source.fmt(f)
144 }
145}
146
147impl fmt::Display for CoinSelectError {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 self.source.fmt(f)
150 }
151}
152
153impl fmt::Display for WalletError {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 self.source.fmt(f)
156 }
157}
158
159impl fmt::Display for ConsumerError {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 self.source.fmt(f)
162 }
163}
164
165impl From<ark_core::Error> for Error {
166 fn from(value: ark_core::Error) -> Self {
167 Self::new(Kind::Core(CoreError { source: value }))
168 }
169}
170
171pub trait IntoError {
172 fn into_error(self) -> Error;
173}
174
175impl IntoError for Error {
176 fn into_error(self) -> Error {
177 self
178 }
179}
180
181impl IntoError for &'static str {
182 fn into_error(self) -> Error {
183 Error::ad_hoc(self)
184 }
185}
186
187impl IntoError for String {
188 fn into_error(self) -> Error {
189 Error::ad_hoc(self)
190 }
191}
192
193pub trait ErrorContext {
201 fn context(self, consequent: impl IntoError) -> Self;
210
211 fn with_context<E: IntoError>(self, consequent: impl FnOnce() -> E) -> Self;
221}
222
223impl ErrorContext for Error {
224 fn context(self, consequent: impl IntoError) -> Error {
225 let mut err = consequent.into_error();
226 assert!(
227 err.inner.cause.is_none(),
228 "cause of consequence must be `None`"
229 );
230
231 err.inner.cause = Some(self);
232 err
233 }
234
235 fn with_context<E: IntoError>(self, consequent: impl FnOnce() -> E) -> Error {
236 let mut err = consequent().into_error();
237 assert!(
238 err.inner.cause.is_none(),
239 "cause of consequence must be `None`"
240 );
241
242 err.inner.cause = Some(self);
243 err
244 }
245}
246
247impl<T> ErrorContext for Result<T, Error> {
248 fn context(self, consequent: impl IntoError) -> Result<T, Error> {
249 self.map_err(|err| err.context(consequent))
250 }
251
252 fn with_context<E: IntoError>(self, consequent: impl FnOnce() -> E) -> Result<T, Error> {
253 self.map_err(|err| err.with_context(consequent))
254 }
255}
256
257impl From<ark_grpc::Error> for Error {
258 fn from(value: ark_grpc::Error) -> Self {
259 Self::ark_server(value)
260 }
261}
262
263impl StdError for Error {
264 fn source(&self) -> Option<&(dyn StdError + 'static)> {
265 self.inner
266 .cause
267 .as_ref()
268 .map(|e| e as &(dyn StdError + 'static))
269 }
270}