1#[cfg(feature = "http")]
2use http::{HeaderMap, StatusCode};
3
4pub struct Formatter<'a> {
11 buf: &'a mut String,
12 #[cfg(feature = "http")]
13 status_code: Option<StatusCode>,
14 #[cfg(feature = "http")]
15 headers: HeaderMap,
16}
17
18impl<'a> Formatter<'a> {
19 #[inline]
21 pub fn new(buf: &'a mut String) -> Self {
22 Self {
23 buf,
24 #[cfg(feature = "http")]
25 status_code: None,
26 #[cfg(feature = "http")]
27 headers: HeaderMap::new(),
28 }
29 }
30
31 #[inline]
33 pub fn write_str(&mut self, s: &str) {
34 self.buf.push_str(s);
35 }
36
37 #[inline]
39 pub fn write_char(&mut self, c: char) {
40 self.buf.push(c);
41 }
42
43 #[cfg(feature = "http")]
46 #[inline]
47 pub(crate) fn record_status_code(&mut self, status_code: StatusCode) {
48 self.status_code.get_or_insert(status_code);
49 }
50
51 #[cfg(feature = "http")]
55 pub(crate) fn record_headers(&mut self, headers: HeaderMap) {
56 if self.headers.is_empty() {
57 self.headers = headers;
58 return;
59 }
60 for name in headers.keys() {
61 if !self.headers.contains_key(name) {
62 for value in headers.get_all(name) {
63 self.headers.append(name.clone(), value.clone());
64 }
65 }
66 }
67 }
68
69 #[cfg(feature = "http")]
72 pub(crate) fn into_recorded(self) -> (Option<StatusCode>, HeaderMap) {
73 (self.status_code, self.headers)
74 }
75}
76
77impl std::fmt::Write for Formatter<'_> {
78 fn write_str(&mut self, s: &str) -> std::fmt::Result {
79 Formatter::write_str(self, s);
80 Ok(())
81 }
82
83 fn write_char(&mut self, c: char) -> std::fmt::Result {
84 Formatter::write_char(self, c);
85 Ok(())
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn write_str_is_verbatim() {
95 let mut buf = String::new();
96 let mut f = Formatter::new(&mut buf);
97 f.write_str("<b>&\"'</b>");
98 assert_eq!(buf, "<b>&\"'</b>");
99 }
100
101 #[test]
102 fn write_char_is_verbatim() {
103 let mut buf = String::new();
104 let mut f = Formatter::new(&mut buf);
105 f.write_char('<');
106 f.write_char('é');
107 assert_eq!(buf, "<é");
108 }
109
110 #[test]
111 fn fmt_write_is_verbatim() {
112 use std::fmt::Write;
113
114 let (one, two) = (1, "two");
115 let mut buf = String::new();
116 let mut f = Formatter::new(&mut buf);
117 write!(f, "{one} < {two}").unwrap();
118 assert_eq!(buf, "1 < two");
119 }
120}