// Copyright 2018-2020 Parity Technologies (UK) Ltd.
// This file is part of cargo-contract.
//
// cargo-contract is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// cargo-contract is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
use super::{
Hex,
Map,
Seq,
Tuple,
Value,
};
use std::fmt::{
Debug,
Display,
Formatter,
LowerHex,
Result,
};
/// Wraps Value for custom Debug impl to provide pretty-printed Display
struct DisplayValue<'a>(&'a Value);
impl<'a> Debug for DisplayValue<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match &self.0 {
Value::Bool(boolean) => ::fmt(boolean, f),
Value::Char(character) => ::fmt(character, f),
Value::UInt(uint) => ::fmt(uint, f),
Value::Int(integer) => ::fmt(integer, f),
Value::Map(map) => ::fmt(&DisplayMap(map), f),
Value::Tuple(tuple) => ::fmt(&DisplayTuple(tuple), f),
Value::String(string) => ::fmt(string, f),
Value::Seq(seq) => ::fmt(&DisplaySeq(seq), f),
Value::Hex(hex) => ::fmt(hex, f),
Value::Literal(literal) => ::fmt(literal, f),
Value::Unit => write!(f, "()"),
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Value::String(string) => ::fmt(string, f),
value => ::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, "{:#x}", self)
}
}
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)"
);
}
}