1use core::fmt;
16
17use crate::number::NumberValue;
18use crate::owned::OwnedDataValue;
19use crate::value::DataValue;
20
21pub(crate) trait JsonSink {
31 type Error;
32 fn write_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error>;
33 fn write_byte(&mut self, b: u8) -> Result<(), Self::Error>;
34}
35
36impl JsonSink for Vec<u8> {
37 type Error = core::convert::Infallible;
38 #[inline]
39 fn write_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error> {
40 self.extend_from_slice(b);
41 Ok(())
42 }
43 #[inline]
44 fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
45 self.push(b);
46 Ok(())
47 }
48}
49
50impl JsonSink for bumpalo::collections::Vec<'_, u8> {
51 type Error = core::convert::Infallible;
52 #[inline]
53 fn write_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error> {
54 self.reserve(b.len());
59 let len = self.len();
60 unsafe {
64 core::ptr::copy_nonoverlapping(b.as_ptr(), self.as_mut_ptr().add(len), b.len());
65 self.set_len(len + b.len());
66 }
67 Ok(())
68 }
69 #[inline]
70 fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
71 self.push(b);
72 Ok(())
73 }
74}
75
76#[inline]
83fn into_arena_str<'b>(mut out: bumpalo::collections::Vec<'b, u8>) -> &'b str {
84 out.shrink_to_fit();
89 unsafe { core::str::from_utf8_unchecked(out.into_bump_slice()) }
90}
91
92const FMT_STAGING: usize = 128;
96
97struct FormatterSink<'a, 'b> {
98 f: &'a mut fmt::Formatter<'b>,
99 buf: [u8; FMT_STAGING],
100 len: usize,
101}
102
103impl<'a, 'b> FormatterSink<'a, 'b> {
104 fn new(f: &'a mut fmt::Formatter<'b>) -> Self {
105 FormatterSink {
106 f,
107 buf: [0; FMT_STAGING],
108 len: 0,
109 }
110 }
111
112 fn flush(&mut self) -> fmt::Result {
113 if self.len > 0 {
114 let s = unsafe { core::str::from_utf8_unchecked(&self.buf[..self.len]) };
118 self.f.write_str(s)?;
119 self.len = 0;
120 }
121 Ok(())
122 }
123}
124
125impl<'a, 'b> JsonSink for FormatterSink<'a, 'b> {
126 type Error = fmt::Error;
127 #[inline]
128 fn write_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error> {
129 if self.len + b.len() > FMT_STAGING {
130 self.flush()?;
131 if b.len() >= FMT_STAGING {
132 let s = unsafe { core::str::from_utf8_unchecked(b) };
134 return self.f.write_str(s);
135 }
136 }
137 self.buf[self.len..self.len + b.len()].copy_from_slice(b);
138 self.len += b.len();
139 Ok(())
140 }
141 #[inline]
142 fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
143 debug_assert!(b.is_ascii());
144 if self.len == FMT_STAGING {
145 self.flush()?;
146 }
147 self.buf[self.len] = b;
148 self.len += 1;
149 Ok(())
150 }
151}
152
153#[inline]
154fn write_escaped_str<S: JsonSink>(out: &mut S, s: &str) -> Result<(), S::Error> {
155 out.write_byte(b'"')?;
156 let bytes = s.as_bytes();
157 let mut run_start = 0;
158
159 while let Some(off) = crate::simd::find_string_terminator(&bytes[run_start..]) {
164 let hit = run_start + off;
165 if hit > run_start {
166 out.write_bytes(&bytes[run_start..hit])?;
167 }
168 write_escape_byte(out, bytes[hit])?;
169 run_start = hit + 1;
170 }
171 if run_start < bytes.len() {
172 out.write_bytes(&bytes[run_start..])?;
173 }
174 out.write_byte(b'"')
175}
176
177#[cfg(feature = "datetime")]
182fn write_datetime<S: JsonSink>(
183 out: &mut S,
184 d: &crate::datetime::DataDateTime,
185) -> Result<(), S::Error> {
186 match d.iso_secs_buf() {
187 Some(buf) => {
188 out.write_byte(b'"')?;
189 out.write_bytes(&buf)?;
190 out.write_byte(b'"')
191 }
192 None => write_escaped_str(out, &d.to_iso_string()),
193 }
194}
195
196#[cfg(feature = "datetime")]
199fn write_duration<S: JsonSink>(
200 out: &mut S,
201 d: &crate::datetime::DataDuration,
202) -> Result<(), S::Error> {
203 let (days, hours, minutes, seconds) = d.dhms();
204 let mut b = itoa::Buffer::new();
205 out.write_byte(b'"')?;
206 out.write_bytes(b.format(days).as_bytes())?;
207 out.write_bytes(b"d:")?;
208 out.write_bytes(b.format(hours).as_bytes())?;
209 out.write_bytes(b"h:")?;
210 out.write_bytes(b.format(minutes).as_bytes())?;
211 out.write_bytes(b"m:")?;
212 out.write_bytes(b.format(seconds).as_bytes())?;
213 out.write_bytes(b"s\"")
214}
215
216#[inline]
217fn write_escape_byte<S: JsonSink>(out: &mut S, b: u8) -> Result<(), S::Error> {
218 match b {
219 b'"' => out.write_bytes(b"\\\""),
220 b'\\' => out.write_bytes(b"\\\\"),
221 b'\n' => out.write_bytes(b"\\n"),
222 b'\r' => out.write_bytes(b"\\r"),
223 b'\t' => out.write_bytes(b"\\t"),
224 0x08 => out.write_bytes(b"\\b"),
225 0x0C => out.write_bytes(b"\\f"),
226 c => {
227 const HEX: &[u8; 16] = b"0123456789abcdef";
230 out.write_bytes(b"\\u00")?;
231 out.write_byte(HEX[((c >> 4) & 0x0F) as usize])?;
232 out.write_byte(HEX[(c & 0x0F) as usize])
233 }
234 }
235}
236
237#[inline]
238fn write_number<S: JsonSink>(out: &mut S, n: NumberValue) -> Result<(), S::Error> {
239 match n {
240 NumberValue::Integer(i) => {
241 let mut buf = itoa::Buffer::new();
242 out.write_bytes(buf.format(i).as_bytes())
243 }
244 NumberValue::Float(f) => {
245 if !f.is_finite() {
246 return out.write_bytes(b"null");
249 }
250 let mut buf = ryu::Buffer::new();
251 out.write_bytes(buf.format_finite(f).as_bytes())
252 }
253 }
254}
255
256fn write_data_value<S: JsonSink>(out: &mut S, v: &DataValue<'_>) -> Result<(), S::Error> {
259 match *v {
260 DataValue::Null => out.write_bytes(b"null"),
261 DataValue::Bool(true) => out.write_bytes(b"true"),
262 DataValue::Bool(false) => out.write_bytes(b"false"),
263 DataValue::Number(n) => write_number(out, n),
264 DataValue::String(s) => write_escaped_str(out, s),
265 DataValue::Array(items) => {
266 out.write_byte(b'[')?;
267 let mut first = true;
268 for item in items {
269 if !first {
270 out.write_byte(b',')?;
271 }
272 first = false;
273 write_data_value(out, item)?;
274 }
275 out.write_byte(b']')
276 }
277 DataValue::Object(pairs) => {
278 out.write_byte(b'{')?;
279 let mut first = true;
280 for (k, v) in pairs {
281 if !first {
282 out.write_byte(b',')?;
283 }
284 first = false;
285 write_escaped_str(out, k)?;
286 out.write_byte(b':')?;
287 write_data_value(out, v)?;
288 }
289 out.write_byte(b'}')
290 }
291 #[cfg(feature = "datetime")]
292 DataValue::DateTime(d) => write_datetime(out, &d),
293 #[cfg(feature = "datetime")]
294 DataValue::Duration(d) => write_duration(out, &d),
295 }
296}
297
298fn write_owned_value<S: JsonSink>(out: &mut S, v: &OwnedDataValue) -> Result<(), S::Error> {
299 match v {
300 OwnedDataValue::Null => out.write_bytes(b"null"),
301 OwnedDataValue::Bool(true) => out.write_bytes(b"true"),
302 OwnedDataValue::Bool(false) => out.write_bytes(b"false"),
303 OwnedDataValue::Number(n) => write_number(out, *n),
304 OwnedDataValue::String(s) => write_escaped_str(out, s),
305 OwnedDataValue::Array(items) => {
306 out.write_byte(b'[')?;
307 let mut first = true;
308 for item in items {
309 if !first {
310 out.write_byte(b',')?;
311 }
312 first = false;
313 write_owned_value(out, item)?;
314 }
315 out.write_byte(b']')
316 }
317 OwnedDataValue::Object(pairs) => {
318 out.write_byte(b'{')?;
319 let mut first = true;
320 for (k, v) in pairs {
321 if !first {
322 out.write_byte(b',')?;
323 }
324 first = false;
325 write_escaped_str(out, k)?;
326 out.write_byte(b':')?;
327 write_owned_value(out, v)?;
328 }
329 out.write_byte(b'}')
330 }
331 #[cfg(feature = "datetime")]
332 OwnedDataValue::DateTime(d) => write_datetime(out, d),
333 #[cfg(feature = "datetime")]
334 OwnedDataValue::Duration(d) => write_duration(out, d),
335 }
336}
337
338#[inline]
341fn write_indent<S: JsonSink>(out: &mut S, depth: usize) -> Result<(), S::Error> {
342 const SPACES: &[u8; 64] = b" ";
345 let mut remaining = depth * 2;
346 while remaining > 0 {
347 let chunk = remaining.min(SPACES.len());
348 out.write_bytes(&SPACES[..chunk])?;
349 remaining -= chunk;
350 }
351 Ok(())
352}
353
354fn write_data_value_pretty<S: JsonSink>(
355 out: &mut S,
356 v: &DataValue<'_>,
357 depth: usize,
358) -> Result<(), S::Error> {
359 match *v {
360 DataValue::Null => out.write_bytes(b"null"),
361 DataValue::Bool(true) => out.write_bytes(b"true"),
362 DataValue::Bool(false) => out.write_bytes(b"false"),
363 DataValue::Number(n) => write_number(out, n),
364 DataValue::String(s) => write_escaped_str(out, s),
365 DataValue::Array(items) => {
366 if items.is_empty() {
367 return out.write_bytes(b"[]");
368 }
369 out.write_byte(b'[')?;
370 for (i, item) in items.iter().enumerate() {
371 if i > 0 {
372 out.write_byte(b',')?;
373 }
374 out.write_byte(b'\n')?;
375 write_indent(out, depth + 1)?;
376 write_data_value_pretty(out, item, depth + 1)?;
377 }
378 out.write_byte(b'\n')?;
379 write_indent(out, depth)?;
380 out.write_byte(b']')
381 }
382 DataValue::Object(pairs) => {
383 if pairs.is_empty() {
384 return out.write_bytes(b"{}");
385 }
386 out.write_byte(b'{')?;
387 for (i, (k, v)) in pairs.iter().enumerate() {
388 if i > 0 {
389 out.write_byte(b',')?;
390 }
391 out.write_byte(b'\n')?;
392 write_indent(out, depth + 1)?;
393 write_escaped_str(out, k)?;
394 out.write_bytes(b": ")?;
395 write_data_value_pretty(out, v, depth + 1)?;
396 }
397 out.write_byte(b'\n')?;
398 write_indent(out, depth)?;
399 out.write_byte(b'}')
400 }
401 #[cfg(feature = "datetime")]
402 DataValue::DateTime(d) => write_datetime(out, &d),
403 #[cfg(feature = "datetime")]
404 DataValue::Duration(d) => write_duration(out, &d),
405 }
406}
407
408fn write_owned_value_pretty<S: JsonSink>(
409 out: &mut S,
410 v: &OwnedDataValue,
411 depth: usize,
412) -> Result<(), S::Error> {
413 match v {
414 OwnedDataValue::Null => out.write_bytes(b"null"),
415 OwnedDataValue::Bool(true) => out.write_bytes(b"true"),
416 OwnedDataValue::Bool(false) => out.write_bytes(b"false"),
417 OwnedDataValue::Number(n) => write_number(out, *n),
418 OwnedDataValue::String(s) => write_escaped_str(out, s),
419 OwnedDataValue::Array(items) => {
420 if items.is_empty() {
421 return out.write_bytes(b"[]");
422 }
423 out.write_byte(b'[')?;
424 for (i, item) in items.iter().enumerate() {
425 if i > 0 {
426 out.write_byte(b',')?;
427 }
428 out.write_byte(b'\n')?;
429 write_indent(out, depth + 1)?;
430 write_owned_value_pretty(out, item, depth + 1)?;
431 }
432 out.write_byte(b'\n')?;
433 write_indent(out, depth)?;
434 out.write_byte(b']')
435 }
436 OwnedDataValue::Object(pairs) => {
437 if pairs.is_empty() {
438 return out.write_bytes(b"{}");
439 }
440 out.write_byte(b'{')?;
441 for (i, (k, v)) in pairs.iter().enumerate() {
442 if i > 0 {
443 out.write_byte(b',')?;
444 }
445 out.write_byte(b'\n')?;
446 write_indent(out, depth + 1)?;
447 write_escaped_str(out, k)?;
448 out.write_bytes(b": ")?;
449 write_owned_value_pretty(out, v, depth + 1)?;
450 }
451 out.write_byte(b'\n')?;
452 write_indent(out, depth)?;
453 out.write_byte(b'}')
454 }
455 #[cfg(feature = "datetime")]
456 OwnedDataValue::DateTime(d) => write_datetime(out, d),
457 #[cfg(feature = "datetime")]
458 OwnedDataValue::Duration(d) => write_duration(out, d),
459 }
460}
461
462impl DataValue<'_> {
465 pub fn write_json_into(&self, out: &mut Vec<u8>) {
470 let _ = write_data_value(out, self);
471 }
472
473 pub fn pretty(&self) -> Pretty<'_, DataValue<'_>> {
485 Pretty(self)
486 }
487
488 pub fn write_json_pretty_into(&self, out: &mut Vec<u8>) {
490 let _ = write_data_value_pretty(out, self, 0);
491 }
492
493 pub fn to_json_str_in<'b>(&self, arena: &'b bumpalo::Bump) -> &'b str {
508 let mut out = bumpalo::collections::Vec::new_in(arena);
509 let _ = write_data_value(&mut out, self);
510 into_arena_str(out)
511 }
512
513 pub fn to_json_pretty_str_in<'b>(&self, arena: &'b bumpalo::Bump) -> &'b str {
515 let mut out = bumpalo::collections::Vec::new_in(arena);
516 let _ = write_data_value_pretty(&mut out, self, 0);
517 into_arena_str(out)
518 }
519}
520
521impl OwnedDataValue {
522 pub fn write_json_into(&self, out: &mut Vec<u8>) {
525 let _ = write_owned_value(out, self);
526 }
527
528 pub fn pretty(&self) -> Pretty<'_, OwnedDataValue> {
537 Pretty(self)
538 }
539
540 pub fn write_json_pretty_into(&self, out: &mut Vec<u8>) {
542 let _ = write_owned_value_pretty(out, self, 0);
543 }
544
545 pub fn to_json_str_in<'b>(&self, arena: &'b bumpalo::Bump) -> &'b str {
548 let mut out = bumpalo::collections::Vec::new_in(arena);
549 let _ = write_owned_value(&mut out, self);
550 into_arena_str(out)
551 }
552
553 pub fn to_json_pretty_str_in<'b>(&self, arena: &'b bumpalo::Bump) -> &'b str {
555 let mut out = bumpalo::collections::Vec::new_in(arena);
556 let _ = write_owned_value_pretty(&mut out, self, 0);
557 into_arena_str(out)
558 }
559}
560
561pub struct Pretty<'b, T: ?Sized>(&'b T);
566
567impl fmt::Display for DataValue<'_> {
568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579 let mut sink = FormatterSink::new(f);
580 write_data_value(&mut sink, self)?;
581 sink.flush()
582 }
583}
584
585impl fmt::Display for OwnedDataValue {
586 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
595 let mut sink = FormatterSink::new(f);
596 write_owned_value(&mut sink, self)?;
597 sink.flush()
598 }
599}
600
601impl fmt::Display for Pretty<'_, DataValue<'_>> {
602 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
603 let mut sink = FormatterSink::new(f);
604 write_data_value_pretty(&mut sink, self.0, 0)?;
605 sink.flush()
606 }
607}
608
609impl fmt::Display for Pretty<'_, OwnedDataValue> {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 let mut sink = FormatterSink::new(f);
612 write_owned_value_pretty(&mut sink, self.0, 0)?;
613 sink.flush()
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use super::*;
620 use bumpalo::Bump;
621
622 fn round_trip(s: &str) -> String {
623 let arena = Bump::new();
624 let v = DataValue::from_str(s, &arena).unwrap();
625 v.to_string()
626 }
627
628 #[test]
629 fn primitives() {
630 assert_eq!(round_trip("null"), "null");
631 assert_eq!(round_trip("true"), "true");
632 assert_eq!(round_trip("false"), "false");
633 assert_eq!(round_trip("42"), "42");
634 assert_eq!(round_trip("-7"), "-7");
635 assert_eq!(round_trip("3.5"), "3.5");
636 }
637
638 #[test]
639 fn strings_with_escapes() {
640 assert_eq!(round_trip(r#""hello""#), r#""hello""#);
641 assert_eq!(round_trip(r#""a\nb""#), r#""a\nb""#);
642 assert_eq!(round_trip(r#""a\\b""#), r#""a\\b""#);
643 assert_eq!(round_trip(r#""a\"b""#), r#""a\"b""#);
644 assert_eq!(round_trip(r#""café""#), r#""café""#);
646 }
647
648 #[test]
649 fn control_bytes_render_as_unicode_escapes() {
650 let arena = Bump::new();
651 let v = DataValue::from_str("\"\\u0001\"", &arena).unwrap();
652 assert_eq!(v.to_string(), "\"\\u0001\"");
653 }
654
655 #[test]
656 fn nested_round_trip_matches_serde_json() {
657 let input = r#"{"a":[1,2,{"b":"hi\n","c":null,"d":true}],"e":-3.5,"f":[],"g":{}}"#;
658 let arena = Bump::new();
659 let v = DataValue::from_str(input, &arena).unwrap();
660 let ours = v.to_string();
661 let serde: serde_json::Value = serde_json::from_str(input).unwrap();
662 let theirs = serde_json::to_string(&serde).unwrap();
663 assert_eq!(ours, theirs);
664 }
665
666 #[test]
667 fn long_string_swar_path() {
668 let arena = Bump::new();
669 let s = format!("\"{}\"", "x".repeat(200));
670 let v = DataValue::from_str(&s, &arena).unwrap();
671 assert_eq!(v.to_string(), s);
672 }
673
674 fn assert_display_matches_vec(input: &str) {
680 let arena = Bump::new();
681 let v = DataValue::from_str(input, &arena).unwrap();
682 let mut buf = Vec::new();
683 v.write_json_into(&mut buf);
684 assert_eq!(v.to_string().into_bytes(), buf, "compact mismatch");
685
686 let mut pretty_buf = Vec::new();
687 v.write_json_pretty_into(&mut pretty_buf);
688 assert_eq!(
689 v.pretty().to_string().into_bytes(),
690 pretty_buf,
691 "pretty mismatch"
692 );
693 }
694
695 #[cfg(feature = "datetime")]
696 #[test]
697 fn datetime_emit_matches_display_wire_format() {
698 use crate::datetime::DataDateTime;
699
700 let dt = DataDateTime::parse("2024-01-15T12:30:45Z").unwrap();
701 let later = DataDateTime::parse("2024-01-18T16:35:51Z").unwrap();
702 let du = later.diff(&dt);
703
704 for v in [DataValue::DateTime(dt), DataValue::Duration(du)] {
705 let display = v.to_string();
706 let mut buf = Vec::new();
707 v.write_json_into(&mut buf);
708 assert_eq!(display.into_bytes(), buf);
709
710 let owned = v.to_owned();
711 assert_eq!(owned.to_string(), v.to_string());
712 }
713 assert_eq!(
714 DataValue::DateTime(dt).to_string(),
715 "\"2024-01-15T12:30:45Z\""
716 );
717 assert_eq!(DataValue::Duration(du).to_string(), "\"3d:4h:5m:6s\"");
718 }
719
720 #[test]
721 fn to_json_str_in_matches_to_string() {
722 let inputs = [
723 "null",
724 "[]",
725 r#"{"a":[1,2.5,"hi\n",null,true],"b":{"c":"é€"},"e":-0.125}"#,
726 ];
727 let arena = Bump::new();
728 let out_arena = Bump::new();
730 for input in inputs {
731 let v = DataValue::from_str(input, &arena).unwrap();
732 assert_eq!(v.to_json_str_in(&out_arena), v.to_string());
733 assert_eq!(v.to_json_pretty_str_in(&out_arena), v.pretty().to_string());
734
735 let owned = v.to_owned();
736 assert_eq!(owned.to_json_str_in(&out_arena), owned.to_string());
737 assert_eq!(
738 owned.to_json_pretty_str_in(&out_arena),
739 owned.pretty().to_string()
740 );
741 }
742 let long = format!("\"{}\"", "x".repeat(5000));
744 let v = DataValue::from_str(&long, &arena).unwrap();
745 assert_eq!(v.to_json_str_in(&out_arena), long);
746 }
747
748 #[test]
749 fn display_matches_vec_across_staging_boundaries() {
750 for n in [1, 7, 126, 127, 128, 129, 200, 255, 256, 257, 1000] {
753 assert_display_matches_vec(&format!("\"{}\"", "x".repeat(n)));
754 }
755 for n in [60, 63, 64, 65, 100] {
758 assert_display_matches_vec(&format!("\"{}\"", "é".repeat(n)));
759 assert_display_matches_vec(&format!("\"{}\"", "€".repeat(n)));
760 }
761 assert_display_matches_vec(&format!("\"{}\"", r#"a\n"#.repeat(100)));
763 assert_display_matches_vec(
765 r#"{"a":[1,2.5,"hi\n",null,true],"b":{"c":"é€","d":[[],{}]},"e":-0.125}"#,
766 );
767 }
768
769 #[test]
770 fn non_finite_floats_render_as_null() {
771 let v = DataValue::from_f64(f64::NAN);
772 assert_eq!(v.to_string(), "null");
773 let v = DataValue::from_f64(f64::INFINITY);
774 assert_eq!(v.to_string(), "null");
775 }
776
777 #[test]
778 fn owned_round_trip() {
779 let v: OwnedDataValue = r#"{"name":"alice","age":30}"#.parse().unwrap();
780 let serde: serde_json::Value = serde_json::from_str(&v.to_string()).unwrap();
781 assert_eq!(serde["name"], "alice");
782 assert_eq!(serde["age"], 30);
783 }
784
785 #[test]
786 fn write_json_into_buffer() {
787 let arena = Bump::new();
788 let v = DataValue::from_str(r#"[1,2,3]"#, &arena).unwrap();
789 let mut buf = Vec::new();
790 v.write_json_into(&mut buf);
791 assert_eq!(buf, b"[1,2,3]");
792 }
793
794 #[test]
795 fn pretty_matches_serde_json_pretty() {
796 let input = r#"{"a":[1,2,{"b":"hi","c":null}],"e":-3.5,"f":[],"g":{}}"#;
797 let arena = Bump::new();
798 let v = DataValue::from_str(input, &arena).unwrap();
799 let ours = v.pretty().to_string();
800 let serde: serde_json::Value = serde_json::from_str(input).unwrap();
801 let theirs = serde_json::to_string_pretty(&serde).unwrap();
802 assert_eq!(ours, theirs);
803 }
804
805 #[test]
806 fn pretty_owned_matches_serde_json_pretty() {
807 let input = r#"{"a":[1,2,{"b":"hi","c":null}],"e":-3.5,"f":[],"g":{}}"#;
808 let v: OwnedDataValue = input.parse().unwrap();
809 let serde: serde_json::Value = serde_json::from_str(input).unwrap();
810 assert_eq!(
811 v.pretty().to_string(),
812 serde_json::to_string_pretty(&serde).unwrap()
813 );
814 }
815
816 #[test]
817 fn pretty_empty_collections_inline() {
818 let arena = Bump::new();
819 let v = DataValue::from_str(r#"{"a":[],"b":{}}"#, &arena).unwrap();
820 assert_eq!(v.pretty().to_string(), "{\n \"a\": [],\n \"b\": {}\n}");
821 }
822
823 #[test]
824 fn pretty_deep_indent_beyond_64_spaces() {
825 let arena = Bump::new();
828 let mut s = String::new();
829 for _ in 0..35 {
830 s.push('[');
831 }
832 s.push('1');
833 for _ in 0..35 {
834 s.push(']');
835 }
836 let v = DataValue::from_str(&s, &arena).unwrap();
837 let ours = v.pretty().to_string();
838 let serde: serde_json::Value = serde_json::from_str(&s).unwrap();
839 assert_eq!(ours, serde_json::to_string_pretty(&serde).unwrap());
840 }
841}