Trait scroll::Pread
[−]
[src]
pub trait Pread<Ctx = Endian, E = Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)> where E: Debug,
Ctx: Copy + Default + Debug,
I: Copy + Debug,
TryCtx: Copy + Default + Debug,
SliceCtx: Copy + Default + Debug { fn pread_with<'a, N: TryFromCtx<'a, TryCtx, Error=E>>(&'a self,
offset: I,
ctx: Ctx)
-> Result<N, E>; fn pread_slice<'a, N: ?Sized + TryRefFromCtx<SliceCtx, Error=E>>(&'a self,
offset: I,
count: I)
-> Result<&'a N, E>; fn pread_unsafe<'a, N: TryFromCtx<'a, TryCtx, Error=E>>(&'a self,
offset: I,
ctx: Ctx)
-> N { ... } fn pread<'a, N: TryFromCtx<'a, TryCtx, Error=E>>(&'a self,
offset: I)
-> Result<N, E> { ... } }
A very generic, contextual pread interface in Rust. Allows completely parallelized reads, as Self
is immutable
Don't be scared! The Pread
definition is terrifying, but it is definitely tractable. Essentially, E
is the error, Ctx
the parsing context, I
is the indexing type, TryCtx
is the "offset + ctx" Context given to the TryFromCtx
trait bounds, and SliceCtx
is the "offset + size + ctx" context given to the TryRefFromCtx
trait bound.
They all have reasonable defaults, so if you're just using this trait, you can usually get away with fn <T: scroll::Pread>(bytes: &T) -> yourResultWhichConvertsScrollErrors
Implementing Your Own Reader
If you want to implement your own reader for a type Foo
from some kind of buffer (say [u8]
), then you need to implement TryFromCtx
use scroll::{self, ctx}; #[derive(Debug, PartialEq, Eq)] pub struct Foo(u16); impl<'a> ctx::TryFromCtx<'a> for Foo { type Error = scroll::Error; fn try_from_ctx(this: &'a [u8], ctx: (usize, scroll::Endian)) -> Result<Self, Self::Error> { use scroll::Pread; let offset = ctx.0; let le = ctx.1; if offset > 2 { return Err((scroll::Error::BadOffset("whatever".to_string())).into()) } let n = this.pread_with(offset, le)?; Ok(Foo(n)) } } use scroll::Pread; // you can now read `Foo`'s out of a &[u8] buffer for free, with `Pread` and `Gread` without doing _anything_ else! let bytes: [u8; 4] = [0xde, 0xad, 0, 0]; let foo = bytes.pread::<Foo>(0).unwrap(); assert_eq!(Foo(0xadde), foo); let foo2 = bytes.pread_with::<Foo>(0, scroll::BE).unwrap(); assert_eq!(Foo(0xdeadu16), foo2);
Advanced: Using Your Own Error in TryFromCtx
use scroll::{self, ctx}; use std::error; use std::fmt::{self, Display}; // make some kind of normal error which also can transform a scroll error ideally (quick_error, error_chain allow this automatically nowadays) #[derive(Debug)] pub struct ExternalError {} impl Display for ExternalError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "ExternalError") } } impl error::Error for ExternalError { fn description(&self) -> &str { "ExternalError" } fn cause(&self) -> Option<&error::Error> { None} } impl From<scroll::Error> for ExternalError { fn from(err: scroll::Error) -> Self { match err { _ => ExternalError{}, } } } #[derive(Debug, PartialEq, Eq)] pub struct Foo(u16); impl<'a> ctx::TryFromCtx<'a> for Foo { type Error = ExternalError; fn try_from_ctx(this: &'a [u8], ctx: (usize, scroll::Endian)) -> Result<Self, Self::Error> { use scroll::Pread; let offset = ctx.0; let le = ctx.1; if offset > 2 { return Err((ExternalError {}).into()) } let n = this.pread_with(offset, le)?; Ok(Foo(n)) } } use scroll::Pread; // the only caveat is that you now need to specify the error type in fn generic params, e.g. `fn thingee<S: scroll::Pread<YourCtx, ExternalError>>` let bytes: [u8; 4] = [0xde, 0xad, 0, 0]; let foo: Result<Foo, ExternalError> = bytes.pread(0);
Required Methods
fn pread_with<'a, N: TryFromCtx<'a, TryCtx, Error=E>>(&'a self,
offset: I,
ctx: Ctx)
-> Result<N, E>
offset: I,
ctx: Ctx)
-> Result<N, E>
Reads a value from self
at offset
with the given ctx
Example
use scroll::Pread; let bytes: [u8; 2] = [0xde, 0xad]; let dead: u16 = bytes.pread_with(0, scroll::BE).unwrap(); assert_eq!(dead, 0xdeadu16);
fn pread_slice<'a, N: ?Sized + TryRefFromCtx<SliceCtx, Error=E>>(&'a self,
offset: I,
count: I)
-> Result<&'a N, E>
offset: I,
count: I)
-> Result<&'a N, E>
Slices an N
from self
at offset
up to count
times
Example
use scroll::Pread; let bytes: [u8; 2] = [0x48, 0x49]; let hi: &str = bytes.pread_slice(0, 2).unwrap(); assert_eq!(hi, "HI"); let bytes2 = bytes.pread_slice::<[u8]>(0, 2).unwrap(); assert_eq!(bytes, bytes2);
Provided Methods
fn pread_unsafe<'a, N: TryFromCtx<'a, TryCtx, Error=E>>(&'a self,
offset: I,
ctx: Ctx)
-> N
offset: I,
ctx: Ctx)
-> N
Implement this if you need a faster version for use by Gread
fn pread<'a, N: TryFromCtx<'a, TryCtx, Error=E>>(&'a self,
offset: I)
-> Result<N, E>
offset: I)
-> Result<N, E>
Reads a value from self
at offset
with a default Ctx
. For the primitive numeric values, this will read at the machine's endianness.
Example
use scroll::Pread; let bytes = [0x7fu8; 0x01]; let byte = bytes.pread::<u8>(0).unwrap();