1use std::collections::{BTreeMap, HashMap};
4
5pub trait ToJson {
6 fn json_write(&self, w: &mut Vec<u8>);
7
8 #[inline]
16 fn json_size_hint(&self) -> usize { 64 }
17
18 #[must_use]
19 fn to_json_bytes(&self) -> Vec<u8> {
20 let mut buf = Vec::with_capacity(self.json_size_hint());
21 self.json_write(&mut buf);
22 buf
23 }
24
25 #[must_use]
26 fn to_json_string(&self) -> String {
27 String::from_utf8(self.to_json_bytes())
31 .expect("ToJson implementations always emit valid UTF-8")
32 }
33}
34
35#[inline]
46pub fn write_escaped_str(s: &str, w: &mut Vec<u8>) {
47 w.push(b'"');
48 w.reserve(s.len() + 1);
51 let bytes = s.as_bytes();
52 let mut start = 0usize; let mut i = start;
55 while i < bytes.len() {
56 let stop = crate::simd::find_escape(bytes, i);
58 if stop >= bytes.len() {
59 break;
61 }
62 w.extend_from_slice(&bytes[start..stop]);
64 escape_one(bytes[stop], w);
65 i = stop + 1;
66 start = i;
67 }
68
69 w.extend_from_slice(&bytes[start..]);
71 w.push(b'"');
72}
73
74#[inline(always)]
75fn escape_one(b: u8, w: &mut Vec<u8>) {
76 match b {
77 b'"' => w.extend_from_slice(b"\\\""),
78 b'\\' => w.extend_from_slice(b"\\\\"),
79 b'\n' => w.extend_from_slice(b"\\n"),
80 b'\r' => w.extend_from_slice(b"\\r"),
81 b'\t' => w.extend_from_slice(b"\\t"),
82 0x08 => w.extend_from_slice(b"\\b"),
83 0x0C => w.extend_from_slice(b"\\f"),
84 b => {
85 let hi = b >> 4;
87 let lo = b & 0xF;
88 w.extend_from_slice(&[
89 b'\\', b'u', b'0', b'0',
90 if hi < 10 { b'0' + hi } else { b'a' + hi - 10 },
91 if lo < 10 { b'0' + lo } else { b'a' + lo - 10 },
92 ]);
93 }
94 }
95}
96
97impl ToJson for bool {
100 #[inline]
101 fn json_write(&self, w: &mut Vec<u8>) {
102 w.extend_from_slice(if *self { b"true" } else { b"false" });
103 }
104 #[inline] fn json_size_hint(&self) -> usize { 5 } }
106
107impl ToJson for str {
108 #[inline]
109 fn json_write(&self, w: &mut Vec<u8>) { write_escaped_str(self, w); }
110 #[inline] fn json_size_hint(&self) -> usize { self.len() + 2 }
111}
112
113impl ToJson for String {
114 #[inline]
115 fn json_write(&self, w: &mut Vec<u8>) { write_escaped_str(self, w); }
116 #[inline] fn json_size_hint(&self) -> usize { self.len() + 2 }
117}
118
119impl ToJson for crate::scanner::JsonStr<'_> {
120 #[inline]
121 fn json_write(&self, w: &mut Vec<u8>) {
122 use crate::scanner::JsonStr;
123 match self {
124 JsonStr::BorrowedNoEsc(s) => {
125 w.reserve(s.len() + 2);
127 w.push(b'"');
128 w.extend_from_slice(s.as_bytes());
129 w.push(b'"');
130 }
131 JsonStr::Borrowed(s) => write_escaped_str(s, w),
132 JsonStr::Owned(s) => write_escaped_str(s, w),
133 }
134 }
135 #[inline]
136 fn json_size_hint(&self) -> usize { self.as_str().len() + 2 }
137}
138
139impl<T: ToJson + ?Sized> ToJson for &T {
140 #[inline]
141 fn json_write(&self, w: &mut Vec<u8>) { (**self).json_write(w); }
142 #[inline] fn json_size_hint(&self) -> usize { (**self).json_size_hint() }
143}
144
145impl<T: ToJson> ToJson for Box<T> {
146 #[inline]
147 fn json_write(&self, w: &mut Vec<u8>) { (**self).json_write(w); }
148 #[inline] fn json_size_hint(&self) -> usize { (**self).json_size_hint() }
149}
150
151impl<T: ToJson> ToJson for Option<T> {
152 #[inline]
153 fn json_write(&self, w: &mut Vec<u8>) {
154 match self {
155 Some(v) => v.json_write(w),
156 None => w.extend_from_slice(b"null"),
157 }
158 }
159 #[inline]
160 fn json_size_hint(&self) -> usize {
161 match self {
162 Some(v) => v.json_size_hint(),
163 None => 4, }
165 }
166}
167
168impl<T: ToJson> ToJson for Vec<T> {
169 fn json_write(&self, w: &mut Vec<u8>) {
170 w.push(b'[');
171 let mut first = true;
172 for item in self {
173 if !first { w.push(b','); }
174 item.json_write(w);
175 first = false;
176 }
177 w.push(b']');
178 }
179 #[inline]
180 fn json_size_hint(&self) -> usize {
181 if self.is_empty() { return 2; }
182 2 + self.len() * (self[0].json_size_hint() + 1)
184 }
185}
186
187impl<T: ToJson, const N: usize> ToJson for [T; N] {
188 fn json_write(&self, w: &mut Vec<u8>) {
189 w.push(b'[');
190 let mut first = true;
191 for item in self {
192 if !first { w.push(b','); }
193 item.json_write(w);
194 first = false;
195 }
196 w.push(b']');
197 }
198 #[inline]
199 fn json_size_hint(&self) -> usize {
200 if N == 0 { return 2; }
201 2 + N * (self[0].json_size_hint() + 1)
202 }
203}
204
205impl<T: ToJson> ToJson for [T] {
206 fn json_write(&self, w: &mut Vec<u8>) {
207 w.push(b'[');
208 let mut first = true;
209 for item in self {
210 if !first { w.push(b','); }
211 item.json_write(w);
212 first = false;
213 }
214 w.push(b']');
215 }
216 #[inline]
217 fn json_size_hint(&self) -> usize {
218 if self.is_empty() { return 2; }
219 2 + self.len() * (self[0].json_size_hint() + 1)
220 }
221}
222
223#[inline(always)]
231pub fn write_u64(mut n: u64, w: &mut Vec<u8>) {
232 if n == 0 { w.push(b'0'); return; }
233 let mut tmp = [0u8; 20];
234 let mut len = 0usize;
235 while n > 0 { tmp[len] = b'0' + (n % 10) as u8; n /= 10; len += 1; }
236 tmp[..len].reverse();
237 w.extend_from_slice(&tmp[..len]);
238}
239
240#[inline(always)]
241pub fn write_i64(n: i64, w: &mut Vec<u8>) {
242 if n < 0 { w.push(b'-'); write_u64(n.unsigned_abs(), w); } else { write_u64(n as u64, w); }
243}
244
245macro_rules! impl_uint {
246 ($($t:ty, $hint:expr),*) => {$(
247 impl ToJson for $t {
248 #[inline] fn json_write(&self, w: &mut Vec<u8>) { write_u64(*self as u64, w); }
249 #[inline] fn json_size_hint(&self) -> usize { $hint }
250 }
251 )*};
252}
253macro_rules! impl_sint {
254 ($($t:ty, $hint:expr),*) => {$(
255 impl ToJson for $t {
256 #[inline] fn json_write(&self, w: &mut Vec<u8>) { write_i64(*self as i64, w); }
257 #[inline] fn json_size_hint(&self) -> usize { $hint }
258 }
259 )*};
260}
261impl_uint!(u8, 3, u16, 5, u32, 10, u64, 20, usize, 20);
265impl_sint!(i8, 4, i16, 6, i32, 11, i64, 20, isize, 20);
266
267#[inline]
269fn write_u128(mut n: u128, w: &mut Vec<u8>) {
270 if n == 0 { w.push(b'0'); return; }
271 let mut tmp = [0u8; 39];
272 let mut len = 0usize;
273 while n > 0 { tmp[len] = b'0' + (n % 10) as u8; n /= 10; len += 1; }
274 tmp[..len].reverse();
275 w.extend_from_slice(&tmp[..len]);
276}
277impl ToJson for u128 {
278 #[inline] fn json_write(&self, w: &mut Vec<u8>) { write_u128(*self, w); }
279 #[inline] fn json_size_hint(&self) -> usize { 39 }
280}
281impl ToJson for i128 {
282 #[inline]
283 fn json_write(&self, w: &mut Vec<u8>) {
284 if *self < 0 { w.push(b'-'); write_u128(self.unsigned_abs(), w); } else { write_u128(*self as u128, w); }
285 }
286 #[inline] fn json_size_hint(&self) -> usize { 40 }
287}
288
289impl ToJson for f64 {
290 #[inline]
291 fn json_write(&self, w: &mut Vec<u8>) {
292 if !self.is_finite() { w.extend_from_slice(b"null"); return; }
293 if *self == 0.0 { w.extend_from_slice(b"0"); return; }
296 #[cfg(feature = "zmij-float-ser")]
297 {
298 let mut buf = zmij::Buffer::new();
299 w.extend_from_slice(buf.format_finite(*self).as_bytes());
300 return;
301 }
302 #[cfg(all(feature = "fast-float", not(feature = "zmij-float-ser")))]
303 {
304 let mut buf = ryu::Buffer::new();
305 w.extend_from_slice(buf.format_finite(*self).as_bytes());
306 return;
307 }
308 #[cfg(not(any(feature = "fast-float", feature = "zmij-float-ser")))]
309 w.extend_from_slice(format!("{}", self).as_bytes());
310 }
311 #[inline] fn json_size_hint(&self) -> usize { 10 }
318}
319
320impl ToJson for f32 {
321 #[inline]
322 fn json_write(&self, w: &mut Vec<u8>) {
323 if !self.is_finite() { w.extend_from_slice(b"null"); return; }
324 #[cfg(feature = "zmij-float-ser")]
325 {
326 let mut buf = zmij::Buffer::new();
327 w.extend_from_slice(buf.format_finite(*self).as_bytes());
328 return;
329 }
330 #[cfg(all(feature = "fast-float", not(feature = "zmij-float-ser")))]
331 {
332 let mut buf = ryu::Buffer::new();
333 w.extend_from_slice(buf.format_finite(*self).as_bytes());
334 return;
335 }
336 #[cfg(not(any(feature = "fast-float", feature = "zmij-float-ser")))]
337 w.extend_from_slice(format!("{}", self).as_bytes());
338 }
339 #[inline] fn json_size_hint(&self) -> usize { 14 }
341}
342
343impl ToJson for char {
346 #[inline]
347 fn json_write(&self, w: &mut Vec<u8>) {
348 let mut buf = [0u8; 4];
349 write_escaped_str(self.encode_utf8(&mut buf), w);
350 }
351 #[inline] fn json_size_hint(&self) -> usize { 6 }
353}
354
355impl ToJson for () {
358 #[inline] fn json_write(&self, w: &mut Vec<u8>) { w.extend_from_slice(b"null"); }
359 #[inline] fn json_size_hint(&self) -> usize { 4 }
360}
361
362impl<K: ToJson, V: ToJson> ToJson for HashMap<K, V> {
365 fn json_write(&self, w: &mut Vec<u8>) {
366 w.push(b'{');
367 let mut first = true;
368 for (k, v) in self {
369 if !first { w.push(b','); }
370 first = false;
371 k.json_write(w);
372 w.push(b':');
373 v.json_write(w);
374 }
375 w.push(b'}');
376 }
377 #[inline]
378 fn json_size_hint(&self) -> usize {
379 if self.is_empty() { return 2; }
380 let (k, v) = self.iter().next().unwrap();
381 2 + self.len() * (k.json_size_hint() + 1 + v.json_size_hint() + 1)
382 }
383}
384
385impl<K: ToJson, V: ToJson> ToJson for BTreeMap<K, V> {
386 fn json_write(&self, w: &mut Vec<u8>) {
387 w.push(b'{');
388 let mut first = true;
389 for (k, v) in self {
390 if !first { w.push(b','); }
391 first = false;
392 k.json_write(w);
393 w.push(b':');
394 v.json_write(w);
395 }
396 w.push(b'}');
397 }
398 #[inline]
399 fn json_size_hint(&self) -> usize {
400 if self.is_empty() { return 2; }
401 let (k, v) = self.iter().next().unwrap();
402 2 + self.len() * (k.json_size_hint() + 1 + v.json_size_hint() + 1)
403 }
404}
405
406macro_rules! impl_tuple_to_json {
409 ($($T:ident . $idx:tt),+) => {
410 impl<$($T: ToJson),+> ToJson for ($($T,)+) {
411 fn json_write(&self, w: &mut Vec<u8>) {
412 w.push(b'[');
413 let mut first = true;
414 $( if !first { w.push(b','); } first = false; self.$idx.json_write(w); )+
415 let _ = first;
416 w.push(b']');
417 }
418 #[inline]
419 fn json_size_hint(&self) -> usize {
420 2 + $( self.$idx.json_size_hint() + 1 + )+ 0
421 - 1 }
423 }
424 };
425}
426
427impl_tuple_to_json!(A.0);
428impl_tuple_to_json!(A.0, B.1);
429impl_tuple_to_json!(A.0, B.1, C.2);
430impl_tuple_to_json!(A.0, B.1, C.2, D.3);
431impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4);
432impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5);
433impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5, G.6);
434impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5, G.6, H.7);
435impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5, G.6, H.7, I.8);
436impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5, G.6, H.7, I.8, J.9);
437impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5, G.6, H.7, I.8, J.9, K.10);
438impl_tuple_to_json!(A.0, B.1, C.2, D.3, E.4, F.5, G.6, H.7, I.8, J.9, K.10, L.11);