1use std::fmt;
4use std::sync::atomic::{self, AtomicUsize};
5
6use deser::ser::{Serialize, SerializeDriver};
7use deser::{Atom, Event};
8
9pub struct ToDebug {
11 events: Vec<(Event<'static>, Option<String>)>,
12}
13
14impl fmt::Display for ToDebug {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 fmt::Debug::fmt(&Helper(&self.events, AtomicUsize::default()), f)
17 }
18}
19
20impl fmt::Debug for ToDebug {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 fmt::Debug::fmt(&Helper(&self.events, AtomicUsize::default()), f)
23 }
24}
25
26impl ToDebug {
27 pub fn new(value: &dyn Serialize) -> ToDebug {
29 let mut events = Vec::new();
30 let mut driver = SerializeDriver::new(value);
31 while let Some((event, descriptor, _)) = driver.next().unwrap() {
32 events.push((event.to_static(), descriptor.name().map(|x| x.to_string())));
33 }
34 ToDebug { events }
35 }
36}
37
38fn dump<'a, 'f>(
39 tokens: &'a [(Event<'a>, Option<String>)],
40 f: &'f mut fmt::Formatter<'_>,
41) -> Result<&'a [(Event<'a>, Option<String>)], fmt::Error> {
42 if let Some((first, mut rest)) = tokens.split_first() {
43 match first.0 {
44 Event::Atom(Atom::Null) => fmt::Debug::fmt(&(), f)?,
45 Event::Atom(Atom::Bool(v)) => fmt::Debug::fmt(&v, f)?,
46 Event::Atom(Atom::Str(ref v)) => fmt::Debug::fmt(v, f)?,
47 Event::Atom(Atom::Bytes(ref v)) => {
48 write!(f, "b\"")?;
49 for &b in &v[..] {
50 if b == b'\n' {
51 write!(f, "\\n")?;
52 } else if b == b'\r' {
53 write!(f, "\\r")?;
54 } else if b == b'\t' {
55 write!(f, "\\t")?;
56 } else if b == b'\\' || b == b'"' {
57 write!(f, "\\{}", b as char)?;
58 } else if b == b'\0' {
59 write!(f, "\\0")?;
60 } else if (0x20..0x7f).contains(&b) {
61 write!(f, "{}", b as char)?;
62 } else {
63 write!(f, "\\x{:02x}", b)?;
64 }
65 }
66 write!(f, "\"")?;
67 }
68 Event::Atom(Atom::Char(v)) => fmt::Debug::fmt(&v, f)?,
69 Event::Atom(Atom::U64(v)) => fmt::Debug::fmt(&v, f)?,
70 Event::Atom(Atom::I64(v)) => fmt::Debug::fmt(&v, f)?,
71 Event::Atom(Atom::F64(v)) => fmt::Debug::fmt(&v, f)?,
72 Event::Atom(..) => f.debug_struct("?").finish()?,
73 Event::MapStart => {
74 if let Some(ref name) = first.1 {
75 write!(f, "{} ", name)?;
76 }
77 let mut map = f.debug_map();
78 let mut is_key = true;
79 loop {
80 if rest.get(0).map_or(false, |x| matches!(x.0, Event::MapEnd)) {
81 rest = &rest[1..];
82 break;
83 }
84 let inner = Helper(rest, AtomicUsize::default());
85 if is_key {
86 map.key(&inner);
87 } else {
88 map.value(&inner);
89 }
90 is_key = !is_key;
91 rest = &rest[inner.1.load(atomic::Ordering::Relaxed)..];
92 }
93 map.finish()?;
94 }
95 Event::MapEnd => unreachable!(),
96 Event::SeqStart => {
97 if let Some(ref name) = first.1 {
98 if name != "Vec" && name != "slice" {
99 write!(f, "{} ", name)?;
100 }
101 }
102 let mut list = f.debug_list();
103 loop {
104 if rest.get(0).map_or(false, |x| matches!(x.0, Event::SeqEnd)) {
105 rest = &rest[1..];
106 break;
107 }
108 let inner = Helper(rest, AtomicUsize::default());
109 list.entry(&inner);
110 rest = &rest[inner.1.load(atomic::Ordering::Relaxed)..];
111 }
112 list.finish()?;
113 }
114 Event::SeqEnd => unreachable!(),
115 }
116 Ok(rest)
117 } else {
118 Ok(tokens)
119 }
120}
121
122struct Helper<'a>(&'a [(Event<'a>, Option<String>)], AtomicUsize);
123
124impl<'a> fmt::Debug for Helper<'a> {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 let new = dump(self.0, f)?;
127 self.1
128 .store(self.0.len() - new.len(), atomic::Ordering::Relaxed);
129 Ok(())
130 }
131}
132
133#[test]
134fn test_debug_format() {
135 let mut m = std::collections::BTreeMap::new();
136 m.insert(true, vec![vec![&b"x"[..], b"yyy"], vec![b"zzzz\x00\x01"]]);
137 m.insert(false, vec![]);
138
139 assert_eq!(
140 ToDebug::new(&m).to_string(),
141 "BTreeMap {false: [], true: [[b\"x\", b\"yyy\"], [b\"zzzz\\0\\x01\"]]}"
142 );
143}