Skip to content

Commit d7e4cc0

Browse files
committed
Add callback lock
1 parent a685f29 commit d7e4cc0

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

src/util.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub mod progress;
2222
pub use mem_or_file::{FileAndSize, MemOrFile};
2323
mod sparse_mem_file;
2424
pub use sparse_mem_file::SparseMemFile;
25+
pub mod callback_lock;
2526
pub mod local_pool;
2627

2728
#[cfg(test)]

src/util/callback_lock.rs

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//! This module defines a wrapper around a [`tokio::sync::RwLock`] that runs a callback
2+
//! After any write operation occurs
3+
4+
use std::future::Future;
5+
6+
/// A wrapper over a [`tokio::sync::RwLock`] that executes a callback function after
7+
/// the write guard is dropped
8+
#[derive(derive_more::Debug)]
9+
pub struct CallbackLock<T, F> {
10+
inner: tokio::sync::RwLock<T>,
11+
#[debug(skip)]
12+
callback: F,
13+
}
14+
15+
/// the wrapper type over a [tokio::sync::RwLockWriteGuard]
16+
#[derive(Debug)]
17+
pub struct CallbackLockWriteGuard<'a, T, F: Fn(&T)> {
18+
inner: tokio::sync::RwLockWriteGuard<'a, T>,
19+
callback: &'a F,
20+
}
21+
22+
impl<T, F: Fn(&T)> std::ops::Deref for CallbackLockWriteGuard<'_, T, F> {
23+
type Target = T;
24+
25+
fn deref(&self) -> &Self::Target {
26+
&self.inner
27+
}
28+
}
29+
30+
impl<T, F: Fn(&T)> std::ops::DerefMut for CallbackLockWriteGuard<'_, T, F> {
31+
fn deref_mut(&mut self) -> &mut Self::Target {
32+
&mut self.inner
33+
}
34+
}
35+
36+
impl<T, F: Fn(&T)> Drop for CallbackLockWriteGuard<'_, T, F> {
37+
fn drop(&mut self) {
38+
(self.callback)(&*self.inner);
39+
}
40+
}
41+
42+
impl<T, F> CallbackLock<T, F>
43+
where
44+
F: Fn(&T),
45+
{
46+
/// create a new instance of the lock from a value
47+
/// and the callback to evaluate when a write guard is dropped
48+
pub fn new(val: T, callback: F) -> Self {
49+
CallbackLock {
50+
inner: tokio::sync::RwLock::new(val),
51+
callback,
52+
}
53+
}
54+
55+
/// return an instance of the write guard
56+
pub async fn write(&self) -> CallbackLockWriteGuard<'_, T, F> {
57+
let guard = self.inner.write().await;
58+
59+
CallbackLockWriteGuard {
60+
inner: guard,
61+
callback: &self.callback,
62+
}
63+
}
64+
65+
/// return the [tokio::sync::RwLockReadGuard]
66+
/// this will not invoke the callback
67+
pub fn read(&self) -> impl Future<Output = tokio::sync::RwLockReadGuard<'_, T>> {
68+
self.inner.read()
69+
}
70+
71+
/// try to synchronously acquire a read lock
72+
pub fn try_read(
73+
&self,
74+
) -> Result<tokio::sync::RwLockReadGuard<'_, T>, tokio::sync::TryLockError> {
75+
self.inner.try_read()
76+
}
77+
}

0 commit comments

Comments
 (0)