read_write_store/
lock.rs

1//! RAII read and write locks for [RwStore](crate::RwStore).
2
3use std::fmt::{Debug, Display, Formatter};
4use std::marker::PhantomData;
5use std::ops::{Deref, DerefMut};
6use std::{fmt, mem};
7
8use crate::block::Block;
9use crate::id::Id;
10
11/// A read lock for an element in an [RwStore](crate::RwStore).
12///
13/// The lock will automatically be released when this is dropped.
14///
15/// # Example
16///
17/// ```
18/// # use read_write_store::RwStore;
19/// # use read_write_store::timeout::Timeout::DontBlock;
20/// # use std::mem;
21/// let store = RwStore::new();
22/// let id = store.insert(42);
23///
24/// let read_lock = store.read(id).unwrap();
25/// assert_eq!(*read_lock, 42);
26///
27/// assert!(store.write_with_timeout(id, DontBlock).is_err());
28/// mem::drop(read_lock);
29/// assert!(store.write_with_timeout(id, DontBlock).is_ok());
30/// ```
31pub struct ReadLock<'a, Element> {
32    id: Id,
33    _marker: PhantomData<(&'a Element, *const ())>,
34}
35
36impl<'a, Element> ReadLock<'a, Element> {
37    pub(super) unsafe fn new(id: Id) -> Self {
38        Self {
39            id,
40            _marker: PhantomData::default(),
41        }
42    }
43}
44
45impl<'a, Element> Deref for ReadLock<'a, Element> {
46    type Target = Element;
47
48    fn deref(&self) -> &Element {
49        unsafe { Block::get_unchecked(self.id).as_ref() }
50    }
51}
52
53impl<'a, Element> Drop for ReadLock<'a, Element> {
54    fn drop(&mut self) {
55        unsafe {
56            Block::<Element>::unlock_read(self.id);
57        }
58    }
59}
60
61impl<'a, Element: Debug> Debug for ReadLock<'a, Element> {
62    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
63        Debug::fmt(self.deref(), f)
64    }
65}
66
67impl<'a, Element: Display> Display for ReadLock<'a, Element> {
68    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
69        Display::fmt(self.deref(), f)
70    }
71}
72
73unsafe impl<'a, Element: Sync> Sync for ReadLock<'a, Element> {}
74
75/// A write lock for an element in an [RwStore](crate::RwStore).
76///
77/// The lock will automatically be released when this is dropped.
78///
79/// # Example
80///
81/// ```
82/// # use read_write_store::RwStore;
83/// # use read_write_store::timeout::Timeout::DontBlock;
84/// # use std::mem;
85/// let store = RwStore::new();
86/// let id = store.insert(42);
87///
88/// let mut write_lock = store.write(id).unwrap();
89/// *write_lock = 24;
90/// assert_eq!(*write_lock, 24);
91///
92/// assert!(store.read_with_timeout(id, DontBlock).is_err());
93/// mem::drop(write_lock);
94/// assert!(store.read_with_timeout(id, DontBlock).is_ok());
95/// ```
96pub struct WriteLock<'a, Element> {
97    id: Id,
98    _marker: PhantomData<(&'a Element, *const ())>,
99}
100
101impl<'a, Element> WriteLock<'a, Element> {
102    pub(super) unsafe fn new(id: Id) -> Self {
103        Self {
104            id,
105            _marker: PhantomData::default(),
106        }
107    }
108
109    pub(super) fn forget(self) -> Id {
110        let result = self.id;
111        mem::forget(self);
112        result
113    }
114}
115
116impl<'a, Element> Deref for WriteLock<'a, Element> {
117    type Target = Element;
118
119    fn deref(&self) -> &Element {
120        unsafe { Block::get_unchecked(self.id).as_ref() }
121    }
122}
123
124impl<'a, Element> DerefMut for WriteLock<'a, Element> {
125    fn deref_mut(&mut self) -> &mut Element {
126        unsafe { Block::get_unchecked(self.id).as_mut() }
127    }
128}
129
130impl<'a, Element> Drop for WriteLock<'a, Element> {
131    fn drop(&mut self) {
132        unsafe { Block::<Element>::unlock_write(self.id) }
133    }
134}
135
136impl<'a, Element: Debug> Debug for WriteLock<'a, Element> {
137    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
138        Debug::fmt(self.deref(), f)
139    }
140}
141
142impl<'a, Element: Display> Display for WriteLock<'a, Element> {
143    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
144        Display::fmt(self.deref(), f)
145    }
146}
147
148unsafe impl<'a, Element: Sync> Sync for WriteLock<'a, Element> {}
149
150#[cfg(test)]
151mod test {
152    use crate::RwStore;
153    use std::panic::{RefUnwindSafe, UnwindSafe};
154
155    #[test]
156    fn read_lock_implements_sync() {
157        let store = RwStore::new();
158        let id = store.insert(42);
159        let lock = store.read(id).unwrap();
160        &lock as &dyn Sync;
161    }
162
163    #[test]
164    fn write_lock_implements_sync() {
165        let store = RwStore::new();
166        let id = store.insert(42);
167        let lock = store.write(id).unwrap();
168        &lock as &dyn Sync;
169    }
170
171    #[test]
172    fn read_lock_implements_unwind_safe() {
173        let store = RwStore::new();
174        let id = store.insert(42);
175        let lock = store.read(id).unwrap();
176        &lock as &dyn UnwindSafe;
177    }
178
179    #[test]
180    fn write_lock_implements_unwind_safe() {
181        let store = RwStore::new();
182        let id = store.insert(42);
183        let lock = store.write(id).unwrap();
184        &lock as &dyn UnwindSafe;
185    }
186
187    #[test]
188    fn read_lock_implements_ref_unwind_safe() {
189        let store = RwStore::new();
190        let id = store.insert(42);
191        let lock = store.read(id).unwrap();
192        &lock as &dyn RefUnwindSafe;
193    }
194
195    #[test]
196    fn write_lock_implements_ref_unwind_safe() {
197        let store = RwStore::new();
198        let id = store.insert(42);
199        let lock = store.write(id).unwrap();
200        &lock as &dyn RefUnwindSafe;
201    }
202}
203
204mod doctest {
205    /// ```compile_fail
206    /// use read_write_store::RwStore;
207    /// let store = RwStore::new();
208    /// let id = store.insert(42);
209    /// let lock = store.read(id).unwrap();
210    /// &lock as &dyn Send;
211    /// ```
212    #[test]
213    fn read_lock_doesnt_implement_send() {}
214
215    /// ```compile_fail
216    /// use read_write_store::RwStore;
217    /// let store = RwStore::new();
218    /// let id = store.insert(42);
219    /// let lock = store.write(id).unwrap();
220    /// &lock as &dyn Send;
221    /// ```
222    #[test]
223    fn write_lock_doesnt_implement_send() {}
224}