use super::{
Hex,
Map,
Seq,
Tuple,
Value,
};
use std::fmt::{
Debug,
Display,
Formatter,
LowerHex,
Result,
};
struct DisplayValue<'a>(&'a Value);
impl<'a> Debug for DisplayValue<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match &self.0 {
Value::Bool(boolean) => <bool as Debug>::fmt(boolean, f),
Value::Char(character) => <char as Debug>::fmt(character, f),
Value::UInt(uint) => <u128 as Display>::fmt(uint, f),
Value::Int(integer) => <i128 as Display>::fmt(integer, f),
Value::Map(map) => <DisplayMap as Debug>::fmt(&DisplayMap(map), f),
Value::Tuple(tuple) => <DisplayTuple as Debug>::fmt(&DisplayTuple(tuple), f),
Value::String(string) => <String as Display>::fmt(string, f),
Value::Seq(seq) => <DisplaySeq as Debug>::fmt(&DisplaySeq(seq), f),
Value::Hex(hex) => <Hex as Debug>::fmt(hex, f),
Value::Literal(literal) => <String as Display>::fmt(literal, f),
Value::Unit => write!(f, "()"),
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Value::String(string) => <String as Display>::fmt(string, f),
value => <DisplayValue as Debug>::fmt(&DisplayValue(value), f),
}
}
}
struct DisplayMap<'a>(&'a Map);
impl<'a> Debug for DisplayMap<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self.0.ident {
Some(ref name) => {
let mut builder = f.debug_struct(name);
for (name, value) in self.0.map.iter() {
builder.field(&format!("{name}"), &DisplayValue(value));
}
builder.finish()
}
None => {
let mut builder = f.debug_map();
for (name, value) in self.0.map.iter() {
builder.entry(name, &DisplayValue(value));
}
builder.finish()
}
}
}
}
struct DisplayTuple<'a>(&'a Tuple);
impl<'a> Debug for DisplayTuple<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let name = self.0.ident.as_ref().map_or("", |s| s.as_str());
let mut builder = f.debug_tuple(name);
for value in self.0.values.iter() {
builder.field(&DisplayValue(value));
}
builder.finish()
}
}
struct DisplaySeq<'a>(&'a Seq);
impl<'a> Debug for DisplaySeq<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let mut builder = f.debug_list();
for elem in &self.0.elems {
builder.entry(&DisplayValue(elem));
}
builder.finish()
}
}
impl Debug for Hex {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{self:#x}")
}
}
impl LowerHex for Hex {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
if f.alternate() {
write!(f, "0x{}", hex::encode(&self.bytes))
} else {
write!(f, "{}", hex::encode(&self.bytes))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_map() {
let map = Value::Map(Map::new(
Some("M"),
vec![(Value::String("a".into()), Value::UInt(1))]
.into_iter()
.collect(),
));
assert_eq!(r#"M { a: 1 }"#, format!("{map}"), "non-alternate same line");
assert_eq!(
"M {\n a: 1,\n}",
format!("{map:#}"),
"alternate indented (pretty)"
);
}
}