Skip to main content

ferroui_remote_protocol/
error.rs

1//! The errors of the library: the exceptions the upstream code throws or
2//! lets through, as one value that can be handed to the exception event of a
3//! connection and to every handler subscribed to it.
4
5use std::fmt;
6use std::io;
7use std::sync::Arc;
8
9use crate::metsys_bson::BsonException;
10
11/// What a serializer, a resolver or a transport reports. Each variant is the
12/// exception of the same name in the upstream code.
13#[derive(Clone, Debug)]
14pub enum Error {
15    /// `BsonException`: what the BSON serializer itself rejects.
16    Bson(BsonException),
17    /// `EndOfStreamException`: the document or the stream ended inside a
18    /// value.
19    EndOfStream,
20    /// `InvalidOperationException`.
21    InvalidOperation(String),
22    /// `InvalidCastException`: a deserialized value is not of the type of
23    /// the property it belongs to.
24    InvalidCast(String),
25    /// `KeyNotFoundException`: an identifier or a type the resolver does not
26    /// know, or an element type the reader has no type for.
27    KeyNotFound(String),
28    /// `ArgumentException` and `ArgumentOutOfRangeException`.
29    Argument(String),
30    /// `OverflowException`.
31    Overflow(String),
32    /// `FormatException`.
33    Format(String),
34    /// `NullReferenceException`.
35    NullReference,
36    /// `IOException` and `SocketException`: what a stream or a socket
37    /// reported.
38    Io(Arc<io::Error>),
39    /// A handler of an event panicked: the port's form of an exception
40    /// thrown by a handler, with the message of the panic.
41    Handler(String),
42}
43
44impl fmt::Display for Error {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        match self {
47            Error::Bson(e) => e.fmt(f),
48            Error::EndOfStream => f.write_str("Unable to read beyond the end of the stream."),
49            Error::InvalidOperation(message)
50            | Error::InvalidCast(message)
51            | Error::KeyNotFound(message)
52            | Error::Argument(message)
53            | Error::Overflow(message)
54            | Error::Format(message)
55            | Error::Handler(message) => f.write_str(message),
56            Error::NullReference => f.write_str("Object reference not set to an instance of an object."),
57            Error::Io(e) => e.fmt(f),
58        }
59    }
60}
61
62impl std::error::Error for Error {
63    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
64        match self {
65            Error::Bson(e) => Some(e),
66            Error::Io(e) => Some(&**e),
67            _ => None,
68        }
69    }
70}
71
72impl From<BsonException> for Error {
73    fn from(e: BsonException) -> Self {
74        Error::Bson(e)
75    }
76}
77
78impl From<io::Error> for Error {
79    fn from(e: io::Error) -> Self {
80        if e.kind() == io::ErrorKind::UnexpectedEof {
81            Error::EndOfStream
82        } else {
83            Error::Io(Arc::new(e))
84        }
85    }
86}
87
88/// Runs a handler and turns a panic of it into [`Error::Handler`]: the `try`
89/// and `catch` around a delegate invocation in the upstream code.
90pub(crate) fn catch_handler(f: impl FnOnce()) -> Result<(), Error> {
91    std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).map_err(|payload| {
92        let message = if let Some(text) = payload.downcast_ref::<&str>() {
93            (*text).to_string()
94        } else if let Some(text) = payload.downcast_ref::<String>() {
95            text.clone()
96        } else {
97            "A handler panicked.".to_string()
98        };
99        Error::Handler(message)
100    })
101}