1#[cfg(feature = "use-locks")]
2use lock::Lock;
3use std::{
4 cell::{Cell, UnsafeCell},
5 fmt::Debug,
6 ops::{Deref, DerefMut},
7};
8
9#[cfg(feature = "use-locks")]
10mod lock;
11
12#[derive(Clone, Copy, PartialEq, Debug)]
13pub enum State {
14 Unlocked,
15 Locked,
16 Poisoned,
17}
18
19pub struct LazyExclusive<T> {
32 state: Cell<State>,
33 data: UnsafeCell<T>,
34 #[cfg(feature = "use-locks")]
35 lock: Lock,
36}
37
38unsafe impl<T> Send for LazyExclusive<T> {}
39unsafe impl<T> Sync for LazyExclusive<T> {}
40
41pub struct Mut<'a, T> {
42 source: &'a LazyExclusive<T>,
43}
44
45impl<T> Mut<'_, T> {
46 fn inner(&self) -> &mut T {
47 unsafe {
48 self.source
49 .data
50 .get()
51 .as_mut()
52 .expect("source.data is never a null pointer")
53 }
54 }
55}
56
57impl<T> Drop for Mut<'_, T> {
58 fn drop(&mut self) {
59 self.source.state.set(State::Unlocked);
60 #[cfg(feature = "use-locks")]
61 {
62 self.source.lock.unlock();
63
64 if std::thread::panicking() {
65 self.source.state.set(State::Poisoned)
66 }
67 }
68 }
69}
70
71impl<T> Deref for Mut<'_, T> {
72 type Target = T;
73
74 fn deref(&self) -> &Self::Target {
75 unsafe {
76 self.source
77 .data
78 .get()
79 .as_ref()
80 .expect("source.data is never a null pointer")
81 }
82 }
83}
84
85impl<T> AsRef<T> for Mut<'_, T> {
86 fn as_ref(&self) -> &T {
87 self.deref()
88 }
89}
90
91impl<T> AsMut<T> for Mut<'_, T> {
92 fn as_mut(&mut self) -> &mut T {
93 self.deref_mut()
94 }
95}
96
97impl<T> DerefMut for Mut<'_, T> {
98 fn deref_mut(&mut self) -> &mut Self::Target {
99 self.inner()
100 }
101}
102
103impl<T> LazyExclusive<T> {
104 pub const fn new(data: T) -> Self {
105 let data = UnsafeCell::new(data);
106 let state = Cell::new(State::Unlocked);
107
108 #[cfg(not(feature = "use-locks"))]
109 return Self { state, data };
110 #[cfg(feature = "use-locks")]
111 Self {
112 state,
113 data,
114 lock: Lock::new(),
115 }
116 }
117
118 pub fn get(&self) -> Option<Mut<'_, T>> {
120 match self.state.get() {
121 State::Unlocked => {
122 self.state.set(State::Locked);
123 #[cfg(feature = "use-locks")]
124 self.lock.lock();
125 Some(Mut { source: self })
126 }
127 _ => None,
128 }
129 }
130
131 pub fn swap(&self, new_value: T) {
133 assert_eq!(self.state.get(), State::Unlocked);
134 unsafe {
135 let t = self.data.get().as_mut().unwrap();
136 *t = new_value;
137 self.state.set(State::Unlocked);
138
139 #[cfg(feature = "use-locks")]
140 self.lock.reset();
141 }
142 }
143
144 pub fn get_state(&self) -> State {
145 self.state.get()
146 }
147
148 #[cfg(feature = "use-locks")]
150 pub fn wait(&self) -> Mut<'_, T> {
151 self.lock.lock();
152 assert_eq!(self.state.get(), State::Unlocked, "The data was poisoned");
153 self.state.set(State::Locked);
154 Mut { source: self }
155 }
156
157 pub fn into_inner(self) -> T {
158 match self.state.get() {
159 State::Unlocked => self.data.into_inner(),
160 State::Locked => panic!("locked"),
161 State::Poisoned => panic!("poisoned"),
162 }
163 }
164
165 pub fn is_unlocked(&self) -> bool {
166 matches!(self.state.get(), State::Unlocked)
167 }
168
169 pub fn is_locked(&self) -> bool {
170 matches!(self.state.get(), State::Locked)
171 }
172
173 pub fn is_poisoned(&self) -> bool {
174 matches!(self.state.get(), State::Poisoned)
175 }
176}
177
178impl<T: Debug> Debug for LazyExclusive<T> {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 let data: &dyn Debug = match self.state.get() {
181 State::Unlocked => unsafe { self.data.get().as_mut().expect("Should never fail") },
182 State::Locked => &"<locked>",
183 State::Poisoned => &"<poisoned>",
184 };
185
186 f.debug_struct("LazyExclusive")
187 .field("state", &self.state.get())
188 .field("data", data)
189 .finish()
190 }
191}
192
193impl<T> From<T> for LazyExclusive<T> {
194 fn from(value: T) -> Self {
195 Self::new(value)
196 }
197}
198
199impl<T: Clone> Clone for LazyExclusive<T> {
200 fn clone(&self) -> Self {
201 let data = match self.state.get() {
202 State::Unlocked => unsafe { self.data.get().as_ref().expect("Should never fail") },
203 State::Locked => panic!("locked"),
204 State::Poisoned => panic!("poisoned"),
205 };
206
207 LazyExclusive::new(data.clone())
208 }
209}
210
211impl<T: Default> Default for LazyExclusive<T> {
212 fn default() -> Self {
213 Self::new(T::default())
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use crate::{LazyExclusive, State};
220
221 #[test]
222 fn basic() {
223 let shared = LazyExclusive::new(230);
224 let mut1 = shared.get();
225 assert!(mut1.is_some());
226 assert!(shared.get().is_none());
227
228 let mut1 = mut1.unwrap();
229 let inner = *mut1;
230 assert_eq!(inner, 230);
231 }
232
233 #[test]
234 fn static_test() {
235 static SHARED: LazyExclusive<i32> = LazyExclusive::new(1231);
236 let pointer = SHARED.get().unwrap();
237 assert_eq!(*pointer, 1231);
238 }
239
240 #[cfg(feature = "use-locks")]
241 #[test]
242 fn lock_test() {
243 use crate::State;
244 use std::time::Duration;
245
246 static SHARED: LazyExclusive<i32> = LazyExclusive::new(120);
247 let mut lock = SHARED.get().unwrap();
248
249 std::thread::spawn(move || {
250 *lock *= 2;
251 std::thread::sleep(Duration::new(5, 0));
252 });
253
254 assert_eq!(SHARED.get_state(), State::Locked);
255 let new_lock = SHARED.wait();
256 assert_eq!(*new_lock, 120 * 2);
257 }
258
259 #[test]
260 fn reset() {
261 let lazy = LazyExclusive::new(120);
262 lazy.swap(10);
263 assert_eq!(*lazy.get().unwrap(), 10);
264 assert_eq!(lazy.get_state(), State::Unlocked);
265 }
266
267 #[test]
268 fn clone() {
269 let lazy = LazyExclusive::new(120);
270 let clone = lazy.clone();
271
272 assert_eq!(lazy.into_inner(), clone.into_inner());
273 }
274}