zng_ext_fs_watcher/
lock.rsuse std::time::Duration;
#[cfg(not(target_arch = "wasm32"))]
pub use fs4::fs_std::FileExt;
#[cfg(target_arch = "wasm32")]
pub trait FileExt {
fn try_lock_shared(&self) -> std::io::Result<()> {
not_supported()
}
fn try_lock_exclusive(&self) -> std::io::Result<()> {
not_supported()
}
fn unlock(&self) -> std::io::Result<()> {
not_supported()
}
}
#[cfg(target_arch = "wasm32")]
impl FileExt for std::fs::File {}
#[cfg(target_arch = "wasm32")]
fn not_supported() -> std::io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"operation not supported on wasm yet",
))
}
pub fn lock_exclusive(file: &impl FileExt, timeout: Duration) -> std::io::Result<()> {
lock_timeout(file, |f| f.try_lock_exclusive(), timeout)
}
pub fn lock_shared(file: &impl FileExt, timeout: Duration) -> std::io::Result<()> {
lock_timeout(file, |f| f.try_lock_shared(), timeout)
}
#[cfg(target_arch = "wasm32")]
pub fn lock_timeout<F: FileExt>(_: &F, _: impl Fn(&F) -> std::io::Result<()>, _: Duration) -> std::io::Result<()> {
not_supported()
}
#[cfg(not(target_arch = "wasm32"))]
pub fn lock_timeout<F: FileExt>(file: &F, try_lock: impl Fn(&F) -> std::io::Result<()>, mut timeout: Duration) -> std::io::Result<()> {
let mut locked_error = None;
loop {
match try_lock(file) {
Ok(()) => return Ok(()),
Err(e) => {
if e.kind() != std::io::ErrorKind::WouldBlock
&& e.raw_os_error() != locked_error.get_or_insert_with(fs4::lock_contended_error).raw_os_error()
{
return Err(e);
}
const INTERVAL: Duration = Duration::from_millis(10);
timeout = timeout.saturating_sub(INTERVAL);
if timeout.is_zero() {
return Err(std::io::Error::new(std::io::ErrorKind::TimedOut, e));
} else {
std::thread::sleep(INTERVAL.min(timeout));
}
}
}
}
}
pub fn unlock_ok(file: &impl FileExt) -> std::io::Result<()> {
if let Err(e) = file.unlock() {
if let Some(_code) = e.raw_os_error() {
#[cfg(windows)]
if _code == 158 {
return Ok(());
}
#[cfg(unix)]
if _code == 22 {
return Ok(());
}
}
Err(e)
} else {
Ok(())
}
}