use {
core::{
hash::{Hash, Hasher},
time::Duration,
},
std::{
io::ErrorKind,
thread,
time::Instant,
},
crate::{Result, SLEEP_DURATION},
super::Namaste,
};
#[cfg(not(windows))]
mod linux;
#[cfg(windows)]
mod windows;
#[derive(Debug)]
pub struct RwNamaste<R, W> where R: AsRef<[u8]>, W: AsRef<[u8]> {
read_id: R,
read: Option<Namaste>,
write_id: W,
write: Option<Namaste>,
timeout: Duration,
}
impl<R, W> RwNamaste<R, W> where R: AsRef<[u8]>, W: AsRef<[u8]> {
pub fn make(read_id: R, write_id: W, timeout: Duration) -> Result<Self> {
if read_id.as_ref() == write_id.as_ref() {
return Err(err!("Read ID must be different to write ID"));
}
if timeout.is_zero() {
return Err(err!("Timeout must not be zero"));
}
Ok(Self {
read_id,
read: None,
write_id,
write: None,
timeout,
})
}
pub fn try_read(&mut self, timeout: Option<Duration>) -> Result<()> {
let start = Instant::now();
loop {
match self.read() {
Ok(()) => return Ok(()),
Err(_) => {
thread::sleep(SLEEP_DURATION);
match Instant::now().checked_duration_since(start) {
Some(duration) => if duration >= timeout.unwrap_or(self.timeout) {
return Err(err!(ErrorKind::TimedOut, "Timed out waiting for a read"));
},
None => return Err(err!("Failed calling Instant::checked_duration_since()")),
};
},
};
}
}
pub fn try_read_with<F, T>(&mut self, timeout: Option<Duration>, f: F) -> Result<T> where F: FnOnce() -> T {
self.try_read(timeout)?;
let result = f();
self.drop_read();
Ok(result)
}
pub fn drop_read(&mut self) {
self.read.take();
}
pub fn try_write(&mut self, timeout: Option<Duration>) -> Result<()> {
let start = Instant::now();
loop {
match self.write() {
Ok(()) => return Ok(()),
Err(_) => {
thread::sleep(SLEEP_DURATION);
match Instant::now().checked_duration_since(start) {
Some(duration) => if duration >= timeout.unwrap_or(self.timeout) {
return Err(err!(ErrorKind::TimedOut, "Timed out waiting for a write"));
},
None => return Err(err!("Failed calling Instant::checked_duration_since()")),
};
},
};
}
}
pub fn try_write_with<F, T>(&mut self, timeout: Option<Duration>, f: F) -> Result<T> where F: FnOnce() -> T {
self.try_write(timeout)?;
let result = f();
self.drop_write();
Ok(result)
}
pub fn drop_write(&mut self) {
self.write.take();
}
}
impl<R, W> Clone for RwNamaste<R, W> where R: AsRef<[u8]> + Clone, W: AsRef<[u8]> + Clone {
fn clone(&self) -> Self {
Self {
read_id: self.read_id.clone(),
read: None,
write_id: self.write_id.clone(),
write: None,
timeout: self.timeout,
}
}
}
impl<R, W> Eq for RwNamaste<R, W> where R: AsRef<[u8]>, W: AsRef<[u8]> {}
impl<R, W> PartialEq for RwNamaste<R, W> where R: AsRef<[u8]>, W: AsRef<[u8]> {
fn eq(&self, other: &Self) -> bool {
self.read_id.as_ref() == other.read_id.as_ref() && self.write_id.as_ref() == other.write_id.as_ref()
}
}
impl<R, W> Hash for RwNamaste<R, W> where R: AsRef<[u8]>, W: AsRef<[u8]> {
fn hash<H>(&self, h: &mut H) where H: Hasher {
self.read_id.as_ref().hash(h);
self.write_id.as_ref().hash(h);
}
}