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