use std;
use std::io::Seek;
pub trait Pos {
fn pos(&mut self) -> usize;
fn size(&mut self) -> usize;
}
impl<T> Pos for T where T: Seek {
fn pos(&mut self) -> usize {
self.seek(std::io::SeekFrom::Current(0))
.expect("Could not check position")
as usize
}
fn size(&mut self) -> usize {
let old = self.seek(std::io::SeekFrom::Current(0))
.expect("Could not check position");
let size = self.seek(std::io::SeekFrom::End(0))
.expect("Could not look for end of stream");
self.seek(std::io::SeekFrom::Start(old))
.expect("Could not rewind");
size as usize
}
}
pub trait ReadConst {
fn read_const(&mut self, bytes: &[u8]) -> Result<(), std::io::Error>;
}
impl<T> ReadConst for T where T: std::io::Read {
fn read_const(&mut self, data: &[u8]) -> Result<(), std::io::Error> {
let mut buf = Vec::with_capacity(data.len());
unsafe { buf.set_len(data.len()); }
let bytes = self.read(&mut buf)?;
if bytes != data.len() || &buf as &[u8] != data {
debug!(target: "read_const", "Invalid data {:?}, expected {:?}",
String::from_utf8(buf.to_vec()),
String::from_utf8(data.to_vec())
);
let details = String::from_utf8(data.to_vec())
.unwrap_or_else(|_| "<invalid read_const string>".to_string());
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, details));
}
Ok(())
}
}
pub struct PoisonLock<S> {
state: S,
poisoned: bool
}
impl<S> PoisonLock<S> {
pub fn new(state: S) -> Self {
PoisonLock {
state,
poisoned: false
}
}
pub fn try<T, E, F>(&mut self, f: F) -> Result<T, E> where F: FnOnce(&mut S) -> Result<T, E> {
assert!(!self.poisoned, "State is poisoned");
f(&mut self.state)
.map_err(|err| {
self.poisoned = true;
err
})
}
pub fn poison(&mut self) {
self.poisoned = true;
}
pub fn is_poisoned(&self) -> bool {
self.poisoned
}
}