use std::io::{Result, ErrorKind as IoErrorKind}; use std::io::prelude::*; use std::time::{Instant, Duration}; // In milliseconds. const DELAY: u64 = 200; pub struct SlowWriter { inner: T, slow: bool, blocking: bool, last_write: Option, } impl SlowWriter { pub fn new(inner: T, slow: bool, blocking: bool) -> Self { Self { inner, slow, blocking, last_write: None, } } } fn emulate_nonblocking(last_io: &mut Option) -> Result<()> { match *last_io { Some(last_io_some) => if last_io_some + Duration::from_millis(DELAY) < Instant::now() { *last_io = None; return Err(IoErrorKind::WouldBlock.into()) }, None => *last_io = Some(Instant::now()), } Ok(()) } impl Write for SlowWriter { fn write(&mut self, data: &[u8]) -> Result { if self.slow { if self.blocking { std::thread::sleep(Duration::from_millis(DELAY)); } else { emulate_nonblocking(&mut self.last_write)? } } self.inner.write(data) } fn flush(&mut self) -> Result<()> { if self.slow { if self.blocking { std::thread::sleep(Duration::from_millis(DELAY)); } else { emulate_nonblocking(&mut self.last_write)?; } } self.inner.flush() } } pub struct SlowReader { inner: T, slow: bool, blocking: bool, last_read: Option, } impl SlowReader { pub fn new(inner: T, slow: bool, blocking: bool) -> Self { Self { inner, slow, blocking, last_read: None, } } } impl Read for SlowReader { fn read(&mut self, buffer: &mut [u8]) -> Result { if self.slow { if self.blocking { std::thread::sleep(Duration::from_millis(DELAY)); } else { emulate_nonblocking(&mut self.last_read)? } } self.inner.read(buffer) } }