use std::{
cmp::min,
io::{
self, Read, Write,
ErrorKind::{ Interrupted, UnexpectedEof, WriteZero }
}
};
pub trait ReadExt {
fn try_read_exact(&mut self, buf: &mut[u8], pos_cb: impl FnMut(usize))
-> Result<(), io::Error>;
fn try_drain(&mut self, len: usize, pos_cb: impl FnMut(usize)) -> Result<(), io::Error>;
}
impl<T: Read> ReadExt for T {
fn try_read_exact(&mut self, mut buf: &mut[u8], mut pos_cb: impl FnMut(usize))
-> Result<(), io::Error>
{
'read_loop: while !buf.is_empty() {
match self.read(&mut buf) {
Err(ref e) if e.kind() == Interrupted => continue 'read_loop,
Err(e) => Err(e)?,
Ok(0) => Err(io::Error::from(UnexpectedEof))?,
Ok(len) => {
buf = &mut buf[len..];
pos_cb(len)
}
}
}
Ok(())
}
fn try_drain(&mut self, mut len: usize, mut pos_cb: impl FnMut(usize))
-> Result<(), io::Error>
{
while len > 0 {
let buf = &mut[0; 4096][.. min(len, 4096)];
self.try_read_exact(buf, |read| {
len -= read;
pos_cb(read)
})?
}
Ok(())
}
}
pub trait WriteExt {
fn try_write_exact(&mut self, data: &[u8], counter: impl FnMut(usize))
-> Result<(), io::Error>;
fn try_fill(&mut self, len: usize, counter: impl FnMut(usize)) -> Result<(), io::Error>;
}
impl<T: Write> WriteExt for T {
fn try_write_exact(&mut self, mut data: &[u8], mut pos_cb: impl FnMut(usize))
-> Result<(), io::Error>
{
'write_loop: while !data.is_empty() {
match self.write(&data) {
Err(ref e) if e.kind() == Interrupted => continue 'write_loop,
Err(e) => Err(e)?,
Ok(0) => Err(io::Error::from(WriteZero))?,
Ok(len) => {
data = &data[len..];
pos_cb(len);
}
}
}
Ok(())
}
fn try_fill(&mut self, mut len: usize, mut pos_cb: impl FnMut(usize))
-> Result<(), io::Error>
{
while len > 0 {
let buf = &mut[0; 4096][.. min(len, 4096)];
self.try_write_exact(buf, |written| {
len -= written;
pos_cb(written)
})?
}
Ok(())
}
}
pub trait U64Ext {
fn ceil_to_multiple_of(&self, num: Self) -> Self;
}
impl U64Ext for u64 {
fn ceil_to_multiple_of(&self, num: Self) -> Self {
match *self % num {
0 => *self,
r => *self + (num - r)
}
}
}