#![cfg_attr(test, feature(test))]
#![deny(warnings)]
#[cfg(unix)]
mod unix;
#[cfg(unix)]
use unix::{
duplicate,
lock_error,
lock_exclusive,
lock_exclusive_nonblock,
lock_shared,
lock_shared_nonblock,
unlock,
};
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use windows::{
duplicate,
lock_error,
lock_exclusive,
lock_exclusive_nonblock,
lock_shared,
lock_shared_nonblock,
unlock,
};
use std::fs::File;
use std::io::{Error, Result};
pub trait FileExt {
fn duplicate(&self) -> Result<File>;
fn lock_shared(&self) -> Result<()>;
fn lock_exclusive(&self) -> Result<()>;
fn lock_shared_nonblock(&self) -> Result<()>;
fn lock_exclusive_nonblock(&self) -> Result<()>;
fn unlock(&self) -> Result<()>;
}
impl FileExt for File {
fn duplicate(&self) -> Result<File> {
duplicate(self)
}
fn lock_shared(&self) -> Result<()> {
lock_shared(self)
}
fn lock_exclusive(&self) -> Result<()> {
lock_exclusive(self)
}
fn lock_shared_nonblock(&self) -> Result<()> {
lock_shared_nonblock(self)
}
fn lock_exclusive_nonblock(&self) -> Result<()> {
lock_exclusive_nonblock(self)
}
fn unlock(&self) -> Result<()> {
unlock(self)
}
}
pub fn lock_contended_error() -> Error {
lock_error()
}
#[cfg(test)]
mod test {
extern crate tempdir;
extern crate test;
use std::fs;
use super::{lock_contended_error, FileExt};
use std::io::{Read, Seek, SeekFrom, Write};
#[test]
fn duplicate() {
let tempdir = tempdir::TempDir::new("fs2").unwrap();
let path = tempdir.path().join("fs2");
let mut file1 =
fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
let mut file2 = file1.duplicate().unwrap();
file1.write_all(b"foo").unwrap();
drop(file1);
let mut buf = vec![];
file2.read_to_end(&mut buf).unwrap();
assert_eq!(0, buf.len());
file2.seek(SeekFrom::Start(0)).unwrap();
file2.read_to_end(&mut buf).unwrap();
assert_eq!(&buf, &b"foo");
}
#[test]
fn lock_shared() {
let tempdir = tempdir::TempDir::new("fs2").unwrap();
let path = tempdir.path().join("fs2");
let file1 = fs::OpenOptions::new().create(true).read(true).open(&path).unwrap();
let file2 = fs::OpenOptions::new().create(true).read(true).open(&path).unwrap();
let file3 = fs::OpenOptions::new().create(true).read(true).open(&path).unwrap();
file1.lock_shared().unwrap();
file2.lock_shared().unwrap();
assert_eq!(file3.lock_exclusive_nonblock().unwrap_err().raw_os_error(),
lock_contended_error().raw_os_error());
file1.unlock().unwrap();
assert_eq!(file3.lock_exclusive_nonblock().unwrap_err().raw_os_error(),
lock_contended_error().raw_os_error());
file2.unlock().unwrap();
file3.lock_exclusive().unwrap();
}
#[test]
fn lock_exclusive() {
let tempdir = tempdir::TempDir::new("fs2").unwrap();
let path = tempdir.path().join("fs2");
let file1 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
let file2 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
file1.lock_exclusive().unwrap();
assert_eq!(file2.lock_exclusive_nonblock().unwrap_err().raw_os_error(),
lock_contended_error().raw_os_error());
assert_eq!(file2.lock_shared_nonblock().unwrap_err().raw_os_error(),
lock_contended_error().raw_os_error());
file1.unlock().unwrap();
file2.lock_exclusive().unwrap();
}
#[test]
fn lock_cleanup() {
let tempdir = tempdir::TempDir::new("fs2").unwrap();
let path = tempdir.path().join("fs2");
let file1 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
let file2 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
file1.lock_exclusive().unwrap();
assert_eq!(file2.lock_shared_nonblock().unwrap_err().raw_os_error(),
lock_contended_error().raw_os_error());
drop(file1);
file2.lock_shared().unwrap();
}
#[bench]
fn bench_duplicate(b: &mut test::Bencher) {
let tempdir = tempdir::TempDir::new("fs2").unwrap();
let path = tempdir.path().join("fs2");
let file = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
b.iter(|| test::black_box(file.duplicate().unwrap()));
}
#[bench]
fn bench_lock_unlock(b: &mut test::Bencher) {
let tempdir = tempdir::TempDir::new("fs2").unwrap();
let path = tempdir.path().join("fs2");
let file = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
b.iter(|| {
file.lock_exclusive().unwrap();
file.unlock().unwrap();
});
}
}