1use std::fmt::{self, Debug, Display, Formatter};
2
3use super::{Scribe, try_set_header};
4use crate::http::Response;
5use crate::http::header::{CONTENT_TYPE, HeaderValue};
6
7#[non_exhaustive]
20pub enum Text<C> {
21 Plain(C),
23 Json(C),
25 Xml(C),
27 Html(C),
29 Js(C),
31 Css(C),
33 Csv(C),
35 Atom(C),
37 Rss(C),
39 Rdf(C),
41}
42
43impl<C> Text<C>
44where
45 C: AsRef<str>,
46{
47 fn try_set_header(self, res: &mut Response) -> C {
48 let (ctype, content) = match self {
49 Self::Plain(content) => (
50 HeaderValue::from_static("text/plain; charset=utf-8"),
51 content,
52 ),
53 Self::Json(content) => (
54 HeaderValue::from_static("application/json; charset=utf-8"),
55 content,
56 ),
57 Self::Xml(content) => (
58 HeaderValue::from_static("application/xml; charset=utf-8"),
59 content,
60 ),
61 Self::Html(content) => (
62 HeaderValue::from_static("text/html; charset=utf-8"),
63 content,
64 ),
65 Self::Js(content) => (
66 HeaderValue::from_static("text/javascript; charset=utf-8"),
67 content,
68 ),
69 Self::Css(content) => (HeaderValue::from_static("text/css; charset=utf-8"), content),
70 Self::Csv(content) => (HeaderValue::from_static("text/csv; charset=utf-8"), content),
71 Self::Atom(content) => (
72 HeaderValue::from_static("application/atom+xml; charset=utf-8"),
73 content,
74 ),
75 Self::Rss(content) => (
76 HeaderValue::from_static("application/rss+xml; charset=utf-8"),
77 content,
78 ),
79 Self::Rdf(content) => (
80 HeaderValue::from_static("application/rdf+xml; charset=utf-8"),
81 content,
82 ),
83 };
84 try_set_header(&mut res.headers, CONTENT_TYPE, ctype);
85 content
86 }
87}
88impl Scribe for Text<&'static str> {
89 #[inline]
90 fn render(self, res: &mut Response) {
91 let content = self.try_set_header(res);
92 let _ = res.write_body(content);
93 }
94}
95impl Scribe for Text<String> {
96 #[inline]
97 fn render(self, res: &mut Response) {
98 let content = self.try_set_header(res);
99 let _ = res.write_body(content);
100 }
101}
102impl Scribe for Text<&String> {
103 #[inline]
104 fn render(self, res: &mut Response) {
105 let content = self.try_set_header(res);
106 let _ = res.write_body(content.as_bytes().to_vec());
107 }
108}
109impl<C: Debug> Debug for Text<C> {
110 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
111 match self {
112 Self::Plain(content) => f.debug_tuple("Text::Plain").field(content).finish(),
113 Self::Json(content) => f.debug_tuple("Text::Json").field(content).finish(),
114 Self::Xml(content) => f.debug_tuple("Text::Xml").field(content).finish(),
115 Self::Html(content) => f.debug_tuple("Text::Html").field(content).finish(),
116 Self::Js(content) => f.debug_tuple("Text::Js").field(content).finish(),
117 Self::Css(content) => f.debug_tuple("Text::Css").field(content).finish(),
118 Self::Csv(content) => f.debug_tuple("Text::Csv").field(content).finish(),
119 Self::Atom(content) => f.debug_tuple("Text::Atom").field(content).finish(),
120 Self::Rss(content) => f.debug_tuple("Text::Rss").field(content).finish(),
121 Self::Rdf(content) => f.debug_tuple("Text::Rdf").field(content).finish(),
122 }
123 }
124}
125impl<C: Display> Display for Text<C> {
126 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
127 match self {
128 Self::Plain(content)
129 | Self::Json(content)
130 | Self::Xml(content)
131 | Self::Html(content)
132 | Self::Js(content)
133 | Self::Css(content)
134 | Self::Csv(content)
135 | Self::Atom(content)
136 | Self::Rss(content)
137 | Self::Rdf(content) => Display::fmt(content, f),
138 }
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use crate::prelude::*;
145
146 use super::*;
147 use crate::test::{ResponseExt, TestClient};
148
149 #[tokio::test]
150 async fn test_write_str() {
151 #[handler]
152 async fn test() -> &'static str {
153 "hello"
154 }
155
156 let router = Router::new().push(Router::with_path("test").get(test));
157
158 let mut res = TestClient::get("http://127.0.0.1:8698/test")
159 .send(router)
160 .await;
161 assert_eq!(res.take_string().await.unwrap(), "hello");
162 assert_eq!(
163 res.headers().get("content-type").unwrap(),
164 "text/plain; charset=utf-8"
165 );
166 }
167
168 #[tokio::test]
169 async fn test_write_string() {
170 #[handler]
171 async fn test() -> String {
172 "hello".to_owned()
173 }
174
175 let router = Router::new().push(Router::with_path("test").get(test));
176 let mut res = TestClient::get("http://127.0.0.1:8698/test")
177 .send(router)
178 .await;
179 assert_eq!(res.take_string().await.unwrap(), "hello");
180 assert_eq!(
181 res.headers().get("content-type").unwrap(),
182 "text/plain; charset=utf-8"
183 );
184 }
185
186 #[tokio::test]
187 async fn test_write_plain_text() {
188 #[handler]
189 async fn test() -> Text<&'static str> {
190 Text::Plain("hello")
191 }
192
193 let router = Router::new().push(Router::with_path("test").get(test));
194
195 let mut res = TestClient::get("http://127.0.0.1:8698/test")
196 .send(router)
197 .await;
198 assert_eq!(res.take_string().await.unwrap(), "hello");
199 assert_eq!(
200 res.headers().get("content-type").unwrap(),
201 "text/plain; charset=utf-8"
202 );
203 }
204
205 #[tokio::test]
206 async fn test_write_json_text() {
207 #[handler]
208 async fn test() -> Text<&'static str> {
209 Text::Json(r#"{"hello": "world"}"#)
210 }
211
212 let router = Router::new().push(Router::with_path("test").get(test));
213 let mut res = TestClient::get("http://127.0.0.1:8698/test")
214 .send(router)
215 .await;
216 assert_eq!(res.take_string().await.unwrap(), r#"{"hello": "world"}"#);
217 assert_eq!(
218 res.headers().get("content-type").unwrap(),
219 "application/json; charset=utf-8"
220 );
221 }
222
223 #[tokio::test]
224 async fn test_write_html_text() {
225 #[handler]
226 async fn test() -> Text<&'static str> {
227 Text::Html("<html><body>hello</body></html>")
228 }
229
230 let router = Router::new().push(Router::with_path("test").get(test));
231 let mut res = TestClient::get("http://127.0.0.1:8698/test")
232 .send(router)
233 .await;
234 assert_eq!(
235 res.take_string().await.unwrap(),
236 "<html><body>hello</body></html>"
237 );
238 assert_eq!(
239 res.headers().get("content-type").unwrap(),
240 "text/html; charset=utf-8"
241 );
242 }
243 #[tokio::test]
244 async fn test_write_xml_text() {
245 #[handler]
246 async fn test() -> Text<&'static str> {
247 Text::Xml("<xml>hello</xml>")
248 }
249
250 let router = Router::new().push(Router::with_path("test").get(test));
251 let mut res = TestClient::get("http://127.0.0.1:8698/test")
252 .send(router)
253 .await;
254 assert_eq!(res.take_string().await.unwrap(), "<xml>hello</xml>");
255 assert_eq!(
256 res.headers().get("content-type").unwrap(),
257 "application/xml; charset=utf-8"
258 );
259 }
260
261 #[tokio::test]
262 async fn test_write_js_text() {
263 #[handler]
264 async fn test() -> Text<&'static str> {
265 Text::Js("var a = 1;")
266 }
267
268 let router = Router::new().push(Router::with_path("test").get(test));
269 let mut res = TestClient::get("http://127.0.0.1:8698/test")
270 .send(router)
271 .await;
272 assert_eq!(res.take_string().await.unwrap(), "var a = 1;");
273 assert_eq!(
274 res.headers().get("content-type").unwrap(),
275 "text/javascript; charset=utf-8"
276 );
277 }
278
279 #[tokio::test]
280 async fn test_write_css_text() {
281 #[handler]
282 async fn test() -> Text<&'static str> {
283 Text::Css("body {color: red;}")
284 }
285
286 let router = Router::new().push(Router::with_path("test").get(test));
287 let mut res = TestClient::get("http://127.0.0.1:8698/test")
288 .send(router)
289 .await;
290 assert_eq!(res.take_string().await.unwrap(), "body {color: red;}");
291 assert_eq!(
292 res.headers().get("content-type").unwrap(),
293 "text/css; charset=utf-8"
294 );
295 }
296
297 #[tokio::test]
298 async fn test_write_csv_text() {
299 #[handler]
300 async fn test() -> Text<&'static str> {
301 Text::Csv("a,b,c")
302 }
303
304 let router = Router::new().push(Router::with_path("test").get(test));
305 let mut res = TestClient::get("http://127.0.0.1:8698/test")
306 .send(router)
307 .await;
308 assert_eq!(res.take_string().await.unwrap(), "a,b,c");
309 assert_eq!(
310 res.headers().get("content-type").unwrap(),
311 "text/csv; charset=utf-8"
312 );
313 }
314
315 #[tokio::test]
316 async fn test_write_atom_text() {
317 #[handler]
318 async fn test() -> Text<&'static str> {
319 Text::Atom("<feed></feed>")
320 }
321
322 let router = Router::new().push(Router::with_path("test").get(test));
323 let mut res = TestClient::get("http://127.0.0.1:8698/test")
324 .send(router)
325 .await;
326 assert_eq!(res.take_string().await.unwrap(), "<feed></feed>");
327 assert_eq!(
328 res.headers().get("content-type").unwrap(),
329 "application/atom+xml; charset=utf-8"
330 );
331 }
332
333 #[tokio::test]
334 async fn test_write_rss_text() {
335 #[handler]
336 async fn test() -> Text<&'static str> {
337 Text::Rss("<rss></rss>")
338 }
339
340 let router = Router::new().push(Router::with_path("test").get(test));
341 let mut res = TestClient::get("http://127.0.0.1:8698/test")
342 .send(router)
343 .await;
344 assert_eq!(res.take_string().await.unwrap(), "<rss></rss>");
345 assert_eq!(
346 res.headers().get("content-type").unwrap(),
347 "application/rss+xml; charset=utf-8"
348 );
349 }
350
351 #[tokio::test]
352 async fn test_write_rdf_text() {
353 #[handler]
354 async fn test() -> Text<&'static str> {
355 Text::Rdf("<rdf></rdf>")
356 }
357
358 let router = Router::new().push(Router::with_path("test").get(test));
359 let mut res = TestClient::get("http://127.0.0.1:8698/test")
360 .send(router)
361 .await;
362 assert_eq!(res.take_string().await.unwrap(), "<rdf></rdf>");
363 assert_eq!(
364 res.headers().get("content-type").unwrap(),
365 "application/rdf+xml; charset=utf-8"
366 );
367 }
368}