use format_bytes::{DisplayBytes, Utf8, Visit, join};
use std::io;
#[derive(Default)]
struct Minimal(Vec<String>);
impl Visit for Minimal {
fn bytes(&mut self, value: &[u8]) -> io::Result<()> {
self.0.push(format!("bytes {:?}", value));
Ok(())
}
fn str(&mut self, value: &str) -> io::Result<()> {
self.0.push(format!("str {}", value));
Ok(())
}
}
#[derive(Debug, PartialEq)]
enum Value {
Bytes(Vec<u8>),
Str(String),
Int(i128),
Uint(u128),
Seq(Vec<Value>),
}
#[derive(Default)]
struct Typed(Vec<Value>);
impl Visit for Typed {
fn bytes(&mut self, value: &[u8]) -> io::Result<()> {
self.0.push(Value::Bytes(value.to_vec()));
Ok(())
}
fn str(&mut self, value: &str) -> io::Result<()> {
self.0.push(Value::Str(value.to_owned()));
Ok(())
}
fn int(&mut self, value: i128) -> io::Result<()> {
self.0.push(Value::Int(value));
Ok(())
}
fn uint(&mut self, value: u128) -> io::Result<()> {
self.0.push(Value::Uint(value));
Ok(())
}
fn seq(
&mut self,
items: &[&dyn DisplayBytes],
_separator: &dyn DisplayBytes,
) -> io::Result<()> {
let items = items.iter().flat_map(|item| typed(item)).collect();
self.0.push(Value::Seq(items));
Ok(())
}
}
fn typed(value: &dyn DisplayBytes) -> Vec<Value> {
let mut visitor = Typed::default();
value.visit(&mut visitor).unwrap();
visitor.0
}
fn minimal(value: &dyn DisplayBytes) -> Vec<String> {
let mut visitor = Minimal::default();
value.visit(&mut visitor).unwrap();
visitor.0
}
#[test]
fn types() {
assert_eq!(typed(b"caf\xe9"), [Value::Bytes(b"caf\xe9".to_vec())]);
assert_eq!(typed(&Utf8("é")), [Value::Str("é".to_owned())]);
assert_eq!(typed(&-1_i8), [Value::Int(-1)]);
assert_eq!(typed(&u64::MAX), [Value::Uint(u64::MAX.into())]);
assert_eq!(typed(&0.5_f64), [Value::Str("0.5".to_owned())]);
assert_eq!(typed(&Box::new(&&3_usize)), [Value::Uint(3)]);
}
#[test]
fn numbers_display_as_usual() {
assert_eq!(minimal(&-1_i8), ["str -1"]);
assert_eq!(minimal(&u8::MAX), ["str 255"]);
}
#[test]
fn default_visit() {
struct Point(u8, u8);
impl DisplayBytes for Point {
fn display_bytes(&self, out: &mut dyn io::Write) -> io::Result<()> {
format_bytes::write_bytes!(out, "{}x{}", self.0, self.1)
}
}
assert_eq!(typed(&Point(1, 2)), [Value::Bytes(b"1x2".to_vec())]);
}
#[test]
fn sequences() {
let paths: [&[u8]; 3] = [b"a", b"caf\xe9", b"b, c"];
assert_eq!(
typed(&join(paths, b", ")),
[Value::Seq(vec![
Value::Bytes(b"a".to_vec()),
Value::Bytes(b"caf\xe9".to_vec()),
Value::Bytes(b"b, c".to_vec()),
])]
);
assert_eq!(
minimal(&join([1, 2], b" and ")),
[format!("bytes {:?}", b"1 and 2")]
);
}