feat: Add synchronous binary reading utilities

This commit is contained in:
Lucas Schwiderski 2022-12-09 10:11:49 +01:00
parent 78eb25368c
commit d1ff738098
Signed by: lucas
GPG key ID: AA12679AAA6DF4D8
3 changed files with 161 additions and 0 deletions

7
Cargo.lock generated
View file

@ -73,6 +73,12 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.2.1" version = "1.2.1"
@ -628,6 +634,7 @@ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
name = "sdk" name = "sdk"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder",
"color-eyre", "color-eyre",
"csv-async", "csv-async",
"futures", "futures",

View file

@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
byteorder = "1.4.3"
color-eyre = "0.6.2" color-eyre = "0.6.2"
csv-async = { version = "1.2.4", features = ["tokio", "serde"] } csv-async = { version = "1.2.4", features = ["tokio", "serde"] }
futures = "0.3.25" futures = "0.3.25"

View file

@ -152,3 +152,156 @@ where
Ok(0) Ok(0)
} }
} }
pub mod sync {
use std::io::{self, Read, Seek, SeekFrom, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use color_eyre::eyre::WrapErr;
use color_eyre::{Help, Result, SectionExt};
macro_rules! make_read {
($func:ident, $read:ident, $type:ty) => {
fn $read(&mut self) -> io::Result<$type> {
ReadBytesExt::$func::<LittleEndian>(&mut self)
}
fn $func(&mut self) -> Result<$type> {
let res = ReadExt::$read(&mut self)
.wrap_err(concat!("failed to read ", stringify!($type)));
if res.is_ok() {
return res;
}
let pos = self.stream_position();
if pos.is_ok() {
res.with_section(|| {
format!("{pos:#X} ({pos})", pos = pos.unwrap()).header("Position: ")
})
} else {
res
}
}
};
}
macro_rules! make_write {
($func:ident, $write:ident, $type:ty) => {
fn $write(&mut self, val: $type) -> io::Result<()> {
WriteBytesExt::$func::<LittleEndian>(&mut self, val)
}
fn $func(&mut self, val: $type) -> Result<()> {
let res = WriteExt::$write(&mut self, val)
.wrap_err(concat!("failed to write ", stringify!($type)));
if res.is_ok() {
return res;
}
let pos = self.stream_position();
if pos.is_ok() {
res.with_section(|| {
format!("{pos:#X} ({pos})", pos = pos.unwrap()).header("Position: ")
})
} else {
res
}
}
};
}
macro_rules! make_skip {
($func:ident, $read:ident, $type:ty) => {
fn $func(&mut self, cmp: $type) -> Result<()> {
let val = ReadExt::$read(&mut self)?;
if val != cmp {
let pos = self.stream_position().unwrap_or(u64::MAX);
tracing::debug!(
pos,
expected = cmp,
actual = val,
"Unexpected value for skipped {}",
stringify!($type)
);
}
Ok(())
}
};
}
pub trait ReadExt: ReadBytesExt + Seek {
fn read_u8(&mut self) -> io::Result<u8> {
ReadBytesExt::read_u8(&mut self)
}
make_read!(read_u32, read_u32_le, u32);
make_read!(read_u64, read_u64_le, u64);
make_skip!(skip_u8, read_u8, u8);
make_skip!(skip_u32, read_u32, u32);
fn skip_padding(&mut self) -> io::Result<()> {
let pos = self.stream_position()?;
let padding_size = 16 - (pos % 16);
if padding_size < 16 && padding_size > 0 {
tracing::trace!(pos, padding_size, "Skipping padding");
self.seek(SeekFrom::Current(padding_size as i64))?;
} else {
tracing::trace!(pos, padding_size, "No padding to skip");
}
Ok(())
}
}
pub trait WriteExt: WriteBytesExt + Seek {
make_write!(write_u32, write_u32_le, u32);
make_write!(write_u64, write_u64_le, u64);
fn write_padding(&mut self) -> io::Result<usize> {
let pos = self.stream_position()?;
let size = 16 - (pos % 16) as usize;
tracing::trace!(padding_size = size, "Writing padding");
if size > 0 && size < 16 {
let buf = vec![0; size];
self.write_all(&buf)?;
Ok(size)
} else {
Ok(0)
}
}
}
impl<R: ReadBytesExt + Seek + ?Sized> ReadExt for R {}
impl<W: WriteBytesExt + Seek + ?Sized> WriteExt for W {}
pub(crate) fn _read_up_to<R>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
where
R: Read + Seek,
{
let pos = r.stream_position()?;
let err = {
match r.read_exact(buf) {
Ok(_) => return Ok(buf.len()),
Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => {
r.seek(SeekFrom::Start(pos))?;
match r.read_to_end(buf) {
Ok(read) => return Ok(read),
Err(err) => err,
}
}
Err(err) => err,
}
};
Err(err).with_section(|| format!("{pos:#X} ({pos})", pos = pos).header("Position: "))
}
}