pub trait IOread<Ctx: Copy>: Read {
fn ioread<N: FromCtx<Ctx> + SizeWith<Ctx>>(&mut self) -> Result<N>
where
Ctx: Default,
{ ... }
fn ioread_with<N: FromCtx<Ctx> + SizeWith<Ctx>>(
&mut self,
ctx: Ctx
) -> Result<N> { ... }
}
Expand description
An extension trait to std::io::Read
streams; mainly targeted at reading primitive types with
a known size.
Requires types to implement FromCtx
and SizeWith
.
NB You should probably add repr(C)
and be very careful how you implement
SizeWith
, otherwise you will get IO errors failing to fill entire
buffer (the size you specified in SizeWith
), or out of bound errors (depending on your impl)
in from_ctx
.
Warning: Currently ioread/write uses a small 256-byte buffer and can not read/write larger types
Example
use std::io::Cursor;
use scroll::{self, ctx, LE, Pread, IOread};
#[repr(packed)]
struct Foo {
foo: i64,
bar: u32,
}
impl ctx::FromCtx<scroll::Endian> for Foo {
fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self {
Foo { foo: bytes.pread_with::<i64>(0, ctx).unwrap(), bar: bytes.pread_with::<u32>(8, ctx).unwrap() }
}
}
impl ctx::SizeWith<scroll::Endian> for Foo {
// our parsing context doesn't influence our size
fn size_with(_: &scroll::Endian) -> usize {
::std::mem::size_of::<Foo>()
}
}
let bytes_ = [0x0b,0x0b,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
let mut bytes = Cursor::new(bytes_);
let foo = bytes.ioread_with::<i64>(LE).unwrap();
let bar = bytes.ioread_with::<u32>(LE).unwrap();
assert_eq!(foo, 0xb0b);
assert_eq!(bar, 0xbeef);
let error = bytes.ioread_with::<f64>(LE);
assert!(error.is_err());
let mut bytes = Cursor::new(bytes_);
let foo_ = bytes.ioread_with::<Foo>(LE).unwrap();
// Remember that you need to copy out fields from packed structs
// with a `{}` block instead of borrowing them directly
// ref: https://github.com/rust-lang/rust/issues/46043
assert_eq!({foo_.foo}, foo);
assert_eq!({foo_.bar}, bar);
Provided methods
Reads the type N
from Self
, with a default parsing context.
For the primitive numeric types, this will be at the host machine’s endianness.
Example
use scroll::IOread;
use std::io::Cursor;
let bytes = [0xef, 0xbe];
let mut bytes = Cursor::new(&bytes[..]);
let beef = bytes.ioread::<u16>().unwrap();
#[cfg(target_endian = "little")]
assert_eq!(0xbeef, beef);
#[cfg(target_endian = "big")]
assert_eq!(0xefbe, beef);
fn ioread_with<N: FromCtx<Ctx> + SizeWith<Ctx>>(
&mut self,
ctx: Ctx
) -> Result<N>
fn ioread_with<N: FromCtx<Ctx> + SizeWith<Ctx>>(
&mut self,
ctx: Ctx
) -> Result<N>
Reads the type N
from Self
, with the parsing context ctx
.
NB: this will panic if the type you’re reading has a size greater than 256. Plans are to have this allocate in larger cases.
For the primitive numeric types, this will be at the host machine’s endianness.
Example
use scroll::{IOread, LE, BE};
use std::io::Cursor;
let bytes = [0xef, 0xbe, 0xb0, 0xb0, 0xfe, 0xed, 0xde, 0xad];
let mut bytes = Cursor::new(&bytes[..]);
let beef = bytes.ioread_with::<u16>(LE).unwrap();
assert_eq!(0xbeef, beef);
let b0 = bytes.ioread::<u8>().unwrap();
assert_eq!(0xb0, b0);
let b0 = bytes.ioread::<u8>().unwrap();
assert_eq!(0xb0, b0);
let feeddead = bytes.ioread_with::<u32>(BE).unwrap();
assert_eq!(0xfeeddead, feeddead);