readlock_tokio/lite.rs
1//! Versions of `Shared` and `SharedReadLock` that are implemented in terms of
2//! the [rclite] crate. Because [`rclite::Arc`] doesn't have weak references,
3//! there is no `WeakReadLock` here.
4
5use std::{fmt, ops};
6
7use rclite::Arc;
8use tokio::sync::RwLock;
9
10use crate::{readguard_into_ref, SharedReadGuard, SharedWriteGuard, TryLockError, TryLockResult};
11
12/// A wrapper around a resource possibly shared with [`SharedReadLock`]s, but no
13/// other `Shared`s.
14pub struct Shared<T>(Arc<RwLock<T>>);
15
16impl<T> Shared<T> {
17 /// Create a new `Shared`.
18 pub fn new(data: T) -> Self {
19 Self(Arc::new(RwLock::new(data)))
20 }
21
22 /// Returns the inner value, if the `Shared` has no associated
23 /// `SharedReadLock`s.
24 ///
25 /// Otherwise, an `Err` is returned with the same `Shared` that was passed
26 /// in.
27 ///
28 /// This will succeed even if there are outstanding weak references.
29 ///
30 /// # Panics
31 ///
32 /// This function will panic if the lock around the inner value is poisoned.
33 pub fn unwrap(this: Self) -> Result<T, Self> {
34 match Arc::try_unwrap(this.0) {
35 Ok(rwlock) => Ok(rwlock.into_inner()),
36 Err(arc) => Err(Self(arc)),
37 }
38 }
39
40 /// Get a reference to the inner value.
41 ///
42 /// Usually, you don't need to call this function since `Shared<T>`
43 /// implements `Deref`. Use this if you want to pass the inner value to a
44 /// generic function where the compiler can't infer that you want to have
45 /// the `Shared` dereferenced otherwise.
46 #[track_caller]
47 pub fn get(this: &Self) -> &T {
48 let read_guard =
49 this.0.try_read().expect("nothing else can hold a write lock at this time");
50 unsafe { readguard_into_ref(read_guard) }
51 }
52
53 /// Lock this `Shared` to be able to mutate it, causing the current task to
54 /// yield until the lock has been acquired.
55 pub async fn lock(this: &mut Self) -> SharedWriteGuard<'_, T> {
56 SharedWriteGuard(this.0.write().await)
57 }
58
59 /// Get a [`SharedReadLock`] for accessing the same resource read-only from
60 /// elsewhere.
61 pub fn get_read_lock(this: &Self) -> SharedReadLock<T> {
62 SharedReadLock(this.0.clone())
63 }
64}
65
66impl<T> ops::Deref for Shared<T> {
67 type Target = T;
68
69 fn deref(&self) -> &Self::Target {
70 Shared::get(self)
71 }
72}
73
74impl<T: fmt::Debug> fmt::Debug for Shared<T> {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 self.0.fmt(f)
77 }
78}
79
80/// A read-only reference to a resource possibly shared with up to one
81/// [`Shared`] and many other [`SharedReadLock`]s.
82#[derive(Clone)]
83pub struct SharedReadLock<T>(Arc<RwLock<T>>);
84
85impl<T> SharedReadLock<T> {
86 /// Lock this `SharedReadLock`, causing the current task to
87 /// yield until the lock has been acquired.
88 pub async fn lock(&self) -> SharedReadGuard<'_, T> {
89 SharedReadGuard(self.0.read().await)
90 }
91
92 /// Try to lock this `SharedReadLock`.
93 ///
94 /// If the value is currently locked for writing through the corresponding
95 /// `Shared` instance, returns [`TryLockError`].
96 pub fn try_lock(&self) -> TryLockResult<SharedReadGuard<'_, T>> {
97 self.0.try_read().map(SharedReadGuard).map_err(TryLockError)
98 }
99}
100
101impl<T: fmt::Debug> fmt::Debug for SharedReadLock<T> {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 self.0.fmt(f)
104 }
105}