use crate::read_guard::RwLockReadGuard; use crate::sys; use crate::write_guard::RwLockWriteGuard; use std::io; /// Advisory reader-writer lock for files. /// /// This type of lock allows a number of readers or at most one writer at any point /// in time. The write portion of this lock typically allows modification of the /// underlying data (exclusive access) and the read portion of this lock typically /// allows for read-only access (shared access). #[derive(Debug)] pub struct RwLock { lock: sys::RwLock, } impl RwLock { /// Create a new instance. /// /// # Examples /// /// ```no_run /// use fd_lock::RwLock; /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { /// let mut f = RwLock::new(File::open("foo.txt")?); /// Ok(()) /// } /// ``` #[inline] pub fn new(inner: T) -> Self { Self { lock: sys::RwLock::new(inner), } } /// Locks this lock with shared read access, blocking the current thread /// until it can be acquired. /// /// The calling thread will be blocked until there are no more writers which /// hold the lock. There may be other readers currently inside the lock when /// this method returns. This method does not provide any guarantees with /// respect to the ordering of whether contentious readers or writers will /// acquire the lock first. /// /// Returns an RAII guard which will release this thread's shared access /// once it is dropped. /// /// # Errors /// /// On Unix this may return an `ErrorKind::Interrupted` if the operation was /// interrupted by a signal handler. #[inline] pub fn read(&self) -> io::Result> { let guard = self.lock.read()?; Ok(RwLockReadGuard::new(guard)) } /// Attempts to acquire this lock with shared read access. /// /// If the access could not be granted at this time, then `Err` is returned. /// Otherwise, an RAII guard is returned which will release the shared access /// when it is dropped. /// /// This function does not block. /// /// This function does not provide any guarantees with respect to the ordering /// of whether contentious readers or writers will acquire the lock first. /// /// # Errors /// /// If the lock is already held and `ErrorKind::WouldBlock` error is returned. /// On Unix this may return an `ErrorKind::Interrupted` if the operation was /// interrupted by a signal handler. #[inline] pub fn try_read(&self) -> io::Result> { let guard = self.lock.try_read()?; Ok(RwLockReadGuard::new(guard)) } /// Locks this lock with exclusive write access, blocking the current thread /// until it can be acquired. /// /// This function will not return while other writers or other readers /// currently have access to the lock. /// /// Returns an RAII guard which will drop the write access of this rwlock /// when dropped. /// /// # Errors /// /// On Unix this may return an `ErrorKind::Interrupted` if the operation was /// interrupted by a signal handler. #[inline] pub fn write(&mut self) -> io::Result> { let guard = self.lock.write()?; Ok(RwLockWriteGuard::new(guard)) } /// Attempts to lock this lock with exclusive write access. /// /// If the lock could not be acquired at this time, then `Err` is returned. /// Otherwise, an RAII guard is returned which will release the lock when /// it is dropped. /// /// # Errors /// /// If the lock is already held and `ErrorKind::WouldBlock` error is returned. /// On Unix this may return an `ErrorKind::Interrupted` if the operation was /// interrupted by a signal handler. #[inline] pub fn try_write(&mut self) -> io::Result> { let guard = self.lock.try_write()?; Ok(RwLockWriteGuard::new(guard)) } /// Consumes this `RwLock`, returning the underlying data. #[inline] pub fn into_inner(self) -> T where T: Sized, { self.lock.into_inner() } }