1use mesh_protobuf::EncodeAs;
7use mesh_protobuf::Protobuf;
8use std::fmt;
9use std::fmt::Display;
10
11#[derive(Protobuf)]
16pub struct RemoteError(EncodeAs<BoxedError, EncodedError>);
17
18type BoxedError = Box<dyn std::error::Error + Send + Sync>;
19
20impl RemoteError {
21 pub fn new<T: Into<BoxedError>>(error: T) -> Self {
24 Self(error.into().into())
25 }
26}
27
28impl Display for RemoteError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 Display::fmt(&self.0, f)
31 }
32}
33
34impl fmt::Debug for RemoteError {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 fmt::Debug::fmt(&self.0, f)
37 }
38}
39
40impl std::error::Error for RemoteError {
41 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
42 self.0.source()
43 }
44}
45
46#[derive(Protobuf)]
48struct EncodedError {
49 errors: Vec<String>,
50}
51
52impl From<EncodedError> for BoxedError {
53 fn from(error: EncodedError) -> Self {
54 Box::new(DecodedError::from(error))
55 }
56}
57
58impl From<BoxedError> for EncodedError {
59 fn from(error: BoxedError) -> Self {
60 let mut errors = Vec::new();
61 let mut error = error.as_ref() as &dyn std::error::Error;
62 loop {
63 errors.push(error.to_string());
64 if let Some(source) = error.source() {
65 error = source;
66 } else {
67 break;
68 }
69 }
70 Self { errors }
71 }
72}
73
74#[derive(Debug)]
79struct DecodedError {
80 source: Option<Box<DecodedError>>,
81 error: String,
82}
83
84impl From<EncodedError> for DecodedError {
85 fn from(value: EncodedError) -> Self {
86 let mut errors = value.errors;
87 let last_error = errors.pop().unwrap_or("no error information".to_string());
88 let mut decoded = DecodedError {
89 source: None,
90 error: last_error,
91 };
92 for error in errors.into_iter().rev() {
93 decoded = DecodedError {
94 source: Some(Box::new(decoded)),
95 error,
96 };
97 }
98 decoded
99 }
100}
101
102impl Display for DecodedError {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 f.write_str(&self.error)
105 }
106}
107
108impl std::error::Error for DecodedError {
109 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
110 self.source.as_ref().map(|s| s as _)
111 }
112}
113
114pub type RemoteResult<T> = Result<T, RemoteError>;