1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::NoPoisonMutex;
16 use std::ops::{Deref, DerefMut};
17 
18 /// A mutual exclusion primitive useful for protecting shared data
19 pub struct Mutex<T>(std::sync::Mutex<T>);
20 
21 impl<T> NoPoisonMutex<T> for Mutex<T> {
22     type MutexGuard<'a> = std::sync::MutexGuard<'a, T> where T: 'a;
23 
lock(&self) -> Self::MutexGuard<'_>24     fn lock(&self) -> Self::MutexGuard<'_> {
25         self.0.lock().unwrap_or_else(|poison| poison.into_inner())
26     }
27 
try_lock(&self) -> Option<Self::MutexGuard<'_>>28     fn try_lock(&self) -> Option<Self::MutexGuard<'_>> {
29         match self.0.try_lock() {
30             Ok(guard) => Some(guard),
31             Err(std::sync::TryLockError::Poisoned(guard)) => Some(guard.into_inner()),
32             Err(std::sync::TryLockError::WouldBlock) => None,
33         }
34     }
35 
new(value: T) -> Self36     fn new(value: T) -> Self {
37         Self(std::sync::Mutex::new(value))
38     }
39 }
40 
41 /// A reader-writer lock
42 /// This type of lock allows a number of readers or at most one writer at any point in time.
43 /// The write portion of this lock typically allows modification of the underlying data (exclusive access)
44 /// and the read portion of this lock typically allows for read-only access (shared access).
45 pub struct RwLock<T>(std::sync::RwLock<T>);
46 
47 impl<T> RwLock<T> {
48     /// Creates a new instance of an `RwLock<T>` which is unlocked.
new(value: T) -> Self49     pub const fn new(value: T) -> Self {
50         Self(std::sync::RwLock::new(value))
51     }
52 }
53 
54 impl<T> crate::RwLock<T> for RwLock<T> {
55     type RwLockReadGuard<'a> = RwLockReadGuard<'a, T> where T: 'a;
56 
57     type RwLockWriteGuard<'a> = RwLockWriteGuard<'a, T> where T: 'a;
58 
read(&self) -> Self::RwLockReadGuard<'_>59     fn read(&self) -> Self::RwLockReadGuard<'_> {
60         RwLockReadGuard(self.0.read().unwrap_or_else(|e| e.into_inner()))
61     }
62 
write(&self) -> Self::RwLockWriteGuard<'_>63     fn write(&self) -> Self::RwLockWriteGuard<'_> {
64         RwLockWriteGuard(self.0.write().unwrap_or_else(|e| e.into_inner()))
65     }
66 }
67 
68 /// RAII structure used to release the shared read access of a lock when dropped.
69 pub struct RwLockReadGuard<'a, T>(std::sync::RwLockReadGuard<'a, T>);
70 
71 impl<'a, T> RwLockReadGuard<'a, T> {
72     /// Make a new MappedRwLockReadGuard for a component of the locked data.
map<U, M>(s: Self, mapping: M) -> MappedRwLockReadGuard<'a, T, U, M> where M: RwMapping<Arg = T, Ret = U>,73     pub fn map<U, M>(s: Self, mapping: M) -> MappedRwLockReadGuard<'a, T, U, M>
74     where
75         M: RwMapping<Arg = T, Ret = U>,
76     {
77         MappedRwLockReadGuard { mapping, guard: s }
78     }
79 }
80 
81 impl<'a, T> Deref for RwLockReadGuard<'a, T> {
82     type Target = T;
83 
deref(&self) -> &Self::Target84     fn deref(&self) -> &Self::Target {
85         self.0.deref()
86     }
87 }
88 
89 /// An RAII read lock guard returned by RwLockReadGuard::map, which can point to a subfield of the protected data.
90 pub struct MappedRwLockReadGuard<'a, T, U, M>
91 where
92     M: RwMapping<Arg = T, Ret = U>,
93 {
94     mapping: M,
95     guard: RwLockReadGuard<'a, T>,
96 }
97 
98 impl<'a, T, U, M> Deref for MappedRwLockReadGuard<'a, T, U, M>
99 where
100     M: RwMapping<Arg = T, Ret = U>,
101 {
102     type Target = U;
103 
deref(&self) -> &Self::Target104     fn deref(&self) -> &Self::Target {
105         self.mapping.map(&*self.guard)
106     }
107 }
108 
109 /// RAII structure used to release the exclusive write access of a lock when dropped.
110 pub struct RwLockWriteGuard<'a, T>(std::sync::RwLockWriteGuard<'a, T>);
111 
112 impl<'a, T> RwLockWriteGuard<'a, T> {
113     /// Make a new MappedRwLockWriteGuard for a component of the locked data.
map<U, M>(s: Self, mapping: M) -> MappedRwLockWriteGuard<'a, T, U, M> where M: RwMapping<Arg = T, Ret = U>,114     pub fn map<U, M>(s: Self, mapping: M) -> MappedRwLockWriteGuard<'a, T, U, M>
115     where
116         M: RwMapping<Arg = T, Ret = U>,
117     {
118         MappedRwLockWriteGuard { mapping, guard: s }
119     }
120 }
121 
122 impl<'a, T> Deref for RwLockWriteGuard<'a, T> {
123     type Target = T;
124 
deref(&self) -> &Self::Target125     fn deref(&self) -> &Self::Target {
126         self.0.deref()
127     }
128 }
129 
130 impl<'a, T> DerefMut for RwLockWriteGuard<'a, T> {
deref_mut(&mut self) -> &mut Self::Target131     fn deref_mut(&mut self) -> &mut Self::Target {
132         self.0.deref_mut()
133     }
134 }
135 
136 /// An RAII read lock guard returned by RwLockWriteGuard::map, which can point to a subfield of the protected data.
137 pub struct MappedRwLockWriteGuard<'a, T, U, M>
138 where
139     M: RwMapping<Arg = T, Ret = U>,
140 {
141     mapping: M,
142     guard: RwLockWriteGuard<'a, T>,
143 }
144 
145 impl<'a, P, T, M> Deref for MappedRwLockWriteGuard<'a, P, T, M>
146 where
147     M: RwMapping<Arg = P, Ret = T>,
148 {
149     type Target = T;
150 
deref(&self) -> &Self::Target151     fn deref(&self) -> &Self::Target {
152         self.mapping.map(&*self.guard)
153     }
154 }
155 
156 impl<'a, P, T, M> DerefMut for MappedRwLockWriteGuard<'a, P, T, M>
157 where
158     M: RwMapping<Arg = P, Ret = T>,
159 {
deref_mut(&mut self) -> &mut Self::Target160     fn deref_mut(&mut self) -> &mut Self::Target {
161         self.mapping.map_mut(&mut *self.guard)
162     }
163 }
164 
165 /// Mapping functions which define how to map from one locked data type to a component of that locked data
166 pub trait RwMapping {
167     /// The original locked data type
168     type Arg;
169     /// The returned mapped locked data type which is a component of the original locked data
170     type Ret;
171     /// Maps from Arg into Ret
map<'a>(&self, arg: &'a Self::Arg) -> &'a Self::Ret172     fn map<'a>(&self, arg: &'a Self::Arg) -> &'a Self::Ret;
173     /// Mutably maps from Arg into Ret
map_mut<'a>(&self, arg: &'a mut Self::Arg) -> &'a mut Self::Ret174     fn map_mut<'a>(&self, arg: &'a mut Self::Arg) -> &'a mut Self::Ret;
175 }
176