use std::{fmt, io};
#[cfg(windows)]
mod windows;
#[cfg(unix)]
mod unix;
#[derive(Debug)]
pub enum FileLockError {
AlreadyLocked,
Io(io::Error),
}
impl fmt::Display for FileLockError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FileLockError::AlreadyLocked => f.write_str("the file is already locked"),
FileLockError::Io(err) => write!(f, "I/O error: {}", err),
}
}
}
impl std::error::Error for FileLockError {}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum FileLockMode {
Exclusive,
Shared,
}
pub trait AdvisoryFileLock {
fn lock(&self, file_lock_mode: FileLockMode) -> Result<(), FileLockError>;
fn try_lock(&self, file_lock_mode: FileLockMode) -> Result<(), FileLockError>;
fn unlock(&self) -> Result<(), FileLockError>;
}
#[cfg(test)]
mod tests {
use super::*;
use std::env::temp_dir;
use std::fs::File;
#[test]
fn simple_shared_lock() {
let mut test_file = temp_dir();
test_file.push("shared_lock");
File::create(&test_file).unwrap();
{
let f1 = File::open(&test_file).unwrap();
f1.lock(FileLockMode::Shared).unwrap();
let f2 = File::open(&test_file).unwrap();
f2.lock(FileLockMode::Shared).unwrap();
}
std::fs::remove_file(&test_file).unwrap();
}
#[test]
fn simple_exclusive_lock() {
let mut test_file = temp_dir();
test_file.push("exclusive_lock");
File::create(&test_file).unwrap();
{
let f1 = File::open(&test_file).unwrap();
f1.lock(FileLockMode::Exclusive).unwrap();
let f2 = File::open(&test_file).unwrap();
assert!(f2.try_lock(FileLockMode::Exclusive).is_err());
}
std::fs::remove_file(&test_file).unwrap();
}
#[test]
fn simple_shared_exclusive_lock() {
let mut test_file = temp_dir();
test_file.push("shared_exclusive_lock");
File::create(&test_file).unwrap();
{
let f1 = File::open(&test_file).unwrap();
f1.lock(FileLockMode::Shared).unwrap();
let f2 = File::open(&test_file).unwrap();
assert!(matches!(
f2.try_lock(FileLockMode::Exclusive),
Err(FileLockError::AlreadyLocked)
));
}
std::fs::remove_file(&test_file).unwrap();
}
#[test]
fn simple_exclusive_shared_lock() {
let mut test_file = temp_dir();
test_file.push("exclusive_shared_lock");
File::create(&test_file).unwrap();
{
let f1 = File::open(&test_file).unwrap();
f1.lock(FileLockMode::Exclusive).unwrap();
let f2 = File::open(&test_file).unwrap();
assert!(f2.try_lock(FileLockMode::Shared).is_err());
}
std::fs::remove_file(&test_file).unwrap();
}
}