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.try_into().expect("Could not convert into a valid `StatusCode`");
44 Error::new(status, error)
45 })
46 }
47
48 fn with_status<S, F>(self, f: F) -> Result<T, Error>
58 where
59 S: TryInto<StatusCode>,
60 S::Error: Debug,
61 F: FnOnce() -> S,
62 {
63 self.map_err(|error| {
64 let status = f().try_into().expect("Could not convert into a valid `StatusCode`");
65 Error::new(status, error)
66 })
67 }
68}
69
70impl<T> Status<T, Error> for Result<T, Error> {
71 fn status<S>(self, status: S) -> Result<T, Error>
80 where
81 S: TryInto<StatusCode>,
82 S::Error: Debug,
83 {
84 self.map_err(|mut error| {
85 error.set_status(status);
86 error
87 })
88 }
89
90 fn with_status<S, F>(self, f: F) -> Result<T, Error>
100 where
101 S: TryInto<StatusCode>,
102 S::Error: Debug,
103 F: FnOnce() -> S,
104 {
105 self.map_err(|mut error| {
106 error.set_status(f());
107 error
108 })
109 }
110}
111
112impl<T> Status<T, Infallible> for Option<T> {
113 fn status<S>(self, status: S) -> Result<T, Error>
122 where
123 S: TryInto<StatusCode>,
124 S::Error: Debug,
125 {
126 self.ok_or_else(|| {
127 let status = status.try_into().expect("Could not convert into a valid `StatusCode`");
128 Error::from_str(status, "NoneError")
129 })
130 }
131
132 fn with_status<S, F>(self, f: F) -> Result<T, Error>
142 where
143 S: TryInto<StatusCode>,
144 S::Error: Debug,
145 F: FnOnce() -> S,
146 {
147 self.ok_or_else(|| {
148 let status = f().try_into().expect("Could not convert into a valid `StatusCode`");
149 Error::from_str(status, "NoneError")
150 })
151 }
152}
153
154pub(crate) mod private {
155 pub trait Sealed {}
156
157 impl<T, E> Sealed for Result<T, E> {}
158 impl<T> Sealed for Option<T> {}
159}
160
161#[cfg(test)]
162mod test {
163 use super::Status;
164
165 #[test]
166 fn construct_shorthand_with_valid_status_code() {
167 Some(()).status(200).unwrap();
168 }
169
170 #[test]
171 #[should_panic(expected = "Could not convert into a valid `StatusCode`")]
172 fn construct_shorthand_with_invalid_status_code() {
173 let res: Result<(), std::io::Error> = Err(std::io::Error::new(std::io::ErrorKind::Other, "oh no!"));
174 res.status(600).unwrap();
175 }
176}