Skip to content

Commit 7ddcd2e

Browse files
committed
Decoder/inspector example
1 parent f9f02d8 commit 7ddcd2e

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

rmp/examples/inspect.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use std::fmt;
2+
use std::io::{self, Read};
3+
use rmp::{decode::*, Marker};
4+
5+
fn main() {
6+
let path = std::env::args_os().nth(1).expect("Specify path to a file with msgpack content");
7+
let data = std::fs::read(&path).expect(&path.to_string_lossy());
8+
9+
dump(&mut Indent { i: 0, start: true }, &mut data.as_slice()).unwrap();
10+
}
11+
12+
fn dump(indent: &mut Indent, rd: &mut &[u8]) -> Result<(), Box<dyn std::error::Error>> {
13+
match read_marker(rd).map_err(ValueReadError::from)? {
14+
Marker::FixPos(n) => print!("U0({n})"),
15+
Marker::FixNeg(n) => print!("I0({n})"),
16+
Marker::Null => print!("Null"),
17+
Marker::True => print!("True"),
18+
Marker::False => print!("False"),
19+
Marker::U8 => print!("U8({})", rd.read_data_u8()?),
20+
Marker::U16 => print!("U16({})", rd.read_data_u16()?),
21+
Marker::U32 => print!("U32({})", rd.read_data_u32()?),
22+
Marker::U64 => print!("U64({})", rd.read_data_u64()?),
23+
Marker::I8 => print!("I8({})", rd.read_data_i8()?),
24+
Marker::I16 => print!("I16({})", rd.read_data_i16()?),
25+
Marker::I32 => print!("I32({})", rd.read_data_i32()?),
26+
Marker::I64 => print!("I64({})", rd.read_data_i64()?),
27+
Marker::F32 => print!("F32({})", rd.read_data_f32()?),
28+
Marker::F64 => print!("F64({})", rd.read_data_f64()?),
29+
Marker::FixStr(len) => print!("Str0(\"{}\")", read_str_data(len.into(), rd)?),
30+
Marker::Str8 => print!("Str8(\"{}\")", read_str_data(rd.read_data_u8()?.into(), rd)?),
31+
Marker::Str16 => print!("Str16(\"{}\")", read_str_data(rd.read_data_u16()?.into(), rd)?),
32+
Marker::Str32 => print!("Str32(\"{}\")", read_str_data(rd.read_data_u32()?.into(), rd)?),
33+
Marker::Bin8 => print!("Bin8({})", HexDump(&read_bin_data(rd.read_data_u8()?.into(), rd)?)),
34+
Marker::Bin16 => print!("Bin16({})", HexDump(&read_bin_data(rd.read_data_u16()?.into(), rd)?)),
35+
Marker::Bin32 => print!("Bin32({})", HexDump(&read_bin_data(rd.read_data_u32()?.into(), rd)?)),
36+
Marker::FixArray(len) => dump_array(indent, 0, len.into(), rd)?,
37+
Marker::Array16 => dump_array(indent, 16, rd.read_data_u16()?.into(), rd)?,
38+
Marker::Array32 => dump_array(indent, 32, rd.read_data_u32()?.into(), rd)?,
39+
Marker::FixMap(len) => dump_map(indent, 0, len.into(), rd)?,
40+
Marker::Map16 => dump_map(indent, 16, rd.read_data_u16()?.into(), rd)?,
41+
Marker::Map32 => dump_map(indent, 32, rd.read_data_u32()?.into(), rd)?,
42+
Marker::FixExt1 => todo!(),
43+
Marker::FixExt2 => todo!(),
44+
Marker::FixExt4 => todo!(),
45+
Marker::FixExt8 => todo!(),
46+
Marker::FixExt16 => todo!(),
47+
Marker::Ext8 => todo!(),
48+
Marker::Ext16 => todo!(),
49+
Marker::Ext32 => todo!(),
50+
Marker::Reserved => todo!(),
51+
}
52+
Ok(())
53+
}
54+
55+
fn dump_map(indent: &mut Indent, ty: u8, len: u32, rd: &mut &[u8]) -> Result<(), Box<dyn std::error::Error>> {
56+
indent.print(format_args!("Map{ty}{{"));
57+
let multiline = len > 1;
58+
if multiline { indent.ln(); } else { print!(" ") }
59+
indent.ind();
60+
for i in 0..len {
61+
indent.print(""); dump(indent, rd)?; print!(": "); dump(indent, rd)?;
62+
if multiline { print!(","); indent.ln(); } else if i+1 != len { print!(", ") }
63+
}
64+
indent.out();
65+
indent.print(format_args!("}}"));
66+
Ok(())
67+
}
68+
69+
fn dump_array(indent: &mut Indent, ty: u8, len: u32, rd: &mut &[u8]) -> Result<(), Box<dyn std::error::Error>> {
70+
indent.print(format_args!("Array{ty}["));
71+
let multiline = len > 1;
72+
if multiline { indent.ln(); } else { print!(" ") }
73+
indent.ind();
74+
for i in 0..len {
75+
indent.print(""); dump(indent, rd)?;
76+
if multiline { print!(","); indent.ln(); } else if i+1 != len { print!(", ") }
77+
}
78+
indent.out();
79+
indent.print("]");
80+
Ok(())
81+
}
82+
83+
fn read_str_data<R: Read>(len: u32, rd: &mut R) -> Result<String, io::Error> {
84+
Ok(String::from_utf8_lossy(&read_bin_data(len, rd)?).into_owned())
85+
}
86+
87+
fn read_bin_data<R: Read>(len: u32, rd: &mut R) -> Result<Vec<u8>, io::Error> {
88+
let mut buf = Vec::with_capacity(len.min(1<<16) as usize);
89+
let bytes_read = rd.take(len as u64).read_to_end(&mut buf)?;
90+
if bytes_read != len as usize {
91+
return Err(io::ErrorKind::UnexpectedEof.into());
92+
}
93+
Ok(buf)
94+
}
95+
96+
struct Indent { i: u16, start: bool }
97+
impl Indent {
98+
fn print(&mut self, args: impl fmt::Display) {
99+
print!("{:w$}{args}", "", w = if self.start { (self.i as usize) * 2 } else { 0 });
100+
self.start = false;
101+
}
102+
103+
pub fn ind(&mut self) {
104+
self.i += 1;
105+
}
106+
107+
pub fn ln(&mut self) {
108+
println!();
109+
self.start = true;
110+
}
111+
112+
pub fn out(&mut self) {
113+
self.i -= 1;
114+
}
115+
}
116+
117+
struct HexDump<'a>(&'a [u8]);
118+
impl fmt::Display for HexDump<'_> {
119+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120+
let truncate = self.0.len() > 50;
121+
if truncate {
122+
f.write_fmt(format_args!("{}B ", self.0.len()))?;
123+
}
124+
125+
for &b in &self.0[0.. (if truncate { 50 } else { self.0.len() })] {
126+
f.write_fmt(format_args!("{b:02x}"))?;
127+
}
128+
129+
if truncate {
130+
f.write_str("…")?;
131+
}
132+
Ok(())
133+
}
134+
}
135+

0 commit comments

Comments
 (0)