#![deny(missing_docs)]
use std::io;
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ThrottledReader<R> {
reader: R,
read_budget: Option<usize>,
}
impl<R> ThrottledReader<R> {
pub fn new(reader: R) -> Self {
ThrottledReader {
reader,
read_budget: None,
}
}
pub fn set_limit(&mut self, limit: usize) {
self.read_budget = Some(limit);
}
pub fn unthrottle(&mut self) {
self.read_budget = None;
}
pub fn remaining(&self) -> Option<usize> {
self.read_budget
}
pub fn into_inner(self) -> R {
self.reader
}
}
impl<R> io::Read for ThrottledReader<R>
where
R: io::Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.read_budget.map(|r| r.checked_sub(1)) {
None => {
self.reader.read(buf)
}
Some(None) => {
Err(io::Error::new(io::ErrorKind::WouldBlock, "read throttled"))
}
Some(Some(remaining)) => {
self.read_budget = Some(remaining);
self.reader.read(buf)
}
}
}
}
impl<R> From<R> for ThrottledReader<R> {
fn from(reader: R) -> Self {
ThrottledReader::new(reader)
}
}
impl<R> Default for ThrottledReader<R>
where
R: Default,
{
fn default() -> Self {
ThrottledReader {
reader: R::default(),
read_budget: None,
}
}
}
use std::ops::{Deref, DerefMut};
impl<R> Deref for ThrottledReader<R> {
type Target = R;
fn deref(&self) -> &Self::Target {
&self.reader
}
}
impl<R> DerefMut for ThrottledReader<R> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.reader
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::prelude::*;
#[test]
fn it_works() {
let mut s = ThrottledReader::new(io::empty());
assert_eq!(s.read(&mut [0]).unwrap(), 0);
assert_eq!(s.read(&mut [0]).unwrap(), 0);
assert_eq!(s.read(&mut [0]).unwrap(), 0);
s.set_limit(2);
assert_eq!(s.read(&mut [0]).unwrap(), 0); assert_eq!(s.remaining(), Some(1));
assert_eq!(s.read(&mut [0]).unwrap(), 0); assert_eq!(s.remaining(), Some(0));
assert_eq!(
s.read(&mut [0]).unwrap_err().kind(),
io::ErrorKind::WouldBlock
); assert_eq!(s.remaining(), Some(0));
assert_eq!(
s.read(&mut [0]).unwrap_err().kind(),
io::ErrorKind::WouldBlock
); assert_eq!(s.remaining(), Some(0));
s.unthrottle();
assert_eq!(s.read(&mut [0]).unwrap(), 0);
assert_eq!(s.read(&mut [0]).unwrap(), 0);
assert_eq!(s.read(&mut [0]).unwrap(), 0);
}
}