#![allow(deprecated)]
use std::fs::File;
use std::os::unix::io::AsRawFd;
use either::{Either, Left, Right};
use nix::errno::Errno;
use nix::fcntl::{flock, FlockArg};
use nix::Result;
#[derive(Debug)]
pub struct UnlockedFile(File);
#[derive(Debug)]
pub struct LockedFileShared(File);
#[derive(Debug)]
pub struct LockedFileExclusive(File);
impl From<File> for UnlockedFile {
fn from(file: File) -> Self {
Self(file)
}
}
impl TryFrom<&std::path::Path> for UnlockedFile {
type Error = std::io::Error;
fn try_from(path: &std::path::Path) -> std::io::Result<Self> {
std::fs::OpenOptions::new()
.append(true)
.create(true)
.open(path)
.map(UnlockedFile)
}
}
impl TryFrom<&std::path::PathBuf> for UnlockedFile {
type Error = std::io::Error;
fn try_from(path: &std::path::PathBuf) -> std::io::Result<Self> {
Self::try_from(path.as_path())
}
}
impl UnlockedFile {
pub fn try_lock_shared(self) -> Result<Either<Self, LockedFileShared>> {
match flock(self.0.as_raw_fd(), FlockArg::LockSharedNonblock) {
Ok(()) => Ok(Right(LockedFileShared(self.0))),
Err(Errno::EAGAIN) => Ok(Left(self)),
Err(err) => Err(err),
}
}
pub fn lock_shared(self) -> Result<LockedFileShared> {
flock(self.0.as_raw_fd(), FlockArg::LockShared)?;
Ok(LockedFileShared(self.0))
}
pub fn try_lock_exclusive(self) -> Result<Either<Self, LockedFileExclusive>> {
match flock(self.0.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
Ok(()) => Ok(Right(LockedFileExclusive(self.0))),
Err(Errno::EAGAIN) => Ok(Left(self)),
Err(err) => Err(err),
}
}
pub fn lock_exclusive(self) -> Result<LockedFileExclusive> {
flock(self.0.as_raw_fd(), FlockArg::LockExclusive)?;
Ok(LockedFileExclusive(self.0))
}
}
impl LockedFileShared {
pub fn try_lock_exclusive(self) -> Result<Either<Self, LockedFileExclusive>> {
match flock(self.0.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
Ok(()) => Ok(Right(LockedFileExclusive(self.0))),
Err(Errno::EAGAIN) => Ok(Left(self)),
Err(err) => Err(err),
}
}
pub fn lock_exclusive(self) -> Result<LockedFileExclusive> {
flock(self.0.as_raw_fd(), FlockArg::LockExclusive)?;
Ok(LockedFileExclusive(self.0))
}
pub fn try_unlock(self) -> Result<Either<Self, UnlockedFile>> {
match flock(self.0.as_raw_fd(), FlockArg::UnlockNonblock) {
Ok(()) => Ok(Right(UnlockedFile(self.0))),
Err(Errno::EAGAIN) => Ok(Left(self)),
Err(err) => Err(err),
}
}
pub fn unlock(self) -> Result<UnlockedFile> {
flock(self.0.as_raw_fd(), FlockArg::Unlock)?;
Ok(UnlockedFile(self.0))
}
}
impl LockedFileExclusive {
pub fn try_lock_shared(self) -> Result<Either<Self, LockedFileShared>> {
match flock(self.0.as_raw_fd(), FlockArg::LockSharedNonblock) {
Ok(()) => Ok(Right(LockedFileShared(self.0))),
Err(Errno::EAGAIN) => Ok(Left(self)),
Err(err) => Err(err),
}
}
pub fn lock_shared(self) -> Result<LockedFileShared> {
flock(self.0.as_raw_fd(), FlockArg::LockShared)?;
Ok(LockedFileShared(self.0))
}
pub fn try_unlock(self) -> Result<Either<Self, UnlockedFile>> {
match flock(self.0.as_raw_fd(), FlockArg::UnlockNonblock) {
Ok(()) => Ok(Right(UnlockedFile(self.0))),
Err(Errno::EAGAIN) => Ok(Left(self)),
Err(err) => Err(err),
}
}
pub fn unlock(self) -> Result<UnlockedFile> {
flock(self.0.as_raw_fd(), FlockArg::Unlock)?;
Ok(UnlockedFile(self.0))
}
}