use ::env_logger::Builder;
use simple_parse::{SpRead, SpWrite};
use std::io::{Cursor, Write};
#[derive(Debug, SpRead, SpWrite)]
pub enum Message {
ClientLogin(
#[sp(var_size)] LoginInfo,
),
Logout(u16, u16),
Chat(String),
File {
name: String,
creation_time: Option<u32>,
contents: Vec<u8>,
},
}
#[derive(Debug, SpRead, SpWrite)]
pub struct LoginInfo {
username_len: u8,
is_admin: bool,
#[sp(endian = "big")]
secret_iv: u16,
#[sp(count = "username_len")] username: String,
password: String,
got_session: bool,
#[sp(count = "got_session")]
session: Option<u32>,
}
macro_rules! dump_optimization_hints {
($typ:ty) => {
println!(
"{} {{\n IS_VAR_SIZE: {}\n STATIC_SIZE: {}\n COUNT_SIZE: {}\n}}",
stringify!($typ),
<$typ as ::simple_parse::SpOptHints>::IS_VAR_SIZE,
<$typ as ::simple_parse::SpOptHints>::STATIC_SIZE,
<$typ as ::simple_parse::SpOptHints>::COUNT_SIZE,
);
};
}
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut builder = Builder::from_default_env();
builder
.format(|buf, record| writeln!(buf, "[{}] {}", record.level(), record.args()))
.init();
let data: &[u8] = &[
0x00, 0x04, 0x01, 0xC0, 0xFE, b'T', b'o', b'n', b'y', 0x03, 0, 0, 0, b'a', b'b', b'c', 0x00, 0x02, 0x05, 0, 0, 0, b'H', b'e', b'l', b'l', b'o', 0x03, 0x06, 0, 0, 0, b'h', b'i', b'.', b't', b'x', b't', 0x00, 0, 0, 0, 0, ];
println!("Original Bytes == {:X?}", data);
let data_len = data.len() as u64;
let mut cursor = Cursor::new(data);
let mut dst = Vec::new();
dump_optimization_hints!(Message);
dump_optimization_hints!(LoginInfo);
loop {
let obj = <Message>::from_reader(&mut cursor);
match obj {
Ok(v) => {
println!("SpRead\tMessage::{:X?}", v);
dst.clear();
v.to_writer(&mut dst)?;
println!("SpWrite\t{:X?}", dst);
}
Err(e) => {
if data_len - cursor.position() > 0 {
println!("{}", e);
} else {
println!("Done !");
}
break;
}
}
}
println!("{} bytes left", data_len - cursor.position());
Ok(())
}