fd_lock/rw_lock.rs
1use crate::read_guard::RwLockReadGuard;
2use crate::sys;
3use crate::write_guard::RwLockWriteGuard;
4use std::io;
5
6/// Advisory reader-writer lock for files.
7///
8/// This type of lock allows a number of readers or at most one writer at any point
9/// in time. The write portion of this lock typically allows modification of the
10/// underlying data (exclusive access) and the read portion of this lock typically
11/// allows for read-only access (shared access).
12#[derive(Debug)]
13pub struct RwLock<T: sys::AsOpenFile> {
14 lock: sys::RwLock<T>,
15}
16
17impl<T: sys::AsOpenFile> RwLock<T> {
18 /// Create a new instance.
19 ///
20 /// # Examples
21 ///
22 /// ```no_run
23 /// use fd_lock::RwLock;
24 /// use std::fs::File;
25 ///
26 /// fn main() -> std::io::Result<()> {
27 /// let mut f = RwLock::new(File::open("foo.txt")?);
28 /// Ok(())
29 /// }
30 /// ```
31 #[inline]
32 pub fn new(inner: T) -> Self {
33 Self {
34 lock: sys::RwLock::new(inner),
35 }
36 }
37
38 /// Locks this lock with shared read access, blocking the current thread
39 /// until it can be acquired.
40 ///
41 /// The calling thread will be blocked until there are no more writers which
42 /// hold the lock. There may be other readers currently inside the lock when
43 /// this method returns. This method does not provide any guarantees with
44 /// respect to the ordering of whether contentious readers or writers will
45 /// acquire the lock first.
46 ///
47 /// Returns an RAII guard which will release this thread's shared access
48 /// once it is dropped.
49 ///
50 /// # Errors
51 ///
52 /// On Unix this may return an `ErrorKind::Interrupted` if the operation was
53 /// interrupted by a signal handler.
54 #[inline]
55 pub fn read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
56 let guard = self.lock.read()?;
57 Ok(RwLockReadGuard::new(guard))
58 }
59
60 /// Attempts to acquire this lock with shared read access.
61 ///
62 /// If the access could not be granted at this time, then `Err` is returned.
63 /// Otherwise, an RAII guard is returned which will release the shared access
64 /// when it is dropped.
65 ///
66 /// This function does not block.
67 ///
68 /// This function does not provide any guarantees with respect to the ordering
69 /// of whether contentious readers or writers will acquire the lock first.
70 ///
71 /// # Errors
72 ///
73 /// If the lock is already held and `ErrorKind::WouldBlock` error is returned.
74 /// On Unix this may return an `ErrorKind::Interrupted` if the operation was
75 /// interrupted by a signal handler.
76 #[inline]
77 pub fn try_read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
78 let guard = self.lock.try_read()?;
79 Ok(RwLockReadGuard::new(guard))
80 }
81
82 /// Locks this lock with exclusive write access, blocking the current thread
83 /// until it can be acquired.
84 ///
85 /// This function will not return while other writers or other readers
86 /// currently have access to the lock.
87 ///
88 /// Returns an RAII guard which will drop the write access of this rwlock
89 /// when dropped.
90 ///
91 /// # Errors
92 ///
93 /// On Unix this may return an `ErrorKind::Interrupted` if the operation was
94 /// interrupted by a signal handler.
95 #[inline]
96 pub fn write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
97 let guard = self.lock.write()?;
98 Ok(RwLockWriteGuard::new(guard))
99 }
100
101 /// Attempts to lock this lock with exclusive write access.
102 ///
103 /// If the lock could not be acquired at this time, then `Err` is returned.
104 /// Otherwise, an RAII guard is returned which will release the lock when
105 /// it is dropped.
106 ///
107 /// # Errors
108 ///
109 /// If the lock is already held and `ErrorKind::WouldBlock` error is returned.
110 /// On Unix this may return an `ErrorKind::Interrupted` if the operation was
111 /// interrupted by a signal handler.
112 #[inline]
113 pub fn try_write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
114 let guard = self.lock.try_write()?;
115 Ok(RwLockWriteGuard::new(guard))
116 }
117
118 /// Consumes this `RwLock`, returning the underlying data.
119 #[inline]
120 pub fn into_inner(self) -> T
121 where
122 T: Sized,
123 {
124 self.lock.into_inner()
125 }
126}