1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//! Remotable errors.

use crate::RecvError;
use mesh_protobuf::EncodeAs;
use mesh_protobuf::Protobuf;
use std::fmt;
use std::fmt::Display;
use thiserror::Error;

/// An error that can be remoted across a mesh channel.
///
/// This erases the error's type, but preserves the source error chain when sent
/// between processes.
#[derive(Protobuf)]
pub struct RemoteError(EncodeAs<BoxedError, EncodedError>);

type BoxedError = Box<dyn std::error::Error + Send + Sync>;

impl RemoteError {
    /// Returns a new remote error wrapping `error` (including the error's
    /// source).
    pub fn new<T: Into<BoxedError>>(error: T) -> Self {
        Self(error.into().into())
    }
}

impl Display for RemoteError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl fmt::Debug for RemoteError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl std::error::Error for RemoteError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.0.source()
    }
}

/// An error encoded for serialization as a mesh message.
#[derive(Protobuf)]
struct EncodedError {
    errors: Vec<String>,
}

impl From<EncodedError> for BoxedError {
    fn from(error: EncodedError) -> Self {
        Box::new(DecodedError::from(error))
    }
}

impl From<BoxedError> for EncodedError {
    fn from(error: BoxedError) -> Self {
        let mut errors = Vec::new();
        let mut error = error.as_ref() as &dyn std::error::Error;
        loop {
            errors.push(error.to_string());
            if let Some(source) = error.source() {
                error = source;
            } else {
                break;
            }
        }
        Self { errors }
    }
}

/// An error decoded from an [`EncodedError`].
///
/// This is a distinct type so that we can implement
/// [`std::error::Error::source`] for it.
#[derive(Debug)]
struct DecodedError {
    source: Option<Box<DecodedError>>,
    error: String,
}

impl From<EncodedError> for DecodedError {
    fn from(value: EncodedError) -> Self {
        let mut errors = value.errors;
        let last_error = errors.pop().unwrap_or("no error information".to_string());
        let mut decoded = DecodedError {
            source: None,
            error: last_error,
        };
        for error in errors.into_iter().rev() {
            decoded = DecodedError {
                source: Some(Box::new(decoded)),
                error,
            };
        }
        decoded
    }
}

impl Display for DecodedError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.error)
    }
}

impl std::error::Error for DecodedError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.source.as_ref().map(|s| s as _)
    }
}

/// Alias for a [`Result`] with a [`RemoteError`] error.
pub type RemoteResult<T> = Result<T, RemoteError>;

/// An error from an RPC call, via
/// [`RpcSend::call_failable`](super::rpc::RpcSend::call_failable).
#[derive(Debug, Error)]
pub enum RpcError<E = RemoteError> {
    #[error(transparent)]
    Call(E),
    #[error(transparent)]
    Channel(RecvError),
}

/// Extension trait to [`Result`] for folding `Result<Result<T, E>, RecvError>`
/// to `RpcError`.
pub trait RemoteResultExt {
    type Flattened;

    /// Flattens the result into `RpcError`.
    fn flatten(self) -> Self::Flattened;
}

impl<T, E> RemoteResultExt for Result<Result<T, E>, RecvError> {
    type Flattened = Result<T, RpcError<E>>;

    fn flatten(self) -> Self::Flattened {
        match self {
            Ok(Ok(t)) => Ok(t),
            Ok(Err(e)) => Err(RpcError::Call(e)),
            Err(e) => Err(RpcError::Channel(e)),
        }
    }
}