1use bytes::Bytes;
4
5pub type Result<T, E = Error> = std::result::Result<T, E>;
7
8#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12 #[error(transparent)]
14 Http(#[from] CanopyHttpError),
15
16 #[error("decoding the response of {path}: {source}")]
18 Decode {
19 path: String,
21 source: serde_json::Error,
23 },
24
25 #[error("encoding the request body for {path}: {source}")]
27 Encode {
28 path: String,
30 source: serde_json::Error,
32 },
33
34 #[error("building the request for {path}: {source}")]
36 Request {
37 path: String,
39 source: http::Error,
41 },
42
43 #[error("compressing the request body for {path}: {source}")]
45 Compress {
46 path: String,
48 source: std::io::Error,
50 },
51
52 #[error("reaching canopy: {0}")]
56 Transport(#[source] Box<dyn std::error::Error + Send + Sync>),
57}
58
59impl Error {
60 pub fn transport<E: std::error::Error + Send + Sync + 'static>(err: E) -> Self {
62 Self::Transport(Box::new(err))
63 }
64
65 pub fn http(&self) -> Option<&CanopyHttpError> {
70 match self {
71 Self::Http(err) => Some(err),
72 _ => None,
73 }
74 }
75
76 pub fn status(&self) -> Option<http::StatusCode> {
78 self.http().map(|err| err.status)
79 }
80}
81
82#[derive(Debug, thiserror::Error)]
87#[error("canopy returned {status} for {path}")]
88pub struct CanopyHttpError {
89 pub status: http::StatusCode,
91 pub path: String,
93 pub body: Bytes,
95}
96
97impl CanopyHttpError {
98 pub fn body_text(&self) -> std::borrow::Cow<'_, str> {
100 String::from_utf8_lossy(&self.body)
101 }
102}