Skip to main content

deser_debug/
lib.rs

1//! This library takes a [`Serialize`] and formats it with [`core::fmt`] like
2//! the [`Debug`](core::fmt::Debug) implementation of Rust types would.
3//!
4//! The Rust shape of the values (struct and variant names, `Option`,
5//! tuples, ...) is taken from their description (see
6//! [`Describe`]).  For types which describe
7//! themselves the output looks like the one of `#[derive(Debug)]`:
8//!
9//! ```
10//! use deser::Serialize;
11//! use deser_debug::ToDebug;
12//!
13//! #[derive(Serialize, Debug)]
14//! struct Point {
15//!     x: i32,
16//!     y: Option<i32>,
17//! }
18//!
19//! let point = Point { x: 1, y: Some(2) };
20//! assert_eq!(ToDebug::new(&point).to_string(), format!("{:?}", point));
21//! assert_eq!(
22//!     ToDebug::new(&point).to_string(),
23//!     "Point { x: 1, y: Some(2) }"
24//! );
25//! ```
26//!
27//! The names are the ones used when serializing: renamed types, variants
28//! and fields are shown with their new names, variants named by integers
29//! are shown as numbers and the fields of flattened structs are shown in
30//! the struct they are flattened into.  For types without such attributes
31//! the output is the same as the one of `#[derive(Debug)]`.
32//!
33//! As all floats are `f64` in the data model, `f32` values are formatted
34//! as the `f64` they widen to.
35#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
36#![cfg_attr(not(test), no_std)]
37
38extern crate alloc;
39
40use alloc::string::String;
41use alloc::vec::Vec;
42use core::fmt;
43
44use deser_core::ser::{Describe, Serialize, SerializeDriver, Variant, VariantKind, VariantRepr};
45use deser_core::{Atom, Event};
46
47/// Serializes a serializable value to `Debug` format.
48pub struct ToDebug {
49    root: Node,
50}
51
52impl fmt::Display for ToDebug {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        fmt::Debug::fmt(self, f)
55    }
56}
57
58impl fmt::Debug for ToDebug {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        fmt::Debug::fmt(&Render(&self.root, &self.root.desc), f)
61    }
62}
63
64impl ToDebug {
65    /// Creates a new [`ToDebug`] object from a serializable value.
66    ///
67    /// # Panics
68    ///
69    /// Panics if the value fails to serialize.
70    pub fn new(value: &dyn Serialize) -> ToDebug {
71        let mut builder = Builder::default();
72        SerializeDriver::new(value)
73            .drive_described(|event, value, state| {
74                builder.event(event, value, state.is_map_key());
75                Ok(())
76            })
77            .unwrap();
78        ToDebug {
79            root: builder.root.expect("no value was serialized"),
80        }
81    }
82}
83
84/// A part of the description of a value.
85#[derive(Debug)]
86enum Desc {
87    Structure(String),
88    Newtype(String),
89    TupleStruct(String),
90    UnitStruct(String),
91    Variant {
92        name: String,
93        kind: VariantKind,
94        repr: Repr,
95    },
96    Some,
97    None,
98    Tuple,
99    Set,
100}
101
102/// An owned [`VariantRepr`].
103#[derive(Debug)]
104enum Repr {
105    External,
106    Internal { tag: String },
107    Adjacent { content: String },
108    Untagged,
109}
110
111/// Collects the description of a value.
112#[derive(Default)]
113struct Collector(Vec<Desc>);
114
115impl Describe for Collector {
116    fn structure(&mut self, name: &str) {
117        self.0.push(Desc::Structure(name.into()));
118    }
119
120    fn newtype(&mut self, name: &str) {
121        self.0.push(Desc::Newtype(name.into()));
122    }
123
124    fn tuple_struct(&mut self, name: &str) {
125        self.0.push(Desc::TupleStruct(name.into()));
126    }
127
128    fn unit_struct(&mut self, name: &str) {
129        self.0.push(Desc::UnitStruct(name.into()));
130    }
131
132    fn variant(&mut self, variant: &Variant<'_>) {
133        let repr = match variant.repr {
134            VariantRepr::Internal { tag } => Repr::Internal { tag: tag.into() },
135            VariantRepr::Adjacent { content, .. } => Repr::Adjacent {
136                content: content.into(),
137            },
138            VariantRepr::Untagged => Repr::Untagged,
139            _ => Repr::External,
140        };
141        self.0.push(Desc::Variant {
142            name: variant.name.into(),
143            kind: variant.kind,
144            repr,
145        });
146    }
147
148    fn some(&mut self) {
149        self.0.push(Desc::Some);
150    }
151
152    fn none(&mut self) {
153        self.0.push(Desc::None);
154    }
155
156    fn tuple(&mut self) {
157        self.0.push(Desc::Tuple);
158    }
159
160    fn set(&mut self) {
161        self.0.push(Desc::Set);
162    }
163}
164
165/// A serialized value with its description.
166#[derive(Debug)]
167struct Node {
168    desc: Vec<Desc>,
169    kind: NodeKind,
170}
171
172#[derive(Debug)]
173enum NodeKind {
174    Atom(Atom<'static>),
175    Map(Vec<(Node, Node)>),
176    Seq(Vec<Node>),
177}
178
179impl Node {
180    /// Returns the value of an entry of a map node by string key.
181    fn get(&self, key: &str) -> Option<&Node> {
182        match self.kind {
183            NodeKind::Map(ref entries) => entries
184                .iter()
185                .find(|(k, _)| k.as_str() == Some(key))
186                .map(|(_, v)| v),
187            _ => None,
188        }
189    }
190
191    fn as_str(&self) -> Option<&str> {
192        match self.kind {
193            NodeKind::Atom(ref atom) => atom.as_str(),
194            _ => None,
195        }
196    }
197}
198
199/// Builds the tree of nodes from the events.
200#[derive(Default)]
201struct Builder {
202    stack: Vec<Node>,
203    // keys of maps waiting for their value
204    keys: Vec<Option<Node>>,
205    root: Option<Node>,
206}
207
208impl Builder {
209    fn event(&mut self, event: Event<'_>, value: &dyn Serialize, is_key: bool) {
210        let describe = |value: &dyn Serialize| {
211            // keys are not described, the parent describes them
212            let mut collector = Collector::default();
213            if !is_key {
214                value.describe(&mut collector);
215            }
216            collector.0
217        };
218        match event {
219            Event::Atom(atom) => {
220                let node = Node {
221                    desc: describe(value),
222                    kind: NodeKind::Atom(atom.to_static()),
223                };
224                self.push(node);
225            }
226            Event::MapStart(_) => {
227                self.stack.push(Node {
228                    desc: describe(value),
229                    kind: NodeKind::Map(Vec::new()),
230                });
231                self.keys.push(None);
232            }
233            Event::SeqStart(_) => {
234                self.stack.push(Node {
235                    desc: describe(value),
236                    kind: NodeKind::Seq(Vec::new()),
237                });
238                self.keys.push(None);
239            }
240            Event::MapEnd | Event::SeqEnd => {
241                self.keys.pop();
242                let node = self.stack.pop().expect("unbalanced events");
243                self.push(node);
244            }
245        }
246    }
247
248    fn push(&mut self, node: Node) {
249        let Some(parent) = self.stack.last_mut() else {
250            self.root = Some(node);
251            return;
252        };
253        match parent.kind {
254            NodeKind::Seq(ref mut items) => items.push(node),
255            NodeKind::Map(ref mut entries) => {
256                let key = self.keys.last_mut().unwrap();
257                match key.take() {
258                    Some(key) => entries.push((key, node)),
259                    None => *key = Some(node),
260                }
261            }
262            NodeKind::Atom(_) => unreachable!(),
263        }
264    }
265}
266
267/// Renders a node with the given (remaining) description.
268struct Render<'a>(&'a Node, &'a [Desc]);
269
270impl<'a> Render<'a> {
271    /// Renders the node without description.
272    fn plain(node: &'a Node) -> Render<'a> {
273        Render(node, &node.desc)
274    }
275}
276
277impl fmt::Debug for Render<'_> {
278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279        let Render(node, desc) = *self;
280        let Some((first, rest)) = desc.split_first() else {
281            return render_undescribed(node, f);
282        };
283        match *first {
284            Desc::Some => f.debug_tuple("Some").field(&Render(node, rest)).finish(),
285            Desc::None => f.write_str("None"),
286            Desc::Newtype(ref name) => f.debug_tuple(name).field(&Render(node, rest)).finish(),
287            Desc::Structure(ref name) => render_struct(name, node, None, f),
288            Desc::TupleStruct(ref name) => render_tuple(name, node, f),
289            Desc::UnitStruct(ref name) => f.write_str(name),
290            Desc::Tuple => render_tuple("", node, f),
291            Desc::Set => match node.kind {
292                NodeKind::Seq(ref items) => f
293                    .debug_set()
294                    .entries(items.iter().map(Render::plain))
295                    .finish(),
296                _ => render_undescribed(node, f),
297            },
298            Desc::Variant {
299                ref name,
300                kind,
301                ref repr,
302            } => render_variant(name, kind, repr, node, rest, f),
303        }
304    }
305}
306
307fn render_undescribed(node: &Node, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308    match node.kind {
309        NodeKind::Atom(ref atom) => render_atom(atom, f),
310        NodeKind::Map(ref entries) => f
311            .debug_map()
312            .entries(
313                entries
314                    .iter()
315                    .map(|(k, v)| (Render::plain(k), Render::plain(v))),
316            )
317            .finish(),
318        NodeKind::Seq(ref items) => f
319            .debug_list()
320            .entries(items.iter().map(Render::plain))
321            .finish(),
322    }
323}
324
325fn render_atom(atom: &Atom, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326    match *atom {
327        Atom::Null => f.write_str("()"),
328        Atom::Bool(v) => fmt::Debug::fmt(&v, f),
329        Atom::Str(ref v) | Atom::Lexical(ref v) => fmt::Debug::fmt(v, f),
330        Atom::Bytes(ref v) => fmt::Debug::fmt(v.data(), f),
331        Atom::Char(v) => fmt::Debug::fmt(&v, f),
332        Atom::U64(v) => fmt::Debug::fmt(&v, f),
333        Atom::I64(v) => fmt::Debug::fmt(&v, f),
334        Atom::F32(v) => fmt::Debug::fmt(&v, f),
335        Atom::F64(v) => fmt::Debug::fmt(&v, f),
336        Atom::Ext(ref v) => fmt::Debug::fmt(v, f),
337        Atom::Implicit(ref v) => render_atom(&v.value().to_atom(), f),
338        _ => f.write_str("?"),
339    }
340}
341
342/// Renders a map as struct, optionally skipping a key (the tag).
343fn render_struct(
344    name: &str,
345    node: &Node,
346    skip: Option<&str>,
347    f: &mut fmt::Formatter<'_>,
348) -> fmt::Result {
349    let NodeKind::Map(ref entries) = node.kind else {
350        return render_undescribed(node, f);
351    };
352    let mut s = f.debug_struct(name);
353    for (key, value) in entries {
354        match key.as_str() {
355            Some(key) if Some(key) == skip => {}
356            Some(key) => {
357                s.field(key, &Render::plain(value));
358            }
359            None => {
360                s.field("?", &Render::plain(value));
361            }
362        }
363    }
364    s.finish()
365}
366
367/// Renders a map as struct without the tag.
368struct StructWithout<'a>(&'a str, &'a Node, &'a str);
369
370impl fmt::Debug for StructWithout<'_> {
371    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372        render_struct(self.0, self.1, Some(self.2), f)
373    }
374}
375
376/// Renders a sequence as tuple.
377fn render_tuple(name: &str, node: &Node, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378    let NodeKind::Seq(ref items) = node.kind else {
379        return render_undescribed(node, f);
380    };
381    let mut t = f.debug_tuple(name);
382    for item in items {
383        t.field(&Render::plain(item));
384    }
385    t.finish()
386}
387
388/// Renders the content of a variant.
389fn render_content(
390    name: &str,
391    kind: VariantKind,
392    content: &Node,
393    rest: &[Desc],
394    f: &mut fmt::Formatter<'_>,
395) -> fmt::Result {
396    match kind {
397        VariantKind::Unit => f.write_str(name),
398        VariantKind::Newtype => f.debug_tuple(name).field(&Render(content, rest)).finish(),
399        VariantKind::Tuple => render_tuple(name, content, f),
400        _ => render_struct(name, content, None, f),
401    }
402}
403
404fn render_variant(
405    name: &str,
406    kind: VariantKind,
407    repr: &Repr,
408    node: &Node,
409    rest: &[Desc],
410    f: &mut fmt::Formatter<'_>,
411) -> fmt::Result {
412    if kind == VariantKind::Unit {
413        return f.write_str(name);
414    }
415    match *repr {
416        Repr::External => match node.kind {
417            NodeKind::Map(ref entries) if entries.len() == 1 => {
418                let content = &entries[0].1;
419                render_content(name, kind, content, &content.desc, f)
420            }
421            _ => render_undescribed(node, f),
422        },
423        // the fields of the content are merged with the tag
424        Repr::Internal { ref tag } => match (kind, rest) {
425            (VariantKind::Newtype, [Desc::Structure(inner), ..]) => f
426                .debug_tuple(name)
427                .field(&StructWithout(inner, node, tag))
428                .finish(),
429            (VariantKind::Newtype | VariantKind::Struct, _) => {
430                render_struct(name, node, Some(tag), f)
431            }
432            _ => render_undescribed(node, f),
433        },
434        Repr::Adjacent { ref content } => match node.get(content) {
435            Some(content) => render_content(name, kind, content, &content.desc, f),
436            None => render_undescribed(node, f),
437        },
438        // the content is serialized in place of the enum
439        Repr::Untagged => render_content(name, kind, node, rest, f),
440    }
441}
442
443#[cfg(test)]
444mod tests {
445    use super::*;
446
447    #[test]
448    fn test_debug_format() {
449        let mut m = alloc::collections::BTreeMap::new();
450        m.insert(true, vec![vec![&b"x"[..], b"yyy"], vec![b"zzzz\x00\x01"]]);
451        m.insert(false, vec![]);
452        assert_eq!(ToDebug::new(&m).to_string(), format!("{:?}", m));
453    }
454
455    #[test]
456    fn test_debug_format_ext() {
457        assert_eq!(
458            ToDebug::new(&vec![u128::MAX, 1]).to_string(),
459            format!("[{}, 1]", u128::MAX)
460        );
461    }
462
463    #[test]
464    fn test_std_types() {
465        fn check<T: Serialize + fmt::Debug>(value: T) {
466            assert_eq!(ToDebug::new(&value).to_string(), format!("{:?}", value));
467            assert_eq!(
468                format!("{:#?}", ToDebug::new(&value)),
469                format!("{:#?}", value)
470            );
471        }
472        check(42u32);
473        check("hello");
474        check('x');
475        check(Some(Some(1i64)));
476        check(None::<u32>);
477        check((1, "two", Some(3.5)));
478        check(vec![Some(1), None]);
479        check(alloc::collections::BTreeSet::from([1, 2, 3]));
480        check(alloc::collections::BTreeMap::from([("a", (1, 2))]));
481        check(Box::new(Some(vec![true])));
482        check(());
483    }
484}