//! This module contains types for all kinds of errors that can occur when //! converting between http requests / responses and ruma's representation of //! matrix API requests / responses. use std::fmt::{self, Display, Formatter}; // FIXME when `!` becomes stable use it /// Default `ResponseError` for `ruma_api!` macro #[derive(Clone, Copy, Debug)] pub struct Void; impl crate::EndpointError for Void { fn try_from_response( response: http::Response>, ) -> Result { Err(ResponseDeserializationError::from_response(response)) } } impl Display for Void { fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { match self {} } } impl std::error::Error for Void {} /// An error when converting one of ruma's endpoint-specific request or response /// types to the corresponding http type. #[derive(Debug)] pub struct IntoHttpError(InnerIntoHttpError); impl IntoHttpError { // For usage in macros #[doc(hidden)] pub fn needs_authentication() -> Self { Self(InnerIntoHttpError::NeedsAuthentication) } } #[doc(hidden)] impl From for IntoHttpError { fn from(err: serde_json::Error) -> Self { Self(InnerIntoHttpError::Json(err)) } } #[doc(hidden)] impl From for IntoHttpError { fn from(err: ruma_serde::urlencoded::ser::Error) -> Self { Self(InnerIntoHttpError::Query(err)) } } #[doc(hidden)] impl From for IntoHttpError { fn from(err: http::header::InvalidHeaderValue) -> Self { Self(InnerIntoHttpError::Header(err)) } } #[doc(hidden)] impl From for IntoHttpError { fn from(err: http::Error) -> Self { Self(InnerIntoHttpError::Http(err)) } } impl Display for IntoHttpError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match &self.0 { InnerIntoHttpError::NeedsAuthentication => write!( f, "This endpoint has to be converted to http::Request using \ try_into_authenticated_http_request" ), InnerIntoHttpError::Json(err) => write!(f, "JSON serialization failed: {}", err), InnerIntoHttpError::Query(err) => { write!(f, "Query parameter serialization failed: {}", err) } InnerIntoHttpError::Header(err) => write!(f, "Header serialization failed: {}", err), InnerIntoHttpError::Http(err) => write!(f, "HTTP request construction failed: {}", err), } } } impl std::error::Error for IntoHttpError {} /// An error when converting a http request to one of ruma's endpoint-specific /// request types. #[derive(Debug)] #[non_exhaustive] pub enum FromHttpRequestError { /// Deserialization failed Deserialization(RequestDeserializationError), } impl Display for FromHttpRequestError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Deserialization(err) => write!(f, "deserialization failed: {}", err), } } } impl From for FromHttpRequestError { fn from(err: RequestDeserializationError) -> Self { Self::Deserialization(err) } } impl std::error::Error for FromHttpRequestError {} /// An error that occurred when trying to deserialize a request. #[derive(Debug)] pub struct RequestDeserializationError { inner: DeserializationError, http_request: http::Request>, } impl RequestDeserializationError { /// This method is public so it is accessible from `ruma_api!` generated /// code. It is not considered part of ruma-api's public API. #[doc(hidden)] pub fn new( inner: impl Into, http_request: http::Request>, ) -> Self { Self { inner: inner.into(), http_request } } } impl Display for RequestDeserializationError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.inner, f) } } impl std::error::Error for RequestDeserializationError {} /// An error when converting a http response to one of ruma's endpoint-specific /// response types. #[derive(Debug)] #[non_exhaustive] pub enum FromHttpResponseError { /// Deserialization failed Deserialization(ResponseDeserializationError), /// The server returned a non-success status Http(ServerError), } impl Display for FromHttpResponseError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Deserialization(err) => write!(f, "deserialization failed: {}", err), Self::Http(err) => write!(f, "the server returned an error: {}", err), } } } impl From> for FromHttpResponseError { fn from(err: ServerError) -> Self { Self::Http(err) } } impl From for FromHttpResponseError { fn from(err: ResponseDeserializationError) -> Self { Self::Deserialization(err) } } impl std::error::Error for FromHttpResponseError {} /// An error that occurred when trying to deserialize a response. #[derive(Debug)] pub struct ResponseDeserializationError { inner: Option, http_response: http::Response>, } impl ResponseDeserializationError { /// This method is public so it is accessible from `ruma_api!` generated /// code. It is not considered part of ruma-api's public API. #[doc(hidden)] pub fn new( inner: impl Into, http_response: http::Response>, ) -> Self { Self { inner: Some(inner.into()), http_response } } /// This method is public so it is accessible from `ruma_api!` generated /// code. It is not considered part of ruma-api's public API. /// Creates an Error from a `http::Response`. #[doc(hidden)] pub fn from_response(http_response: http::Response>) -> Self { Self { http_response, inner: None } } } impl Display for ResponseDeserializationError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { if let Some(ref inner) = self.inner { Display::fmt(inner, f) } else { Display::fmt("deserialization error, no error specified", f) } } } impl std::error::Error for ResponseDeserializationError {} /// An error was reported by the server (HTTP status code 4xx or 5xx) #[derive(Debug)] pub enum ServerError { /// An error that is expected to happen under certain circumstances and /// that has a well-defined structure Known(E), /// An error of unexpected type of structure Unknown(ResponseDeserializationError), } impl Display for ServerError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { ServerError::Known(e) => Display::fmt(e, f), ServerError::Unknown(res_err) => Display::fmt(res_err, f), } } } impl std::error::Error for ServerError {} #[derive(Debug)] enum InnerIntoHttpError { NeedsAuthentication, Json(serde_json::Error), Query(ruma_serde::urlencoded::ser::Error), Header(http::header::InvalidHeaderValue), Http(http::Error), } /// This type is public so it is accessible from `ruma_api!` generated code. /// It is not considered part of ruma-api's public API. #[doc(hidden)] #[derive(Debug)] pub enum DeserializationError { Utf8(std::str::Utf8Error), Json(serde_json::Error), Query(ruma_serde::urlencoded::de::Error), Ident(ruma_identifiers::Error), // String <> Enum conversion failed. This can currently only happen in path // segment deserialization Strum(strum::ParseError), Header(http::header::ToStrError), } impl Display for DeserializationError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { DeserializationError::Utf8(err) => Display::fmt(err, f), DeserializationError::Json(err) => Display::fmt(err, f), DeserializationError::Query(err) => Display::fmt(err, f), DeserializationError::Ident(err) => Display::fmt(err, f), DeserializationError::Strum(err) => Display::fmt(err, f), DeserializationError::Header(err) => Display::fmt(err, f), } } } #[doc(hidden)] impl From for DeserializationError { fn from(err: http::header::ToStrError) -> Self { Self::Header(err) } } #[doc(hidden)] impl From for DeserializationError { fn from(err: std::str::Utf8Error) -> Self { Self::Utf8(err) } } #[doc(hidden)] impl From for DeserializationError { fn from(err: serde_json::Error) -> Self { Self::Json(err) } } #[doc(hidden)] impl From for DeserializationError { fn from(err: ruma_serde::urlencoded::de::Error) -> Self { Self::Query(err) } } #[doc(hidden)] impl From for DeserializationError { fn from(err: ruma_identifiers::Error) -> Self { Self::Ident(err) } } #[doc(hidden)] impl From for DeserializationError { fn from(err: strum::ParseError) -> Self { Self::Strum(err) } } #[doc(hidden)] impl From for DeserializationError { fn from(err: std::convert::Infallible) -> Self { match err {} } }