1use crate::{Error, StatusCode};
2use core::convert::{Infallible, TryInto};
3use std::error::Error as StdError;
4use std::fmt::Debug;
5
6pub trait Status<T, E>: private::Sealed {
10 fn status<S>(self, status: S) -> Result<T, Error>
12 where
13 S: TryInto<StatusCode>,
14 S::Error: Debug;
15
16 fn with_status<S, F>(self, f: F) -> Result<T, Error>
19 where
20 S: TryInto<StatusCode>,
21 S::Error: Debug,
22 F: FnOnce() -> S;
23}
24
25impl<T, E> Status<T, E> for Result<T, E>
26where
27 E: StdError + Send + Sync + 'static,
28{
29 fn status<S>(self, status: S) -> Result<T, Error>
38 where
39 S: TryInto<StatusCode>,
40 S::Error: Debug,
41 {
42 self.map_err(|error| {
43 let status = status
44 .try_into()
45 .expect("Could not convert into a valid `StatusCode`");
46 Error::new(status, error)
47 })
48 }
49
50 fn with_status<S, F>(self, f: F) -> Result<T, Error>
60 where
61 S: TryInto<StatusCode>,
62 S::Error: Debug,
63 F: FnOnce() -> S,
64 {
65 self.map_err(|error| {
66 let status = f()
67 .try_into()
68 .expect("Could not convert into a valid `StatusCode`");
69 Error::new(status, error)
70 })
71 }
72}
73
74impl<T> Status<T, Error> for Result<T, Error> {
75 fn status<S>(self, status: S) -> Result<T, Error>
84 where
85 S: TryInto<StatusCode>,
86 S::Error: Debug,
87 {
88 self.map_err(|mut error| {
89 error.set_status(status);
90 error
91 })
92 }
93
94 fn with_status<S, F>(self, f: F) -> Result<T, Error>
104 where
105 S: TryInto<StatusCode>,
106 S::Error: Debug,
107 F: FnOnce() -> S,
108 {
109 self.map_err(|mut error| {
110 error.set_status(f());
111 error
112 })
113 }
114}
115
116impl<T> Status<T, Infallible> for Option<T> {
117 fn status<S>(self, status: S) -> Result<T, Error>
126 where
127 S: TryInto<StatusCode>,
128 S::Error: Debug,
129 {
130 self.ok_or_else(|| {
131 let status = status
132 .try_into()
133 .expect("Could not convert into a valid `StatusCode`");
134 Error::from_str(status, "NoneError")
135 })
136 }
137
138 fn with_status<S, F>(self, f: F) -> Result<T, Error>
148 where
149 S: TryInto<StatusCode>,
150 S::Error: Debug,
151 F: FnOnce() -> S,
152 {
153 self.ok_or_else(|| {
154 let status = f()
155 .try_into()
156 .expect("Could not convert into a valid `StatusCode`");
157 Error::from_str(status, "NoneError")
158 })
159 }
160}
161
162pub(crate) mod private {
163 pub trait Sealed {}
164
165 impl<T, E> Sealed for Result<T, E> {}
166 impl<T> Sealed for Option<T> {}
167}
168
169#[cfg(test)]
170mod test {
171 use super::Status;
172
173 #[test]
174 fn construct_shorthand_with_valid_status_code() {
175 Some(()).status(200).unwrap();
176 }
177
178 #[test]
179 #[should_panic(expected = "Could not convert into a valid `StatusCode`")]
180 fn construct_shorthand_with_invalid_status_code() {
181 let res: Result<(), std::io::Error> =
182 Err(std::io::Error::other("oh no!"));
183 res.status(600).unwrap();
184 }
185}