#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod test;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
use crate::unix as sys;
mod string;
mod fmt;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use crate::windows as sys;
pub use crate::{
string::{EitherOsStr, IntoOsString, ToOsStr},
sys::{Error, OsStr, OsString},
};
#[derive(Debug)]
pub struct LockFile {
locked: bool,
desc: sys::FileDesc,
}
impl LockFile {
pub fn open<P>(path: &P) -> Result<Self, Error>
where
P: ToOsStr + ?Sized,
{
let path = path.to_os_str()?;
let desc = sys::open(path.as_ref())?;
Ok(Self { locked: false, desc })
}
pub fn lock(&mut self) -> Result<(), Error> {
if self.locked {
panic!("Cannot lock if already owning a lock");
}
sys::lock(self.desc)?;
self.locked = true;
Ok(())
}
pub fn lock_with_pid(&mut self) -> Result<(), Error> {
if let Err(error) = self.lock() {
return Err(error);
}
let result = writeln!(fmt::Writer(self.desc), "{}", sys::pid());
if result.is_err() {
let _ = self.unlock();
}
result
}
pub fn try_lock(&mut self) -> Result<bool, Error> {
if self.locked {
panic!("Cannot lock if already owning a lock");
}
let lock_result = sys::try_lock(self.desc);
if let Ok(true) = lock_result {
self.locked = true;
}
lock_result
}
pub fn owns_lock(&self) -> bool {
self.locked
}
pub fn unlock(&mut self) -> Result<(), Error> {
if !self.locked {
panic!("Attempted to unlock already locked lockfile");
}
self.locked = false;
sys::unlock(self.desc)?;
sys::truncate(self.desc)?;
Ok(())
}
}
impl Drop for LockFile {
fn drop(&mut self) {
if self.locked {
let _ = self.unlock();
}
sys::close(self.desc);
}
}
#[cfg(windows)]
unsafe impl Send for LockFile {}
#[cfg(windows)]
unsafe impl Sync for LockFile {}