modio/response/
error.rs

1use std::fmt;
2use std::str::Utf8Error;
3
4use hyper::body::Bytes;
5
6type Source = Box<dyn std::error::Error + Send + Sync>;
7
8/// Failure when processing a response body.
9pub struct BodyError {
10    inner: Box<ErrorImpl>,
11}
12
13impl BodyError {
14    #[inline]
15    pub(super) fn new(kind: BodyErrorKind, source: Option<Source>) -> Self {
16        Self {
17            inner: Box::new(ErrorImpl { kind, source }),
18        }
19    }
20
21    pub(crate) fn decode(bytes: Bytes, source: serde_json::Error) -> Self {
22        Self::new(BodyErrorKind::Decode { bytes }, Some(Box::new(source)))
23    }
24
25    pub(crate) fn invalid_utf8(bytes: Vec<u8>, source: Utf8Error) -> Self {
26        Self::new(BodyErrorKind::InvalidUtf8 { bytes }, Some(Box::new(source)))
27    }
28
29    /// Returns true if the body could not be loaded.
30    pub fn is_loading(&self) -> bool {
31        matches!(self.inner.kind, BodyErrorKind::Loading)
32    }
33
34    /// Returns true if the response body could not be deserialized.
35    pub fn is_decode(&self) -> bool {
36        matches!(self.inner.kind, BodyErrorKind::Decode { .. })
37    }
38
39    /// Returns true if the response body contains invalid utf8 data.
40    pub fn is_invalid_utf8(&self) -> bool {
41        matches!(self.inner.kind, BodyErrorKind::InvalidUtf8 { .. })
42    }
43
44    /// Returns a slice of `u8`s bytes that were attempted to deserialize or convert to a `String`.
45    pub fn as_bytes(&self) -> Option<&[u8]> {
46        match &self.inner.kind {
47            BodyErrorKind::Decode { bytes } => Some(bytes),
48            BodyErrorKind::InvalidUtf8 { bytes } => Some(bytes),
49            _ => None,
50        }
51    }
52}
53
54impl fmt::Debug for BodyError {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        let mut f = f.debug_struct("BodyError");
57        f.field("kind", &self.inner.kind);
58        if let Some(ref source) = self.inner.source {
59            f.field("source", source);
60        }
61        f.finish()
62    }
63}
64
65impl fmt::Display for BodyError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self.inner.kind {
68            BodyErrorKind::Loading => f.write_str("failed to retrieve response body"),
69            BodyErrorKind::Decode { .. } => f.write_str("failed to decode response body"),
70            BodyErrorKind::InvalidUtf8 { .. } => {
71                f.write_str("response body is not a valid utf8 string")
72            }
73        }
74    }
75}
76
77impl std::error::Error for BodyError {
78    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
79        self.inner.source.as_ref().map(|e| &**e as _)
80    }
81}
82
83struct ErrorImpl {
84    kind: BodyErrorKind,
85    source: Option<Source>,
86}
87
88#[derive(Debug)]
89#[non_exhaustive]
90pub(super) enum BodyErrorKind {
91    Loading,
92    Decode { bytes: Bytes },
93    InvalidUtf8 { bytes: Vec<u8> },
94}