rustack_cloudfront_http/xml/
writer.rs1#[derive(Debug, Default)]
5pub struct XmlWriter {
6 buf: String,
7}
8
9impl XmlWriter {
10 #[must_use]
12 pub fn new() -> Self {
13 Self::with_capacity(512)
14 }
15
16 #[must_use]
18 pub fn with_capacity(cap: usize) -> Self {
19 Self {
20 buf: String::with_capacity(cap),
21 }
22 }
23
24 pub fn declaration(&mut self) {
26 self.buf
27 .push_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
28 }
29
30 pub fn open_root(&mut self, name: &str, namespace: Option<&str>) {
32 self.buf.push('<');
33 self.buf.push_str(name);
34 if let Some(ns) = namespace {
35 self.buf.push_str(" xmlns=\"");
36 self.buf.push_str(ns);
37 self.buf.push('\"');
38 }
39 self.buf.push('>');
40 }
41
42 pub fn open(&mut self, name: &str) {
44 self.buf.push('<');
45 self.buf.push_str(name);
46 self.buf.push('>');
47 }
48
49 pub fn close(&mut self, name: &str) {
51 self.buf.push_str("</");
52 self.buf.push_str(name);
53 self.buf.push('>');
54 }
55
56 pub fn empty(&mut self, name: &str) {
58 self.buf.push('<');
59 self.buf.push_str(name);
60 self.buf.push_str("/>");
61 }
62
63 pub fn element(&mut self, name: &str, text: &str) {
65 self.open(name);
66 self.buf.push_str(&escape(text));
67 self.close(name);
68 }
69
70 pub fn element_display<D: std::fmt::Display>(&mut self, name: &str, v: D) {
72 let s = v.to_string();
73 self.element(name, &s);
74 }
75
76 pub fn bool(&mut self, name: &str, v: bool) {
78 self.element(name, if v { "true" } else { "false" });
79 }
80
81 pub fn optional_str(&mut self, name: &str, v: &str) {
83 if !v.is_empty() {
84 self.element(name, v);
85 }
86 }
87
88 pub fn items<T, F: FnMut(&mut Self, &T)>(
90 &mut self,
91 items: &[T],
92 wrapper: &str,
93 item_name: &str,
94 mut emit: F,
95 ) {
96 self.open(wrapper);
97 self.element_display("Quantity", items.len());
98 if items.is_empty() {
99 } else {
101 self.open("Items");
102 for it in items {
103 self.open(item_name);
104 emit(self, it);
105 self.close(item_name);
106 }
107 self.close("Items");
108 }
109 self.close(wrapper);
110 }
111
112 #[must_use]
114 pub fn finish(self) -> String {
115 self.buf
116 }
117
118 pub fn raw(&mut self, s: &str) {
120 self.buf.push_str(s);
121 }
122}
123
124fn escape(s: &str) -> String {
125 let mut out = String::with_capacity(s.len());
126 for c in s.chars() {
127 match c {
128 '&' => out.push_str("&"),
129 '<' => out.push_str("<"),
130 '>' => out.push_str(">"),
131 '"' => out.push_str("""),
132 '\'' => out.push_str("'"),
133 _ => out.push(c),
134 }
135 }
136 out
137}