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::SerializeRef;
45use deser_core::ser::{
46    Describe, EventSink, Serialize, SerializeDriver, Variant, VariantKind, VariantRepr,
47};
48use deser_core::{Atom, Error, Event, State};
49
50/// Serializes a serializable value to `Debug` format.
51pub struct ToDebug {
52    root: Node,
53}
54
55impl fmt::Display for ToDebug {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        fmt::Debug::fmt(self, f)
58    }
59}
60
61impl fmt::Debug for ToDebug {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        fmt::Debug::fmt(&Render(&self.root, &self.root.desc), f)
64    }
65}
66
67impl ToDebug {
68    /// Creates a new [`ToDebug`] object from a serializable value.
69    ///
70    /// # Panics
71    ///
72    /// Panics if the value fails to serialize.
73    pub fn new<T: Serialize + ?Sized>(value: &T) -> ToDebug {
74        let mut builder = Builder::default();
75        SerializeDriver::new(&value)
76            .drive_sink(&mut builder)
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 EventSink for Builder {
209    const DESCRIBED: bool = true;
210
211    fn event(
212        &mut self,
213        event: Event<'_>,
214        value: SerializeRef<'_>,
215        state: &mut State,
216    ) -> Result<(), Error> {
217        Builder::event(self, event, value, state.is_map_key());
218        Ok(())
219    }
220}
221
222impl Builder {
223    fn event(&mut self, event: Event<'_>, value: SerializeRef<'_>, is_key: bool) {
224        let describe = |value: SerializeRef<'_>| {
225            // keys are not described, the parent describes them
226            let mut collector = Collector::default();
227            if !is_key {
228                value.describe(&mut collector);
229            }
230            collector.0
231        };
232        match event {
233            Event::Atom(atom) => {
234                let node = Node {
235                    desc: describe(value),
236                    kind: NodeKind::Atom(atom.to_static()),
237                };
238                self.push(node);
239            }
240            Event::MapStart(_) => {
241                self.stack.push(Node {
242                    desc: describe(value),
243                    kind: NodeKind::Map(Vec::new()),
244                });
245                self.keys.push(None);
246            }
247            Event::SeqStart(_) => {
248                self.stack.push(Node {
249                    desc: describe(value),
250                    kind: NodeKind::Seq(Vec::new()),
251                });
252                self.keys.push(None);
253            }
254            Event::MapEnd | Event::SeqEnd => {
255                self.keys.pop();
256                let node = self.stack.pop().expect("unbalanced events");
257                self.push(node);
258            }
259        }
260    }
261
262    fn push(&mut self, node: Node) {
263        let Some(parent) = self.stack.last_mut() else {
264            self.root = Some(node);
265            return;
266        };
267        match parent.kind {
268            NodeKind::Seq(ref mut items) => items.push(node),
269            NodeKind::Map(ref mut entries) => {
270                let key = self.keys.last_mut().unwrap();
271                match key.take() {
272                    Some(key) => entries.push((key, node)),
273                    None => *key = Some(node),
274                }
275            }
276            NodeKind::Atom(_) => unreachable!(),
277        }
278    }
279}
280
281/// Renders a node with the given (remaining) description.
282struct Render<'a>(&'a Node, &'a [Desc]);
283
284impl<'a> Render<'a> {
285    /// Renders the node without description.
286    fn plain(node: &'a Node) -> Render<'a> {
287        Render(node, &node.desc)
288    }
289}
290
291impl fmt::Debug for Render<'_> {
292    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293        let Render(node, desc) = *self;
294        let Some((first, rest)) = desc.split_first() else {
295            return render_undescribed(node, f);
296        };
297        match *first {
298            Desc::Some => f.debug_tuple("Some").field(&Render(node, rest)).finish(),
299            Desc::None => f.write_str("None"),
300            Desc::Newtype(ref name) => f.debug_tuple(name).field(&Render(node, rest)).finish(),
301            Desc::Structure(ref name) => render_struct(name, node, None, f),
302            Desc::TupleStruct(ref name) => render_tuple(name, node, f),
303            Desc::UnitStruct(ref name) => f.write_str(name),
304            Desc::Tuple => render_tuple("", node, f),
305            Desc::Set => match node.kind {
306                NodeKind::Seq(ref items) => f
307                    .debug_set()
308                    .entries(items.iter().map(Render::plain))
309                    .finish(),
310                _ => render_undescribed(node, f),
311            },
312            Desc::Variant {
313                ref name,
314                kind,
315                ref repr,
316            } => render_variant(name, kind, repr, node, rest, f),
317        }
318    }
319}
320
321fn render_undescribed(node: &Node, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322    match node.kind {
323        NodeKind::Atom(ref atom) => render_atom(atom, f),
324        NodeKind::Map(ref entries) => f
325            .debug_map()
326            .entries(
327                entries
328                    .iter()
329                    .map(|(k, v)| (Render::plain(k), Render::plain(v))),
330            )
331            .finish(),
332        NodeKind::Seq(ref items) => f
333            .debug_list()
334            .entries(items.iter().map(Render::plain))
335            .finish(),
336    }
337}
338
339fn render_atom(atom: &Atom, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340    match *atom {
341        Atom::Null => f.write_str("()"),
342        Atom::Bool(v) => fmt::Debug::fmt(&v, f),
343        Atom::Str(ref v) | Atom::Lexical(ref v) => fmt::Debug::fmt(v, f),
344        Atom::Bytes(ref v) => fmt::Debug::fmt(v.data(), f),
345        Atom::Char(v) => fmt::Debug::fmt(&v, f),
346        Atom::U64(v) => fmt::Debug::fmt(&v, f),
347        Atom::I64(v) => fmt::Debug::fmt(&v, f),
348        Atom::F32(v) => fmt::Debug::fmt(&v, f),
349        Atom::F64(v) => fmt::Debug::fmt(&v, f),
350        Atom::Ext(ref v) => fmt::Debug::fmt(v, f),
351        Atom::Implicit(ref v) => render_atom(&v.value().to_atom(), f),
352        _ => f.write_str("?"),
353    }
354}
355
356/// Renders a map as struct, optionally skipping a key (the tag).
357fn render_struct(
358    name: &str,
359    node: &Node,
360    skip: Option<&str>,
361    f: &mut fmt::Formatter<'_>,
362) -> fmt::Result {
363    let NodeKind::Map(ref entries) = node.kind else {
364        return render_undescribed(node, f);
365    };
366    let mut s = f.debug_struct(name);
367    for (key, value) in entries {
368        match key.as_str() {
369            Some(key) if Some(key) == skip => {}
370            Some(key) => {
371                s.field(key, &Render::plain(value));
372            }
373            None => {
374                s.field("?", &Render::plain(value));
375            }
376        }
377    }
378    s.finish()
379}
380
381/// Renders a map as struct without the tag.
382struct StructWithout<'a>(&'a str, &'a Node, &'a str);
383
384impl fmt::Debug for StructWithout<'_> {
385    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386        render_struct(self.0, self.1, Some(self.2), f)
387    }
388}
389
390/// Renders a sequence as tuple.
391fn render_tuple(name: &str, node: &Node, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392    let NodeKind::Seq(ref items) = node.kind else {
393        return render_undescribed(node, f);
394    };
395    let mut t = f.debug_tuple(name);
396    for item in items {
397        t.field(&Render::plain(item));
398    }
399    t.finish()
400}
401
402/// Renders the content of a variant.
403fn render_content(
404    name: &str,
405    kind: VariantKind,
406    content: &Node,
407    rest: &[Desc],
408    f: &mut fmt::Formatter<'_>,
409) -> fmt::Result {
410    match kind {
411        VariantKind::Unit => f.write_str(name),
412        VariantKind::Newtype => f.debug_tuple(name).field(&Render(content, rest)).finish(),
413        VariantKind::Tuple => render_tuple(name, content, f),
414        _ => render_struct(name, content, None, f),
415    }
416}
417
418fn render_variant(
419    name: &str,
420    kind: VariantKind,
421    repr: &Repr,
422    node: &Node,
423    rest: &[Desc],
424    f: &mut fmt::Formatter<'_>,
425) -> fmt::Result {
426    if kind == VariantKind::Unit {
427        return f.write_str(name);
428    }
429    match *repr {
430        Repr::External => match node.kind {
431            NodeKind::Map(ref entries) if entries.len() == 1 => {
432                let content = &entries[0].1;
433                render_content(name, kind, content, &content.desc, f)
434            }
435            _ => render_undescribed(node, f),
436        },
437        // the fields of the content are merged with the tag
438        Repr::Internal { ref tag } => match (kind, rest) {
439            (VariantKind::Newtype, [Desc::Structure(inner), ..]) => f
440                .debug_tuple(name)
441                .field(&StructWithout(inner, node, tag))
442                .finish(),
443            (VariantKind::Newtype | VariantKind::Struct, _) => {
444                render_struct(name, node, Some(tag), f)
445            }
446            _ => render_undescribed(node, f),
447        },
448        Repr::Adjacent { ref content } => match node.get(content) {
449            Some(content) => render_content(name, kind, content, &content.desc, f),
450            None => render_undescribed(node, f),
451        },
452        // the content is serialized in place of the enum
453        Repr::Untagged => render_content(name, kind, node, rest, f),
454    }
455}
456
457#[cfg(test)]
458mod tests {
459    use super::*;
460
461    #[test]
462    fn test_debug_format() {
463        let mut m = alloc::collections::BTreeMap::new();
464        m.insert(true, vec![vec![&b"x"[..], b"yyy"], vec![b"zzzz\x00\x01"]]);
465        m.insert(false, vec![]);
466        assert_eq!(ToDebug::new(&m).to_string(), format!("{:?}", m));
467    }
468
469    #[test]
470    fn test_debug_format_ext() {
471        assert_eq!(
472            ToDebug::new(&vec![u128::MAX, 1]).to_string(),
473            format!("[{}, 1]", u128::MAX)
474        );
475    }
476
477    #[test]
478    fn test_std_types() {
479        fn check<T: Serialize + fmt::Debug>(value: T) {
480            assert_eq!(ToDebug::new(&value).to_string(), format!("{:?}", value));
481            assert_eq!(
482                format!("{:#?}", ToDebug::new(&value)),
483                format!("{:#?}", value)
484            );
485        }
486        check(42u32);
487        check("hello");
488        check('x');
489        check(Some(Some(1i64)));
490        check(None::<u32>);
491        check((1, "two", Some(3.5)));
492        check(vec![Some(1), None]);
493        check(alloc::collections::BTreeSet::from([1, 2, 3]));
494        check(alloc::collections::BTreeMap::from([("a", (1, 2))]));
495        check(Box::new(Some(vec![true])));
496        check(());
497    }
498}