lumina_node_wasm/
error.rs1use std::fmt::{self, Display};
4
5use serde::{Deserialize, Serialize};
6use wasm_bindgen::convert::IntoWasmAbi;
7use wasm_bindgen::describe::WasmDescribe;
8use wasm_bindgen::{JsCast, JsValue};
9
10pub type Result<T, E = Error> = std::result::Result<T, E>;
12
13#[derive(Debug, Serialize, Deserialize)]
15pub struct Error(#[serde(with = "serde_wasm_bindgen::preserve")] JsValue);
16
17impl Error {
18 pub fn new(msg: &str) -> Error {
20 Error(js_sys::Error::new(msg).into())
21 }
22
23 pub fn from_js_value<T>(value: T) -> Error
25 where
26 T: Into<JsValue>,
27 {
28 Error(value.into())
29 }
30
31 pub fn from_display<T>(value: T) -> Error
36 where
37 T: Display,
38 {
39 Error::new(&value.to_string())
40 }
41
42 pub fn context<C>(self, context: C) -> Error
44 where
45 C: Display,
46 {
47 let e = js_sys::Error::new(&context.to_string());
48 e.set_cause(&self.0);
49 Error(e.into())
50 }
51}
52
53impl Display for Error {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
55 let Some(error) = self.0.dyn_ref::<js_sys::Error>() else {
56 return write!(f, "{:?}", self.0.as_string());
57 };
58
59 write!(f, "{} ({})", error.name(), error.message())?;
60
61 let mut cause = error.cause();
62 loop {
63 if let Some(error) = cause.dyn_ref::<js_sys::Error>() {
64 write!(f, "\n{} ({})", error.name(), error.message())?;
65 cause = error.cause();
66 } else {
67 write!(f, "\n{:?}", cause.as_string())?;
68 break;
69 }
70 }
71
72 Ok(())
73 }
74}
75
76impl WasmDescribe for Error {
80 fn describe() {
81 JsValue::describe()
82 }
83}
84
85impl IntoWasmAbi for Error {
89 type Abi = <JsValue as IntoWasmAbi>::Abi;
90
91 fn into_abi(self) -> Self::Abi {
92 self.0.into_abi()
93 }
94}
95
96impl From<Error> for JsValue {
97 fn from(error: Error) -> JsValue {
98 error.0
99 }
100}
101
102macro_rules! from_js_value {
106 ($($t:ty,)*) => ($(
107 impl From<$t> for Error {
108 fn from(value: $t) -> Error {
109 Error::from_js_value(value)
110 }
111 }
112 )*)
113}
114
115macro_rules! from_display {
119 ($($t:ty,)*) => ($(
120 impl From<$t> for Error {
121 fn from(value: $t) -> Error {
122 Error::from_display(value)
123 }
124 }
125 )*)
126}
127
128from_js_value! {
129 JsValue,
130 serde_wasm_bindgen::Error,
131 wasm_bindgen::JsError,
132}
133
134from_display! {
135 blockstore::Error,
136 tendermint::error::Error,
137 libp2p::identity::ParseError,
138 libp2p::multiaddr::Error,
139 libp2p::identity::DecodingError,
140 celestia_types::Error,
141 lumina_node::node::NodeError,
142 lumina_node::store::StoreError,
143 crate::worker::WorkerError,
144 tokio::sync::oneshot::error::RecvError,
145}
146
147impl<T> From<tokio::sync::mpsc::error::SendError<T>> for Error {
148 fn from(value: tokio::sync::mpsc::error::SendError<T>) -> Error {
149 Error::from_display(value)
150 }
151}
152
153impl<T> From<tokio::sync::broadcast::error::SendError<T>> for Error {
154 fn from(value: tokio::sync::broadcast::error::SendError<T>) -> Error {
155 Error::from_display(value)
156 }
157}
158
159pub trait Context<T> {
161 fn context<C>(self, context: C) -> Result<T, Error>
163 where
164 C: Display;
165
166 fn with_context<F, C>(self, context_fn: F) -> Result<T, Error>
168 where
169 C: Display,
170 F: FnOnce() -> C,
171 Self: Sized,
172 {
173 self.context(context_fn())
174 }
175}
176
177impl<T, E> Context<T> for Result<T, E>
178where
179 E: Into<Error>,
180{
181 fn context<C>(self, context: C) -> Result<T, Error>
182 where
183 C: Display,
184 {
185 self.map_err(|e| e.into().context(context))
186 }
187}
188
189impl<T> Context<T> for Option<T> {
190 fn context<C>(self, context: C) -> Result<T, Error>
191 where
192 C: Display,
193 {
194 self.ok_or_else(|| Error::new(&context.to_string()))
195 }
196}