use byteorder::{BigEndian, ByteOrder};
use num_complex::Complex;
use std::io;
use std::io::{Read, Result, Write};
use std::result;
#[derive(Debug)]
pub struct AligningReader<R: Read> {
inner: R,
offset: u64,
}
impl<R: Read> AligningReader<R> {
pub fn new(inner: R) -> Self {
AligningReader { inner, offset: 0 }
}
pub fn into_inner(self) -> R {
self.inner
}
pub fn offset(&self) -> u64 {
self.offset
}
pub fn align_to(&mut self, alignment: usize) -> Result<bool> {
let mut buf = [0u8; 64];
if alignment > 64 {
panic!("maximum alignment size is 64");
}
let excess = (self.offset % alignment as u64) as usize;
if excess == 0 {
Ok(true)
} else {
let amount = alignment - excess;
let result = self.inner.eof_read_exact(&mut buf[..amount]);
if result.is_ok() {
self.offset += amount as u64;
}
result
}
}
}
impl<R: Read> Read for AligningReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let result = self.inner.read(buf);
if let Ok(n) = result {
self.offset += n as u64;
}
result
}
}
#[derive(Debug)]
pub struct AligningWriter<W: Write> {
inner: W,
offset: u64,
}
impl<W: Write> AligningWriter<W> {
pub fn new(inner: W) -> Self {
AligningWriter { inner, offset: 0 }
}
pub fn into_inner(self) -> W {
self.inner
}
pub fn offset(&self) -> u64 {
self.offset
}
pub fn align_to(&mut self, alignment: usize) -> Result<bool> {
let buf = [0u8; 64];
if alignment > 64 {
panic!("maximum alignment size is 64");
}
let excess = (self.offset % alignment as u64) as usize;
if excess == 0 {
Ok(true)
} else {
let amount = alignment - excess;
self.inner.write_all(&buf[..amount])?;
self.offset += amount as u64;
Ok(false)
}
}
}
impl<W: Write> Write for AligningWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let result = self.inner.write(buf);
if let Ok(n) = result {
self.offset += n as u64;
}
result
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub trait OpenResultExt {
type Reprocessed;
fn require_found(self) -> Self::Reprocessed;
}
impl<T, E> OpenResultExt for result::Result<Option<T>, E>
where
E: From<io::Error>,
{
type Reprocessed = result::Result<T, E>;
fn require_found(self) -> Self::Reprocessed {
match self {
Err(e) => Err(e),
Ok(o) => {
if let Some(x) = o {
Ok(x)
} else {
Err(io::Error::new(io::ErrorKind::NotFound, "not found").into())
}
}
}
}
}
pub trait EofReadExactExt: Read {
fn eof_read_exact<E>(&mut self, buf: &mut [u8]) -> result::Result<bool, E>
where
E: From<io::Error>;
fn eof_read_be_i16<E>(&mut self) -> result::Result<Option<i16>, E>
where
E: From<io::Error>,
{
let mut buf = [0u8; 2];
if self.eof_read_exact(&mut buf)? {
Ok(Some(BigEndian::read_i16(&buf)))
} else {
Ok(None)
}
}
fn eof_read_be_i32<E>(&mut self) -> result::Result<Option<i32>, E>
where
E: From<io::Error>,
{
let mut buf = [0u8; 4];
if self.eof_read_exact(&mut buf)? {
Ok(Some(BigEndian::read_i32(&buf)))
} else {
Ok(None)
}
}
fn eof_read_be_i64<E>(&mut self) -> result::Result<Option<i64>, E>
where
E: From<io::Error>,
{
let mut buf = [0u8; 8];
if self.eof_read_exact(&mut buf)? {
Ok(Some(BigEndian::read_i64(&buf)))
} else {
Ok(None)
}
}
fn eof_read_be_f32<E>(&mut self) -> result::Result<Option<f32>, E>
where
E: From<io::Error>,
{
let mut buf = [0u8; 4];
if self.eof_read_exact(&mut buf)? {
Ok(Some(BigEndian::read_f32(&buf)))
} else {
Ok(None)
}
}
fn eof_read_be_f64<E>(&mut self) -> result::Result<Option<f64>, E>
where
E: From<io::Error>,
{
let mut buf = [0u8; 4];
if self.eof_read_exact(&mut buf)? {
Ok(Some(BigEndian::read_f64(&buf)))
} else {
Ok(None)
}
}
fn eof_read_be_c64<E>(&mut self) -> result::Result<Option<Complex<f32>>, E>
where
E: From<io::Error>,
{
let mut buf = [0u8; 8];
if self.eof_read_exact(&mut buf)? {
Ok(Some(Complex::new(
BigEndian::read_f32(&buf[..4]),
BigEndian::read_f32(&buf[4..]),
)))
} else {
Ok(None)
}
}
}
impl<R: Read> EofReadExactExt for R {
fn eof_read_exact<E>(&mut self, buf: &mut [u8]) -> result::Result<bool, E>
where
E: From<io::Error>,
{
let mut n_left = buf.len();
let mut ofs = 0;
while n_left > 0 {
let n_read = match self.read(&mut buf[ofs..]) {
Ok(n) => n,
Err(e) => {
if e.kind() == io::ErrorKind::Interrupted {
continue;
}
return Err(e.into());
}
};
if n_read == 0 {
return if ofs == 0 {
Ok(false) } else {
Err(
io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected end of file")
.into(),
)
};
}
ofs += n_read;
n_left -= n_read;
}
Ok(true) }
}