1#![forbid(future_incompatible)]
45#![deny(missing_debug_implementations, nonstandard_style)]
46#![cfg_attr(doc, warn(missing_docs))]
47
48use sys::AsOpenFileExt;
49
50mod read_guard;
51mod write_guard;
52
53pub(crate) mod error;
54pub(crate) mod sys;
55
56pub use error::*;
57#[cfg(feature = "async")]
58pub use nonblocking::*;
59pub use read_guard::RwLockReadGuard;
60pub use sys::AsOpenFile;
61pub use write_guard::RwLockWriteGuard;
62
63pub mod blocking {
64 use super::*;
65
66 pub trait LockRead: AsOpenFile + std::io::Read {
67 fn lock_read(self) -> LockReadResult<Self>
68 where
69 Self: Sized;
70
71 fn try_lock_read(self) -> LockReadResult<Self>
72 where
73 Self: Sized;
74 }
75
76 pub trait LockWrite: AsOpenFile + std::io::Write {
77 fn lock_write(self) -> LockWriteResult<Self>
78 where
79 Self: Sized;
80
81 fn try_lock_write(self) -> LockWriteResult<Self>
82 where
83 Self: Sized;
84 }
85
86 impl<T> LockRead for T
87 where
88 T: AsOpenFile + std::io::Read,
89 {
90 fn lock_read(self) -> LockReadResult<Self> {
91 match self.acquire_lock_blocking::<false, true>() {
92 Ok(guard) => Ok(RwLockReadGuard::new(self, guard)),
93 Err(error) => Err(LockError::new(self, error)),
94 }
95 }
96
97 fn try_lock_read(self) -> LockReadResult<Self> {
98 match self.acquire_lock_blocking::<false, false>() {
99 Ok(guard) => Ok(RwLockReadGuard::new(self, guard)),
100 Err(error) => Err(LockError::new(self, error)),
101 }
102 }
103 }
104
105 impl<T> LockWrite for T
106 where
107 T: AsOpenFile + std::io::Write,
108 {
109 fn lock_write(self) -> LockWriteResult<Self> {
110 match self.acquire_lock_blocking::<true, true>() {
111 Ok(guard) => Ok(RwLockWriteGuard::new(self, guard)),
112 Err(error) => Err(LockError::new(self, error)),
113 }
114 }
115
116 fn try_lock_write(self) -> LockWriteResult<Self> {
117 match self.acquire_lock_blocking::<true, false>() {
118 Ok(guard) => Ok(RwLockWriteGuard::new(self, guard)),
119 Err(error) => Err(LockError::new(self, error)),
120 }
121 }
122 }
123}
124
125#[cfg(feature = "async")]
126pub mod nonblocking {
127 use super::*;
128 use async_trait::async_trait;
129 use std::io;
130 use sys::{AsOpenFileExt, RwLockGuard};
131
132 async fn lock<const WRITE: bool, const BLOCK: bool, T>(
133 file: &T,
134 ) -> Result<RwLockGuard<<T as AsOpenFileExt>::OwnedOpenFile>, io::Error>
135 where
136 T: AsOpenFile + Sync + 'static,
137 {
138 let handle = file.borrow_open_file().try_clone_to_owned()?;
139 let (sync_send, async_recv) = tokio::sync::oneshot::channel();
140 tokio::task::spawn_blocking(move || {
141 let guard = handle.acquire_lock_blocking::<WRITE, BLOCK>();
142 let result = sync_send.send(guard);
143 drop(result); });
145 async_recv
146 .await
147 .expect("the blocking task is not cancelable")
148 }
149
150 #[async_trait]
151 pub trait LockRead: AsOpenFile + tokio::io::AsyncRead {
152 async fn lock_read(self) -> LockReadResult<Self>
153 where
154 Self: Sized;
155
156 async fn try_lock_read(self) -> LockReadResult<Self>
157 where
158 Self: Sized;
159 }
160
161 #[async_trait]
162 pub trait LockWrite: AsOpenFile + tokio::io::AsyncWrite {
163 async fn lock_write(self) -> LockWriteResult<Self>
164 where
165 Self: Sized;
166
167 async fn try_lock_write(self) -> LockWriteResult<Self>
168 where
169 Self: Sized;
170 }
171
172 #[async_trait]
173 impl<T> LockRead for T
174 where
175 T: AsOpenFile + tokio::io::AsyncRead + Send + Sync + 'static,
176 {
177 async fn lock_read(self) -> LockReadResult<Self> {
178 match lock::<false, true, _>(&self).await {
179 Ok(guard) => Ok(RwLockReadGuard::new(self, guard)),
180 Err(error) => Err(LockError::new(self, error)),
181 }
182 }
183
184 async fn try_lock_read(self) -> LockReadResult<Self> {
185 match lock::<false, false, _>(&self).await {
186 Ok(guard) => Ok(RwLockReadGuard::new(self, guard)),
187 Err(error) => Err(LockError::new(self, error)),
188 }
189 }
190 }
191
192 #[async_trait]
193 impl<T> LockWrite for T
194 where
195 T: AsOpenFile + tokio::io::AsyncWrite + Send + Sync + 'static,
196 {
197 async fn lock_write(self) -> LockWriteResult<Self> {
198 match lock::<true, true, _>(&self).await {
199 Ok(guard) => Ok(RwLockWriteGuard::new(self, guard)),
200 Err(error) => Err(LockError::new(self, error)),
201 }
202 }
203
204 async fn try_lock_write(self) -> LockWriteResult<Self> {
205 match lock::<true, false, _>(&self).await {
206 Ok(guard) => Ok(RwLockWriteGuard::new(self, guard)),
207 Err(error) => return Err(LockError::new(self, error)),
208 }
209 }
210 }
211}