use core::convert::{AsRef, AsMut};
use core::result;
use core::fmt::Debug;
use core::ops::{Add, AddAssign};
use ctx::{self, TryFromCtx, TryRefFromCtx, TryIntoCtx, SizeWith};
use error::*;
use error;
use pread::Pread;
use pwrite::Pwrite;
use endian::Endian;
pub trait TryOffsetWith<Ctx = ctx::DefaultCtx, E = error::Error, I = usize> {
fn try_offset<N: SizeWith<Ctx, Units = I>>(&self, offset: I, ctx: &Ctx) -> result::Result<I, E>;
}
pub trait Gread<Ctx = Endian, E = error::Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)> : Pread<Ctx, E, I, TryCtx, SliceCtx> + TryOffsetWith<Ctx, E, I>
where Ctx: Copy + Default + Debug,
I: AddAssign + Copy + Add + Default + Debug,
E: Debug,
TryCtx: Copy + Default + Debug,
SliceCtx: Copy + Default + Debug,
{
#[inline]
fn gread_unsafe<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I, ctx: Ctx) -> N {
let o = *offset;
let count = self.try_offset::<N>(o, &ctx).unwrap();
*offset += count;
self.pread_unsafe(o, ctx)
}
#[inline]
fn gread<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I) -> result::Result<N, E> {
let ctx = Ctx::default();
self.gread_with(offset, ctx)
}
#[inline]
fn gread_with<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I, ctx: Ctx) -> result::Result<N, E> {
let o = *offset;
let count = self.try_offset::<N>(o, &ctx)?;
let res = self.pread_unsafe(o, ctx);
*offset += count;
Ok(res)
}
#[inline]
fn gread_slice<N: ?Sized>(&self, offset: &mut I, count: I) -> result::Result<&N, E>
where N: TryRefFromCtx<SliceCtx, Error = E> {
let o = *offset;
let res = self.pread_slice::<N>(o, count);
if res.is_ok() { *offset += count;}
res
}
#[inline]
fn gread_inout<'a, N>(&'a self, offset: &mut I, inout: &mut [N]) -> result::Result<(), E>
where
N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>,
{
let len = inout.len();
for i in 0..len {
inout[i] = self.gread(offset)?;
}
Ok(())
}
#[inline]
fn gread_inout_with<'a, N>(&'a self, offset: &mut I, inout: &mut [N], ctx: Ctx) -> result::Result<(), E>
where
N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>,
{
let len = inout.len();
for i in 0..len {
inout[i] = self.gread_with(offset, ctx)?;
}
Ok(())
}
}
impl<Ctx> TryOffsetWith<Ctx> for [u8] {
#[inline]
fn try_offset<N: SizeWith<Ctx, Units = usize>>(&self, offset: usize, ctx: &Ctx) -> Result<usize> {
let size = N::size_with(ctx);
if offset + size > self.len() {
Err(error::Error::BadRange{range: offset..offset+size, size: self.len()})
} else {
Ok(size)
}
}
}
impl<Ctx, T> TryOffsetWith<Ctx> for T where T: AsRef<[u8]> {
#[inline]
fn try_offset<N: SizeWith<Ctx, Units = usize>>(&self, offset: usize, ctx: &Ctx) -> Result<usize> {
<[u8] as TryOffsetWith<Ctx>>::try_offset::<N>(self.as_ref(), offset, ctx)
}
}
impl<Ctx, E> Gread<Ctx, E> for [u8] where
[u8]: TryOffsetWith<Ctx, E>,
Ctx: Copy + Default + Debug,
E: Debug {}
impl<Ctx, E, T> Gread<Ctx, E> for T where
T: AsRef<[u8]> + TryOffsetWith<Ctx, E>,
Ctx: Copy + Default + Debug,
E: Debug {}
pub trait Gwrite<Ctx = Endian, E = error::Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)>: Pwrite<Ctx, E, I, TryCtx, SliceCtx> + TryOffsetWith<Ctx, E, I>
where E: Debug,
Ctx: Copy + Default + Debug,
I: AddAssign + Copy + Add + Default + Debug,
TryCtx: Copy + Default + Debug,
SliceCtx: Copy + Default + Debug,
{
#[inline]
fn gwrite_unsafe<N: SizeWith<Ctx, Units = I> + TryIntoCtx<TryCtx, Error = E>>(&mut self, n: N, offset: &mut I, ctx: Ctx) {
let o = *offset;
let count = self.try_offset::<N>(o, &ctx).unwrap();
*offset += count;
self.pwrite_unsafe(n, o, ctx)
}
#[inline]
fn gwrite<N: SizeWith<Ctx, Units = I> + TryIntoCtx<TryCtx, Error = E>>(&mut self, n: N, offset: &mut I) -> result::Result<(), E> {
let ctx = Ctx::default();
self.gwrite_with(n, offset, ctx)
}
#[inline]
fn gwrite_with<N: SizeWith<Ctx, Units = I> + TryIntoCtx<TryCtx, Error = E>>(&mut self, n: N, offset: &mut I, ctx: Ctx) -> result::Result<(), E> {
let o = *offset;
let count = self.try_offset::<N>(o, &ctx)?;
*offset += count;
self.pwrite_unsafe(n, o, ctx);
Ok(())
}
}
impl<Ctx, E, T> Gwrite<Ctx, E> for T where
T: AsRef<[u8]> + AsMut<[u8]> + TryOffsetWith<Ctx, E>,
Ctx: Copy + Default + Debug,
E: Debug {}
impl<Ctx, E> Gwrite<Ctx, E> for [u8] where
[u8]: TryOffsetWith<Ctx, E>,
Ctx: Copy + Default + Debug,
E: Debug {}