#![cfg(any(target_os="android", target_os="l4re", target_os="linux", windows))]
#![doc(cfg(any(target_os="android", target_os="l4re", target_os="linux", windows)))]
use {
core::{
hash::{Hash, Hasher},
time::Duration,
},
std::{
io::ErrorKind,
time::Instant,
},
crate::{Result, SLEEP_DURATION},
super::Namaste,
};
#[cfg(feature="async-std")]
use core::future::Future;
#[cfg(any(target_os="android", target_os="l4re", target_os="linux"))]
#[doc(cfg(any(target_os="android", target_os="l4re", target_os="linux")))]
mod linux;
#[cfg(windows)]
#[doc(cfg(windows))]
mod windows;
macro_rules! try_read { ($self: ident, $timeout: ident) => {{
let start = Instant::now();
loop {
match async_call!($self.read()) {
Ok(read) => return Ok(read),
Err(_) => {
sleep!();
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()")),
};
},
};
}
}}}
macro_rules! try_write { ($self: ident, $timeout: ident) => {{
let start = Instant::now();
loop {
match async_call!($self.write()) {
Ok(write) => return Ok(write),
Err(_) => {
sleep!();
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()")),
};
},
};
}
}}}
macro_rules! try_read_with { ($self: ident, $timeout: ident, $f: ident) => {{
let _read = async_call!($self.try_read($timeout))?;
#[cfg(not(feature="async-std"))]
let result = $f();
#[cfg(feature="async-std")]
let result = $f.await;
Ok(result)
}}}
macro_rules! try_write_with { ($self: ident, $timeout: ident, $f: ident) => {{
let _write = async_call!($self.try_write($timeout))?;
#[cfg(not(feature="async-std"))]
let result = $f();
#[cfg(feature="async-std")]
let result = $f.await;
Ok(result)
}}}
#[derive(Debug, Clone)]
pub struct RwNamaste<R, W> {
read_id: R,
write_id: W,
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,
write_id,
timeout,
})
}
#[cfg(not(feature="async-std"))]
#[doc(cfg(not(feature="async-std")))]
pub fn try_read(&self, timeout: Option<Duration>) -> Result<Namaste> {
try_read!(self, timeout)
}
#[cfg(feature="async-std")]
#[doc(cfg(feature="async-std"))]
pub async fn try_read(&self, timeout: Option<Duration>) -> Result<Namaste> {
try_read!(self, timeout)
}
#[cfg(not(feature="async-std"))]
#[doc(cfg(not(feature="async-std")))]
pub fn try_read_with<F, T>(&self, timeout: Option<Duration>, f: F) -> Result<T> where F: FnOnce() -> T {
try_read_with!(self, timeout, f)
}
#[cfg(feature="async-std")]
#[doc(cfg(feature="async-std"))]
pub async fn try_read_with<F, T>(&self, timeout: Option<Duration>, f: F) -> Result<T> where F: Future<Output=T> {
try_read_with!(self, timeout, f)
}
#[cfg(not(feature="async-std"))]
#[doc(cfg(not(feature="async-std")))]
pub fn try_write(&self, timeout: Option<Duration>) -> Result<Namaste> {
try_write!(self, timeout)
}
#[cfg(feature="async-std")]
#[doc(cfg(feature="async-std"))]
pub async fn try_write(&self, timeout: Option<Duration>) -> Result<Namaste> {
try_write!(self, timeout)
}
#[cfg(not(feature="async-std"))]
#[doc(cfg(not(feature="async-std")))]
pub fn try_write_with<F, T>(&self, timeout: Option<Duration>, f: F) -> Result<T> where F: FnOnce() -> T {
try_write_with!(self, timeout, f)
}
#[cfg(feature="async-std")]
#[doc(cfg(feature="async-std"))]
pub async fn try_write_with<F, T>(&self, timeout: Option<Duration>, f: F) -> Result<T> where F: Future<Output=T> {
try_write_with!(self, timeout, f)
}
}
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);
}
}