raii_flock/
lib.rs

1//! Little library implementing a wrapper over a file that's locked on creation and unlocked when
2//! it goes out of scope.
3
4use ::{
5        fs2::FileExt,
6        std::{
7            fs::File,
8            io::{self, SeekFrom, prelude::*},
9            ops::{Deref, DerefMut},
10            thread::panicking,
11        },
12};
13
14/// Wrapper over a file that calls [`FileExt::unlock`] at [dropping][`Drop`].
15#[derive(Debug)]
16pub struct FileLock<'a>(pub &'a File);
17
18impl<'a> FileLock<'a> {
19    /// Creates a `Self` instance calling [`FileExt::try_lock_shared`] on `f` and returning any
20    /// error that could have caused.
21    pub fn try_wrap_shared(f: &'a File) -> io::Result<Self> {
22        f.try_lock_shared()?;
23        Ok(Self(f))
24    }
25
26    /// Creates a `Self` instance calling [`FileExt::lock_shared`] on `f` and returning any
27    /// error that could have caused.
28    pub fn wrap_shared(f: &'a File) -> io::Result<Self> {
29        f.lock_shared()?;
30        Ok(Self(f))
31    }
32
33    /// Creates a `Self` instance calling [`FileExt::try_lock_exclusive`] on `f` and returning any
34    /// error that could have caused.
35    pub fn try_wrap_exclusive(f: &'a File) -> io::Result<Self> {
36        f.try_lock_exclusive()?;
37        Ok(Self(f))
38    }
39
40    /// Creates a `Self` instance calling [`FileExt::lock_exclusive`] on `f` and returning any
41    /// error that could have caused.
42    pub fn wrap_exclusive(f: &'a File) -> io::Result<Self> {
43        f.lock_exclusive()?;
44        Ok(Self(f))
45    }
46}
47
48impl<'a> Write for FileLock<'a> {
49    #[inline(always)]
50    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
51        self.0.write(buf)
52    }
53
54    #[inline(always)]
55    fn flush(&mut self) -> io::Result<()> {
56        self.0.flush()
57    }
58}
59
60impl<'a> Read for FileLock<'a> {
61    #[inline(always)]
62    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
63        self.0.read(buf)
64    }
65}
66
67impl<'a> Seek for FileLock<'a> {
68    #[inline(always)]
69    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
70        self.0.seek(pos)
71    }
72}
73
74impl<'a> Deref for FileLock<'a> {
75    type Target = &'a File;
76
77    #[inline(always)]
78    fn deref(&self) -> &Self::Target {
79        &self.0
80    }
81}
82
83impl<'a> DerefMut for FileLock<'a> {
84    #[inline(always)]
85    fn deref_mut(&mut self) -> &mut Self::Target {
86        &mut self.0
87    }
88}
89
90impl<'a> Drop for FileLock<'a> {
91    fn drop(&mut self) {
92        if let Err(e) = self.0.unlock() {
93            if panicking() {
94                eprintln!("error unlocking file lock: {}", e)
95            } else {
96                panic!("error unlocking file lock: {}", e)
97            }
98        }
99    }
100}