use super::{Read, Write};
use darkbio_clock::Clock;
use std::io;
use std::time::Instant;
#[derive(Debug)]
pub struct Memory<T> {
pub inner: T,
clock: Clock,
read_deadline: Option<Instant>,
write_deadline: Option<Instant>,
}
impl<T> Memory<T> {
pub fn new(inner: T, clock: &Clock) -> Self {
Self {
inner,
clock: clock.clone(),
read_deadline: None,
write_deadline: None,
}
}
}
impl<T: io::Read> io::Read for Memory<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
check_deadline(&self.clock, self.read_deadline)?;
self.inner.read(buf)
}
}
impl<T: io::Read> Read for Memory<T> {
fn clock(&self) -> Clock {
self.clock.clone()
}
fn set_read_deadline(&mut self, deadline: Option<Instant>) -> io::Result<()> {
self.read_deadline = deadline;
Ok(())
}
}
impl<T: io::Write> io::Write for Memory<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
check_deadline(&self.clock, self.write_deadline)?;
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
check_deadline(&self.clock, self.write_deadline)?;
self.inner.flush()
}
}
impl<T: io::Write> Write for Memory<T> {
fn clock(&self) -> Clock {
self.clock.clone()
}
fn set_write_deadline(&mut self, deadline: Instant) -> io::Result<()> {
self.write_deadline = Some(deadline);
Ok(())
}
}
fn check_deadline(clock: &Clock, deadline: Option<Instant>) -> io::Result<()> {
if deadline.is_some_and(|deadline| clock.now() >= deadline) {
Err(io::ErrorKind::TimedOut.into())
} else {
Ok(())
}
}
#[cfg(any(test, feature = "fuzz"))]
pub fn test_clock() -> darkbio_clock::TestClock {
let mut tester = darkbio_clock::TestClock::new();
tester.advance(std::time::Duration::from_secs(86400));
tester
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{Read as _, Write as _};
use std::time::Duration;
#[test]
fn test_independent_deadlines_and_reuse() {
let tester = test_clock();
let clock = tester.clock();
let mut memory = Memory::new(io::Cursor::new(vec![1, 2, 3]), &clock);
memory.set_read_deadline(Some(clock.now())).unwrap();
assert_eq!(
memory.read_exact(&mut [0]).unwrap_err().kind(),
io::ErrorKind::TimedOut
);
memory.write_all(&[4]).unwrap();
assert_eq!(memory.inner.get_ref(), &[4, 2, 3]);
memory.set_write_deadline(clock.now()).unwrap();
memory.set_read_deadline(None).unwrap();
let mut rest = Vec::new();
memory.read_to_end(&mut rest).unwrap();
assert_eq!(rest, [2, 3]);
assert_eq!(
memory.write_all(&[5]).unwrap_err().kind(),
io::ErrorKind::TimedOut
);
assert_eq!(memory.flush().unwrap_err().kind(), io::ErrorKind::TimedOut);
assert_eq!(memory.inner.get_ref(), &[4, 2, 3]);
memory
.set_write_deadline(clock.now() + Duration::from_secs(1))
.unwrap();
memory.write_all(&[5]).unwrap();
memory.flush().unwrap();
assert_eq!(memory.inner.get_ref(), &[4, 2, 3, 5]);
}
}