Skip to content

Instantly share code, notes, and snippets.

@rbran
Created January 26, 2023 16:11
Show Gist options
  • Save rbran/e7814fd6694ee37d54243236b77ff3cf to your computer and use it in GitHub Desktop.
Save rbran/e7814fd6694ee37d54243236b77ff3cf to your computer and use it in GitHub Desktop.
Deku read from std::io::Read proposal
use deku::prelude::*;
#[derive(Debug, PartialEq, DekuRead)]
struct DekuStruct {
field_a: u8,
field_b: u16,
field_c: DekuEnum,
}
#[derive(Debug, PartialEq, DekuRead)]
#[deku(type = "u8")]
enum DekuEnum {
#[deku(id = "0")]
Var1,
#[deku(id = "1")]
Var2(u32),
}
trait DekuFromReader: Sized {
//Similar to from_bytes, but the rest is only one u8, in case the struct/enum
//is not byte complete, AKA `size_in_bits(type) % 8 != 0`
fn from_reader<R: std::io::Read>(
reader: R,
) -> Result<(u8, Self), DekuError>;
}
//Implementation generated by a macro
impl DekuFromReader for DekuStruct {
fn from_reader<R: std::io::Read>(
mut reader: R,
) -> Result<(u8, Self), DekuError> {
//condensate multiple reads for performance, or just use std::io::BufReader
let mut field_a_b = [0u8; 3];
reader
.read_exact(&mut field_a_b)
.expect("TODO into DekuError");
let field_a = field_a_b[0];
let field_b = u16::from_be_bytes(field_a_b[1..3].try_into().unwrap());
let (rest, field_c): (_, DekuEnum) = reader.deku_read()?;
let value = Self {
field_a,
field_b,
field_c,
};
Ok((rest, value))
}
}
//Implementation generated by a macro
impl DekuFromReader for DekuEnum {
fn from_reader<R: std::io::Read>(
mut reader: R,
) -> Result<(u8, Self), DekuError> {
let mut id = [0u8];
reader.read_exact(&mut id).expect("TODO into DekuError");
match id[0] {
0 => Ok((0, Self::Var1)),
1 => {
let mut value = [0u8; 4];
reader.read_exact(&mut value).expect("TODO into DekuError");
let value = u32::from_be_bytes(value);
Ok((0, Self::Var2(value)))
}
_ => Err(DekuError::IdVariantNotFound),
}
}
}
//blanked implementation
trait DekuReader {
fn deku_read<T: DekuFromReader>(&mut self) -> Result<(u8, T), DekuError>;
}
impl<R: std::io::Read> DekuReader for R {
fn deku_read<T: DekuFromReader>(&mut self) -> Result<(u8, T), DekuError> {
T::from_reader(self)
}
}
fn main() {
let mut file =
std::io::Cursor::new([0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x03]);
let (_rest, val) = file.deku_read::<DekuStruct>().unwrap();
assert_eq!(
val,
DekuStruct {
field_a: 0x01,
field_b: 0x02,
field_c: DekuEnum::Var2(0x03),
}
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment