opentitanlib/proxy/
errors.rs1use erased_serde::Serialize;
6
7#[doc(hidden)]
8pub use inventory::submit;
9
10#[doc(hidden)]
11pub struct SerializableErrorRegistration {
12 pub try_convert: fn(anyhow::Error) -> Result<SerializedError, anyhow::Error>,
13}
14inventory::collect!(SerializableErrorRegistration);
15
16#[typetag::serde(tag = "error_type")]
19pub trait SerializableError: Serialize + std::error::Error + std::fmt::Debug + Send + Sync {
20 fn as_anyhow_error(self: Box<Self>) -> anyhow::Error;
21}
22
23#[macro_export]
26macro_rules! impl_serializable_error {
27 ($t:ty) => {
28 const _: () = {
29 #[typetag::serde]
30 impl $crate::proxy::errors::SerializableError for $t {
31 fn as_anyhow_error(self: Box<$t>) -> anyhow::Error {
32 self.into()
33 }
34 }
35
36 $crate::proxy::errors::submit! {
37 $crate::proxy::errors::SerializableErrorRegistration {
38 try_convert: |err| {
39 if !err.is::<$t>() {
40 return Err(err);
41 }
42
43 let description = err.to_string();
44 let backtrace = format!("{:#?}", err.backtrace());
45 let downcast = err.downcast::<$t>().unwrap();
46 Ok($crate::proxy::errors::SerializedError {
47 description,
48 backtrace,
49 error: Some(Box::new(downcast)),
50 })
51 }
52 }
53 };
54 };
55 };
56}
57
58#[derive(serde::Serialize, serde::Deserialize, Debug)]
60pub struct SerializedError {
61 pub description: String,
62 pub backtrace: String,
63 pub error: Option<Box<dyn SerializableError>>,
64}
65
66impl From<SerializedError> for anyhow::Error {
68 fn from(ser: SerializedError) -> anyhow::Error {
69 let error = if let Some(error) = ser.error {
70 error.as_anyhow_error()
71 } else {
72 anyhow::Error::msg(ser.description)
73 };
74 if ser.backtrace == "<disabled>" {
75 error
76 } else {
77 error.context(format!("Server Error.\nRemote {}", ser.backtrace))
78 }
79 }
80}
81
82impl From<anyhow::Error> for SerializedError {
84 fn from(mut error: anyhow::Error) -> SerializedError {
85 for reg in inventory::iter::<SerializableErrorRegistration> {
86 match (reg.try_convert)(error) {
87 Ok(v) => return v,
88 Err(e) => error = e,
89 }
90 }
91
92 let description = error.to_string();
93 let backtrace = format!("{:#?}", error.backtrace());
94 SerializedError {
95 description,
96 backtrace,
97 error: None,
98 }
99 }
100}