Skip to main content

rmcp/
error.rs

1use std::{borrow::Cow, fmt::Display};
2
3pub use crate::model::ErrorData;
4impl Display for ErrorData {
5    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6        write!(f, "{}: {}", self.code.0, self.message)?;
7        if let Some(data) = &self.data {
8            write!(f, "({})", data)?;
9        }
10        Ok(())
11    }
12}
13
14impl std::error::Error for ErrorData {}
15
16#[cfg(all(feature = "auth", any(feature = "client", feature = "server")))]
17pub(crate) struct ErrorChain<'a>(pub(crate) &'a (dyn std::error::Error + 'static));
18
19#[cfg(all(feature = "auth", any(feature = "client", feature = "server")))]
20impl Display for ErrorChain<'_> {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        write!(f, "{}", self.0)?;
23        for source in std::iter::successors(self.0.source(), |source| source.source()) {
24            write!(f, "\n  Caused by: {source}")?;
25        }
26        Ok(())
27    }
28}
29
30/// This is an unified error type for the errors could be returned by the service.
31#[derive(Debug, thiserror::Error)]
32#[allow(clippy::large_enum_variant)]
33#[non_exhaustive]
34pub enum RmcpError {
35    #[cfg(any(feature = "client", feature = "server"))]
36    #[error("Service error: {0}")]
37    Service(#[from] crate::ServiceError),
38    #[cfg(feature = "client")]
39    #[error("Client initialization error: {0}")]
40    ClientInitialize(#[from] crate::service::ClientInitializeError),
41    #[cfg(feature = "server")]
42    #[error("Server initialization error: {0}")]
43    ServerInitialize(#[from] crate::service::ServerInitializeError),
44    #[error("Runtime error: {0}")]
45    Runtime(#[from] tokio::task::JoinError),
46    #[error("Transport creation error: {error}")]
47    // TODO: Maybe we can introduce something like `TryIntoTransport` to auto wrap transport type,
48    // but it could be an breaking change, so we could do it in the future.
49    TransportCreation {
50        into_transport_type_name: Cow<'static, str>,
51        into_transport_type_id: std::any::TypeId,
52        #[source]
53        error: Box<dyn std::error::Error + Send + Sync>,
54    },
55    // and cancellation shouldn't be an error?
56
57    // TODO: add more error variants as needed
58    #[error("Task error: {0}")]
59    TaskError(String),
60}
61
62impl RmcpError {
63    pub fn transport_creation<T: 'static>(
64        error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
65    ) -> Self {
66        RmcpError::TransportCreation {
67            into_transport_type_id: std::any::TypeId::of::<T>(),
68            into_transport_type_name: std::any::type_name::<T>().into(),
69            error: error.into(),
70        }
71    }
72}