1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use crate::{DebugPls, Formatter};
/// A helper designed to assist with creation of
/// [`DebugPls`] implementations for maps.
///
/// # Examples
///
/// ```rust
/// use dbg_pls::{pretty, DebugPls, Formatter};
/// use std::collections::BTreeMap;
///
/// struct Foo(BTreeMap<String, i32>);
///
/// impl DebugPls for Foo {
/// fn fmt(&self, f: Formatter) {
/// f.debug_map().entries(&self.0).finish()
/// }
/// }
/// let mut value = Foo(BTreeMap::from([
/// ("Hello".to_string(), 5),
/// ("World".to_string(), 10),
/// ]));
/// assert_eq!(
/// format!("{}", pretty(&value)),
/// "{
/// \"Hello\" = 5;
/// \"World\" = 10;
/// }",
/// );
/// ```
pub struct DebugMap<'a> {
formatter: Formatter<'a>,
set: syn::Block,
key: Option<syn::Expr>,
}
impl<'a> DebugMap<'a> {
pub(crate) fn new(formatter: Formatter<'a>) -> Self {
DebugMap {
formatter,
set: syn::Block {
brace_token: syn::token::Brace::default(),
stmts: vec![],
},
key: None,
}
}
/// Adds the key part to the map output.
///
/// # Panics
///
/// `key` must be called before `value` and each call to `key` must be followed
/// by a corresponding call to `value`. Otherwise this method will panic.
#[must_use]
pub fn key(mut self, key: &dyn DebugPls) -> Self {
assert!(
self.key.replace(Formatter::process(key)).is_none(),
"attempted to begin a new map entry without completing the previous one"
);
self
}
/// Adds the value part to the map output.
///
/// # Panics
///
/// `key` must be called before `value` and each call to `key` must be followed
/// by a corresponding call to `value`. Otherwise this method will panic.
#[must_use]
pub fn value(mut self, value: &dyn DebugPls) -> Self {
let key = self
.key
.take()
.expect("attempted to format a map value before its key");
let value = Formatter::process(value);
let entry = syn::ExprAssign {
attrs: vec![],
left: Box::new(key),
eq_token: syn::token::Eq::default(),
right: Box::new(value),
};
self.set
.stmts
.push(syn::Stmt::Semi(entry.into(), syn::token::Semi::default()));
self
}
/// Adds the entry to the map output.
#[must_use]
pub fn entry(self, key: &dyn DebugPls, value: &dyn DebugPls) -> Self {
self.key(key).value(value)
}
/// Adds all the entries to the map output.
#[must_use]
pub fn entries<K, V, I>(self, entries: I) -> Self
where
K: DebugPls,
V: DebugPls,
I: IntoIterator<Item = (K, V)>,
{
entries
.into_iter()
.fold(self, |f, (key, value)| f.entry(&key, &value))
}
/// Closes off the map.
pub fn finish(self) {
self.formatter.write_expr(syn::ExprBlock {
attrs: vec![],
label: None,
block: self.set,
});
}
}