1#[inline]
24pub fn null(buf: &mut String) {
25 encode_null(buf, ());
26}
27#[inline]
28pub fn bool(buf: &mut String, value: bool) {
29 encode_bool(buf, value);
30}
31#[inline]
32pub fn number(buf: &mut String, number: f64) {
33 encode_number(buf, number);
34}
35#[inline]
36pub fn string(buf: &mut String, string: &str) {
37 encode_str(buf, string);
38}
39#[inline]
40pub fn object(buf: &mut String) -> Object<'_> {
41 Object::new(buf)
42}
43#[inline]
44pub fn array(buf: &mut String) -> Array<'_> {
45 Array::new(buf)
46}
47
48pub struct Object<'a> {
49 buf: &'a mut String,
50 first: bool,
51}
52
53impl<'a> Object<'a> {
54 #[inline]
55 fn new(buf: &'a mut String) -> Self {
56 buf.push('{');
57 Object { buf, first: true }
58 }
59 #[inline]
60 fn key(&mut self, key: &str) {
61 if !self.first {
62 self.buf.push(',');
63 }
64 self.first = false;
65 encode_str(&mut self.buf, key);
66 self.buf.push(':');
67 }
68 #[inline]
69 fn field<T, F: FnOnce(&mut String, T)>(&mut self, key: &str, enc: F, value: T) -> &mut Self {
70 self.key(key);
71 enc(&mut self.buf, value);
72 self
73 }
74
75 #[inline]
76 pub fn null(&mut self, key: &str) -> &mut Self {
77 self.field(key, encode_null, ())
78 }
79 #[inline]
80 pub fn bool(&mut self, key: &str, value: bool) -> &mut Self {
81 self.field(key, encode_bool, value)
82 }
83 #[inline]
84 pub fn number(&mut self, key: &str, value: f64) -> &mut Self {
85 self.field(key, encode_number, value)
86 }
87 #[inline]
88 pub fn string(&mut self, key: &str, value: &str) -> &mut Self {
89 self.field(key, encode_str, value)
90 }
91 #[inline]
92 pub fn object(&mut self, key: &str) -> Object<'_> {
93 self.key(key);
94 Object::new(self.buf)
95 }
96 #[inline]
97 pub fn array(&mut self, key: &str) -> Array<'_> {
98 self.key(key);
99 Array::new(self.buf)
100 }
101}
102
103impl Drop for Object<'_> {
104 #[inline]
105 fn drop(&mut self) {
106 self.buf.push('}')
107 }
108}
109
110pub struct Array<'a> {
111 buf: &'a mut String,
112 first: bool,
113}
114
115impl<'a> Array<'a> {
116 #[inline]
117 fn new(buf: &'a mut String) -> Self {
118 buf.push('[');
119 Array { buf, first: true }
120 }
121 #[inline]
122 fn comma(&mut self) {
123 if !self.first {
124 self.buf.push(',');
125 }
126 self.first = false;
127 }
128 #[inline]
129 fn element<T, F: FnOnce(&mut String, T)>(&mut self, enc: F, value: T) -> &mut Self {
130 self.comma();
131 enc(&mut self.buf, value);
132 self
133 }
134
135 #[inline]
136 pub fn null(&mut self) -> &mut Self {
137 self.element(encode_null, ())
138 }
139 #[inline]
140 pub fn bool(&mut self, value: bool) -> &mut Self {
141 self.element(encode_bool, value)
142 }
143 #[inline]
144 pub fn number(&mut self, value: f64) -> &mut Self {
145 self.element(encode_number, value)
146 }
147 #[inline]
148 pub fn string(&mut self, value: &str) -> &mut Self {
149 self.element(encode_str, value)
150 }
151 #[inline]
152 pub fn object(&mut self) -> Object<'_> {
153 self.comma();
154 Object::new(self.buf)
155 }
156 #[inline]
157 pub fn array(&mut self) -> Array<'_> {
158 self.comma();
159 Array::new(self.buf)
160 }
161}
162
163impl Drop for Array<'_> {
164 #[inline]
165 fn drop(&mut self) {
166 self.buf.push(']')
167 }
168}
169
170#[inline]
171fn encode_null(buf: &mut String, (): ()) {
172 buf.push_str("null")
173}
174#[inline]
175fn encode_bool(buf: &mut String, value: bool) {
176 buf.push_str(if value { "true" } else { "false" })
177}
178#[inline]
179fn encode_number(buf: &mut String, number: f64) {
180 use std::fmt::Write;
181 let _ = write!(buf, "{}", number);
182}
183
184#[inline]
185fn encode_str(buf: &mut String, s: &str) {
186 buf.reserve(s.len() + 2);
187 buf.push('\"');
188 if s.bytes()
189 .all(|b| 0x1F < b && b != b'"' && b != b'\\' && b < 0x7F)
190 {
191 buf.push_str(s)
192 } else {
193 slow_path(buf, s)
194 }
195 buf.push('\"');
196
197 #[inline(never)]
198 fn slow_path(buf: &mut String, s: &str) {
199 for c in s.chars() {
200 if (c as u32) < 256 {
201 let b = c as u8;
202 match b {
203 b'\\' | b'"' => push_escape(buf, c),
204 b'\n' => push_escape(buf, 'n'),
205 b'\r' => push_escape(buf, 'r'),
206 b'\t' => push_escape(buf, 't'),
207 0..=0x1F | 0x7F..=0x9F => {
208 push_escape(buf, 'u');
209 buf.push_str("00");
210 buf.push(hex(b >> 4));
211 buf.push(hex(b & 0xF));
212 }
213 _ => buf.push(c),
214 }
215 } else {
216 buf.push(c)
217 }
218 }
219 }
220
221 #[inline]
222 fn push_escape(buf: &mut String, c: char) {
223 buf.push('\\');
224 buf.push(c);
225 }
226
227 #[inline]
228 fn hex(b: u8) -> char {
229 (b"0123456789ABCDEF"[(b & 0xF) as usize]) as char
230 }
231}