1use hyper::{Body, Response, StatusCode, header};
4use mime_guess::from_path as get_mine_from_path;
5use serde::Serialize;
6use std::fs::read_to_string as read_file;
7
8pub trait IntoResponse {
10 fn into_response(self) -> Response<Body>;
11}
12
13impl IntoResponse for &'static str {
15 fn into_response(self) -> Response<Body> {
16 Response::builder()
17 .header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
18 .body(Body::from(self))
19 .unwrap()
20 }
21}
22
23impl IntoResponse for String {
25 fn into_response(self) -> Response<Body> {
26 Response::builder()
27 .header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
28 .body(Body::from(self))
29 .unwrap()
30 }
31}
32
33impl IntoResponse for Vec<u8> {
35 fn into_response(self) -> Response<Body> {
36 Response::builder().body(Body::from(self)).unwrap()
37 }
38}
39
40impl IntoResponse for () {
42 fn into_response(self) -> Response<Body> {
43 Response::builder()
44 .status(StatusCode::NO_CONTENT)
45 .body(Body::empty())
46 .unwrap()
47 }
48}
49
50impl<const N: usize> IntoResponse for ([(header::HeaderName, &'static str); N], String) {
52 fn into_response(self) -> Response<Body> {
53 let (headers, body) = self;
54 let mut builder = Response::builder();
55
56 for (name, value) in headers {
57 builder = builder.header(name, value);
58 }
59
60 builder.body(Body::from(body)).unwrap()
61 }
62}
63
64impl<const N: usize> IntoResponse for ([(header::HeaderName, &'static str); N], StatusCode, String) {
66 fn into_response(self) -> Response<Body> {
67 let (headers, status, body) = self;
68 let mut builder = Response::builder().status(status);
69
70 for (name, value) in headers {
71 builder = builder.header(name, value);
72 }
73
74 builder.body(Body::from(body)).unwrap()
75 }
76}
77
78impl IntoResponse for StatusCode {
80 fn into_response(self) -> Response<Body> {
81 Response::builder()
82 .status(self)
83 .body(Body::empty())
84 .unwrap()
85 }
86}
87
88pub struct Json<T: Serialize>(pub T);
90
91impl<T: Serialize> IntoResponse for Json<T> {
92 fn into_response(self) -> Response<Body> {
93 let json = serde_json::to_string(&self.0).unwrap();
94 Response::builder()
95 .header(header::CONTENT_TYPE, "application/json")
96 .body(Body::from(json))
97 .unwrap()
98 }
99}
100
101pub struct Html(pub String);
103
104impl IntoResponse for Html {
105 fn into_response(self) -> Response<Body> {
106 Response::builder()
107 .header(header::CONTENT_TYPE, "text/html; charset=utf-8")
108 .body(Body::from(self.0))
109 .unwrap()
110 }
111}
112
113pub struct Text(pub String);
115
116impl IntoResponse for Text {
117 fn into_response(self) -> Response<Body> {
118 Response::builder()
119 .header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
120 .body(Body::from(self.0))
121 .unwrap()
122 }
123}
124
125impl<T, E> IntoResponse for Result<T, E>
127where
128 T: IntoResponse,
129 E: IntoResponse,
130{
131 fn into_response(self) -> Response<Body> {
132 match self {
133 Ok(value) => value.into_response(),
134 Err(err) => err.into_response(),
135 }
136 }
137}
138
139pub struct Redirect(pub String);
141
142impl IntoResponse for Redirect {
143 fn into_response(self) -> Response<Body> {
144 Response::builder()
145 .status(302)
146 .header("Location", self.0)
147 .body(Body::empty())
148 .unwrap()
149 }
150}
151
152pub struct PermRedirect(pub String);
154
155impl IntoResponse for PermRedirect {
156 fn into_response(self) -> Response<Body> {
157 Response::builder()
158 .status(301)
159 .header("Location", self.0)
160 .body(Body::empty())
161 .unwrap()
162 }
163}
164
165impl Redirect {
166 pub fn perm(url: String) -> PermRedirect {
167 PermRedirect(url)
168 }
169}
170
171pub struct File(pub String, pub bool);
173
174impl IntoResponse for File {
175 fn into_response(self) -> Response<Body> {
176 Response::builder()
177 .header(
178 header::CONTENT_TYPE,
179 if self.1 {
180 "application/octet-stream; charset=utf-8".to_string()
181 } else {
182 format!(
183 "{}; charset=utf-8",
184 get_mine_from_path(&self.0)
185 .first_or_octet_stream()
186 .to_string()
187 )
188 },
189 )
190 .body(Body::from(read_file(self.0).unwrap_or(String::new())))
191 .unwrap()
192 }
193}