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