More readable Debug::fmt for Value::{Ascii, Undefined}.

This commit is contained in:
KAMADA Ken'ichi 2020-02-05 23:05:48 +09:00
commit 79cc94f615
2 changed files with 94 additions and 20 deletions

View file

@ -27,7 +27,6 @@
extern crate exif;
use std::env;
use std::fmt::Write;
use std::fs::File;
use std::io::BufReader;
use std::path::{Path, PathBuf};
@ -50,24 +49,7 @@ fn dump_file(path: &Path) -> Result<(), exif::Error> {
println!(" {}/{}: {}",
f.ifd_num.index(), f.tag,
f.display_value().with_unit(&exif));
if let exif::Value::Ascii(ref v) = f.value {
println!(" Ascii({:?})",
v.iter().map(|x| escape(x)).collect::<Vec<_>>());
} else {
println!(" {:?}", f.value);
}
println!(" {:?}", f.value);
}
Ok(())
}
fn escape(bytes: &[u8]) -> String {
let mut buf = String::new();
for &c in bytes {
match c {
b'\\' | b'"' => write!(buf, "\\{}", c as char).unwrap(),
0x20..=0x7e => buf.write_char(c as char).unwrap(),
_ => write!(buf, "\\x{:02x}", c).unwrap(),
}
}
buf
}

View file

@ -25,11 +25,12 @@
//
use std::fmt;
use std::fmt::Write as _;
use crate::endian::Endian;
/// Types and values of TIFF fields (for Exif attributes).
#[derive(Debug, Clone)]
#[derive(Clone)]
pub enum Value {
/// Vector of 8-bit unsigned integers.
Byte(Vec<u8>),
@ -159,6 +160,65 @@ impl<'a> fmt::Display for Display<'a> {
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Byte(v) => f.debug_tuple("Byte").field(v).finish(),
Self::Ascii(v) => f.debug_tuple("Ascii")
.field(&IterDebugAdapter(
|| v.iter().map(|x| AsciiDebugAdapter(x)))).finish(),
Self::Short(v) => f.debug_tuple("Short").field(v).finish(),
Self::Long(v) => f.debug_tuple("Long").field(v).finish(),
Self::Rational(v) => f.debug_tuple("Rational").field(v).finish(),
Self::SByte(v) => f.debug_tuple("SByte").field(v).finish(),
Self::Undefined(v, o) => f.debug_tuple("Undefined")
.field(&HexDebugAdapter(v))
.field(&format_args!("ofs={:#x}", o)).finish(),
Self::SShort(v) => f.debug_tuple("SShort").field(v).finish(),
Self::SLong(v) => f.debug_tuple("SLong").field(v).finish(),
Self::SRational(v) => f.debug_tuple("SRational").field(v).finish(),
Self::Float(v) => f.debug_tuple("Float").field(v).finish(),
Self::Double(v) => f.debug_tuple("Double").field(v).finish(),
Self::Unknown(t, c, oo) => f.debug_tuple("Unknown")
.field(&format_args!("typ={}", t))
.field(&format_args!("cnt={}", c))
.field(&format_args!("ofs={:#x}", oo)).finish(),
}
}
}
struct IterDebugAdapter<F>(F);
impl<F, T, I> fmt::Debug for IterDebugAdapter<F>
where F: Fn() -> T, T: Iterator<Item = I>, I: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.0()).finish()
}
}
struct AsciiDebugAdapter<'a>(&'a [u8]);
impl<'a> fmt::Debug for AsciiDebugAdapter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('"')?;
self.0.iter().try_for_each(|&c| match c {
b'\\' | b'"' => write!(f, "\\{}", c as char),
0x20..=0x7e => f.write_char(c as char),
_ => write!(f, "\\x{:02x}", c),
})?;
f.write_char('"')
}
}
struct HexDebugAdapter<'a>(&'a [u8]);
impl<'a> fmt::Debug for HexDebugAdapter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("0x")?;
self.0.iter().try_for_each(|x| write!(f, "{:02x}", x))
}
}
// Static default values.
pub enum DefaultValue {
None,
@ -717,6 +777,38 @@ mod tests {
assert_eq!(it.len(), 2);
}
#[test]
fn value_fmt_debug() {
let v = Value::Byte(b"b\0y".to_vec());
assert_eq!(format!("{:?}", v), "Byte([98, 0, 121])");
let v = Value::Ascii(vec![]);
assert_eq!(format!("{:?}", v), "Ascii([])");
let v = Value::Ascii(vec![b"abc\"\\\n\x7f".to_vec(), b"".to_vec()]);
assert_eq!(format!("{:?}", v), r#"Ascii(["abc\"\\\x0a\x7f", ""])"#);
let v = Value::Short(vec![]);
assert_eq!(format!("{:?}", v), "Short([])");
let v = Value::Long(vec![1, 2]);
assert_eq!(format!("{:?}", v), "Long([1, 2])");
let v = Value::Rational(vec![(0, 0).into()]);
assert_eq!(format!("{:?}", v), "Rational([Rational(0/0)])");
let v = Value::SByte(vec![-3, 4, 5]);
assert_eq!(format!("{:?}", v), "SByte([-3, 4, 5])");
let v = Value::Undefined(vec![0, 0xff], 0);
assert_eq!(format!("{:?}", v), "Undefined(0x00ff, ofs=0x0)");
let v = Value::SShort(vec![6, -7]);
assert_eq!(format!("{:?}", v), "SShort([6, -7])");
let v = Value::SLong(vec![-9]);
assert_eq!(format!("{:?}", v), "SLong([-9])");
let v = Value::SRational(vec![(-2, -1).into()]);
assert_eq!(format!("{:?}", v), "SRational([SRational(-2/-1)])");
let v = Value::Float(vec![1.5, 0.0]);
assert_eq!(format!("{:?}", v), "Float([1.5, 0.0])");
let v = Value::Double(vec![-0.5, 1.0]);
assert_eq!(format!("{:?}", v), "Double([-0.5, 1.0])");
let v = Value::Unknown(1, 2, 10);
assert_eq!(format!("{:?}", v), "Unknown(typ=1, cnt=2, ofs=0xa)");
}
#[test]
fn rational_fmt_display() {
let r = Rational::from((u32::max_value(), u32::max_value()));