1use std::fmt;
2use std::str::Utf8Error;
3
4use hyper::body::Bytes;
5
6type Source = Box<dyn std::error::Error + Send + Sync>;
7
8pub 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 pub fn is_loading(&self) -> bool {
31 matches!(self.inner.kind, BodyErrorKind::Loading)
32 }
33
34 pub fn is_decode(&self) -> bool {
36 matches!(self.inner.kind, BodyErrorKind::Decode { .. })
37 }
38
39 pub fn is_invalid_utf8(&self) -> bool {
41 matches!(self.inner.kind, BodyErrorKind::InvalidUtf8 { .. })
42 }
43
44 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}