// 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)" ); } }