a291c8690a
GitOrigin-RevId: e6e19f3d81a982a62e1bba08f0b4f7fdc21b4ea0
163 lines
5.1 KiB
Rust
163 lines
5.1 KiB
Rust
extern crate netencode;
|
||
|
||
use netencode::{Tag, T, U};
|
||
|
||
pub enum Pretty {
|
||
Single {
|
||
r#type: char,
|
||
length: String,
|
||
val: String,
|
||
trailer: char,
|
||
},
|
||
Tag {
|
||
r#type: char,
|
||
length: String,
|
||
key: String,
|
||
inner: char,
|
||
val: Box<Pretty>,
|
||
},
|
||
Multi {
|
||
r#type: char,
|
||
length: String,
|
||
vals: Vec<Pretty>,
|
||
trailer: char,
|
||
},
|
||
}
|
||
|
||
impl Pretty {
|
||
pub fn from_u<'a>(u: U<'a>) -> Pretty {
|
||
match u {
|
||
U::Unit => Self::scalar('u', "", ""),
|
||
U::N1(b) => Self::scalar('n', "1:", if b { "1" } else { "0" }),
|
||
U::N3(n) => Self::scalar('n', "3:", n),
|
||
U::N6(n) => Self::scalar('n', "6:", n),
|
||
U::N7(n) => Self::scalar('n', "7:", n),
|
||
U::I3(i) => Self::scalar('i', "3:", i),
|
||
U::I6(i) => Self::scalar('i', "6:", i),
|
||
U::I7(i) => Self::scalar('i', "7:", i),
|
||
U::Text(s) => Pretty::Single {
|
||
r#type: 't',
|
||
length: format!("{}:", s.len()),
|
||
val: s.to_string(),
|
||
trailer: ',',
|
||
},
|
||
U::Binary(s) => Pretty::Single {
|
||
r#type: 'b',
|
||
length: format!("{}:", s.len()),
|
||
// For pretty printing we want the string to be visible obviously.
|
||
// Instead of not supporting binary, let’s use lossy conversion.
|
||
val: String::from_utf8_lossy(s).into_owned(),
|
||
trailer: ',',
|
||
},
|
||
U::Sum(Tag { tag, val }) => Self::pretty_tag(tag, Self::from_u(*val)),
|
||
U::Record(m) => Pretty::Multi {
|
||
r#type: '{',
|
||
// TODO: we are losing the size here, should we recompute it? Keep it?
|
||
length: String::from(""),
|
||
vals: m
|
||
.into_iter()
|
||
.map(|(k, v)| Self::pretty_tag(k, Self::from_u(v)))
|
||
.collect(),
|
||
trailer: '}',
|
||
},
|
||
U::List(l) => Pretty::Multi {
|
||
r#type: '[',
|
||
// TODO: we are losing the size here, should we recompute it? Keep it?
|
||
length: String::from(""),
|
||
vals: l.into_iter().map(|v| Self::from_u(v)).collect(),
|
||
trailer: ']',
|
||
},
|
||
}
|
||
}
|
||
|
||
fn scalar<D>(r#type: char, length: &str, d: D) -> Pretty
|
||
where
|
||
D: std::fmt::Display,
|
||
{
|
||
Pretty::Single {
|
||
r#type,
|
||
length: length.to_string(),
|
||
val: format!("{}", d),
|
||
trailer: ',',
|
||
}
|
||
}
|
||
|
||
fn pretty_tag(tag: &str, val: Pretty) -> Pretty {
|
||
Pretty::Tag {
|
||
r#type: '<',
|
||
length: format!("{}:", tag.len()),
|
||
key: tag.to_string(),
|
||
inner: '|',
|
||
val: Box::new(val),
|
||
}
|
||
}
|
||
|
||
pub fn print_multiline<W>(&self, mut w: &mut W) -> std::io::Result<()>
|
||
where
|
||
W: std::io::Write,
|
||
{
|
||
Self::go(&mut w, self, 0, true);
|
||
write!(w, "\n")
|
||
}
|
||
|
||
fn go<W>(mut w: &mut W, p: &Pretty, depth: usize, is_newline: bool) -> std::io::Result<()>
|
||
where
|
||
W: std::io::Write,
|
||
{
|
||
const full: usize = 4;
|
||
const half: usize = 2;
|
||
let i = &vec![b' '; depth * full];
|
||
let iandhalf = &vec![b' '; depth * full + half];
|
||
let (i, iandhalf) = unsafe {
|
||
(
|
||
std::str::from_utf8_unchecked(i),
|
||
std::str::from_utf8_unchecked(iandhalf),
|
||
)
|
||
};
|
||
if is_newline {
|
||
write!(&mut w, "{}", i);
|
||
}
|
||
match p {
|
||
Pretty::Single {
|
||
r#type,
|
||
length,
|
||
val,
|
||
trailer,
|
||
} => write!(&mut w, "{} {}{}", r#type, val, trailer),
|
||
Pretty::Tag {
|
||
r#type,
|
||
length,
|
||
key,
|
||
inner,
|
||
val,
|
||
} => {
|
||
write!(&mut w, "{} {} {}", r#type, key, inner)?;
|
||
Self::go::<W>(&mut w, val, depth, false)
|
||
}
|
||
// if the length is 0 or 1, we print on one line,
|
||
// only if there’s more than one element we split the resulting value.
|
||
// we never break lines on arbitrary column sizes, since that is just silly.
|
||
Pretty::Multi {
|
||
r#type,
|
||
length,
|
||
vals,
|
||
trailer,
|
||
} => match vals.len() {
|
||
0 => write!(&mut w, "{} {}", r#type, trailer),
|
||
1 => {
|
||
write!(&mut w, "{} ", r#type);
|
||
Self::go::<W>(&mut w, &vals[0], depth, false)?;
|
||
write!(&mut w, "{}", trailer)
|
||
}
|
||
more => {
|
||
write!(&mut w, "\n{}{} \n", iandhalf, r#type)?;
|
||
for v in vals {
|
||
Self::go::<W>(&mut w, v, depth + 1, true)?;
|
||
write!(&mut w, "\n")?;
|
||
}
|
||
write!(&mut w, "{}{}", iandhalf, trailer)
|
||
}
|
||
},
|
||
}
|
||
}
|
||
}
|