1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub mod checked {
5 use core::{
6 cell::UnsafeCell,
7 mem::MaybeUninit,
8 ptr,
9 sync::atomic::{AtomicBool, Ordering},
10 };
11
12 #[derive(Debug)]
14 pub struct Maybe<T> {
15 data: UnsafeCell<MaybeUninit<T>>,
16 loaded: AtomicBool,
17 }
18
19 impl<T> Maybe<T> {
20 #[inline]
22 pub const fn empty() -> Self {
23 Self {
24 data: UnsafeCell::new(MaybeUninit::uninit()),
25 loaded: AtomicBool::new(false),
26 }
27 }
28
29 #[inline]
31 pub const fn new(data: T) -> Self {
32 Self {
33 data: UnsafeCell::new(MaybeUninit::new(data)),
34 loaded: AtomicBool::new(true),
35 }
36 }
37
38 #[inline]
40 pub unsafe fn as_ptr(&self) -> *const T {
41 assert_eq!(
42 self.loaded.load(Ordering::Relaxed),
43 true,
44 "as_ptr for uninitialized cell"
45 );
46
47 (&*self.data.get()).as_ptr()
48 }
49
50 #[inline]
52 pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
53 assert_eq!(
54 self.loaded.load(Ordering::Relaxed),
55 true,
56 "as_mut_ptr for uninitialized cell"
57 );
58
59 (&mut *self.data.get()).as_mut_ptr()
60 }
61
62 #[inline]
65 pub unsafe fn as_ref(&self) -> &T {
66 assert_eq!(
67 self.loaded.load(Ordering::Relaxed),
68 true,
69 "as_ref for uninitialized cell"
70 );
71
72 &*(&*self.data.get()).as_ptr()
73 }
74
75 #[inline(always)]
77 pub unsafe fn as_mut(&mut self) -> &mut T {
78 assert_eq!(
79 self.loaded.load(Ordering::Relaxed),
80 true,
81 "as_mut for uninitialized cell"
82 );
83
84 &mut *(&mut *self.data.get()).as_mut_ptr()
85 }
86
87 #[inline]
91 pub fn set_loaded(&self, loaded: bool) {
92 self.loaded.store(loaded, Ordering::Relaxed);
93 }
94
95 #[inline]
97 pub unsafe fn clear(&self) {
98 assert_eq!(
99 self.loaded.swap(false, Ordering::Relaxed),
100 true,
101 "cleared uninitialized cell"
102 );
103
104 ptr::drop_in_place((&mut *self.data.get()).as_mut_ptr())
105 }
106
107 #[inline]
109 pub unsafe fn load(&self) -> T {
110 assert_eq!(
111 self.loaded.swap(false, Ordering::Relaxed),
112 true,
113 "duplicate load"
114 );
115
116 ptr::read(self.data.get()).assume_init()
117 }
118
119 #[inline]
121 pub unsafe fn replace(&self, value: T) -> T {
122 assert_eq!(
123 self.loaded.load(Ordering::Relaxed),
124 true,
125 "replace on empty store"
126 );
127 let result = ptr::read(self.data.get()).assume_init();
128 self.data.get().write(MaybeUninit::new(value));
129 result
130 }
131
132 #[inline]
134 pub unsafe fn store(&self, value: T) {
135 assert_eq!(
136 self.loaded.swap(true, Ordering::Relaxed),
137 false,
138 "duplicate store"
139 );
140
141 self.data.get().write(MaybeUninit::new(value))
142 }
143 }
144
145 impl<T> Drop for Maybe<T> {
146 fn drop(&mut self) {
147 assert_eq!(
148 self.loaded.load(Ordering::Relaxed),
149 false,
150 "cell not cleared before drop"
151 );
152 }
153 }
154
155 impl<T> From<T> for Maybe<T> {
156 fn from(value: T) -> Self {
157 Self::new(value)
158 }
159 }
160
161 #[derive(Debug)]
164 pub struct MaybeCopy<T> {
165 data: UnsafeCell<MaybeUninit<T>>,
166 loaded: AtomicBool,
167 }
168
169 impl<T> MaybeCopy<T> {
171 #[inline]
173 pub const fn empty() -> Self {
174 Self {
175 data: UnsafeCell::new(MaybeUninit::uninit()),
176 loaded: AtomicBool::new(false),
177 }
178 }
179
180 #[inline]
182 pub const fn new(data: T) -> Self {
183 Self {
184 data: UnsafeCell::new(MaybeUninit::new(data)),
185 loaded: AtomicBool::new(true),
186 }
187 }
188 }
189
190 impl<T: Copy> MaybeCopy<T> {
191 #[inline]
193 pub unsafe fn as_ptr(&self) -> *const T {
194 assert_eq!(
195 self.loaded.load(Ordering::Relaxed),
196 true,
197 "as_ptr for uninitialized cell"
198 );
199
200 (&*self.data.get()).as_ptr()
201 }
202
203 #[inline]
205 pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
206 assert_eq!(
207 self.loaded.load(Ordering::Relaxed),
208 true,
209 "as_mut_ptr for uninitialized cell"
210 );
211
212 (&mut *self.data.get()).as_mut_ptr()
213 }
214
215 #[inline]
218 pub unsafe fn as_ref(&self) -> &T {
219 assert_eq!(
220 self.loaded.load(Ordering::Relaxed),
221 true,
222 "as_ref for uninitialized cell"
223 );
224
225 &*(&*self.data.get()).as_ptr()
226 }
227
228 #[inline(always)]
230 pub unsafe fn as_mut(&mut self) -> &mut T {
231 assert_eq!(
232 self.loaded.load(Ordering::Relaxed),
233 true,
234 "as_mut for uninitialized cell"
235 );
236
237 &mut *(&mut *self.data.get()).as_mut_ptr()
238 }
239
240 #[inline]
244 pub fn set_loaded(&self, loaded: bool) {
245 self.loaded.store(loaded, Ordering::Relaxed);
246 }
247
248 #[inline]
250 pub unsafe fn load(&self) -> T {
251 assert_eq!(
252 self.loaded.load(Ordering::Relaxed),
253 true,
254 "load of uninitialized cell"
255 );
256
257 ptr::read(self.data.get()).assume_init()
258 }
259
260 #[inline]
262 pub unsafe fn replace(&self, value: T) -> T {
263 assert_eq!(
264 self.loaded.load(Ordering::Relaxed),
265 true,
266 "replace on empty store"
267 );
268 let result = ptr::read(self.data.get()).assume_init();
269 self.data.get().write(MaybeUninit::new(value));
270 result
271 }
272
273 #[inline]
275 pub unsafe fn store(&self, value: T) {
276 self.loaded.store(true, Ordering::Relaxed);
277
278 self.data.get().write(MaybeUninit::new(value))
279 }
280 }
281
282 impl<T: Copy> From<T> for MaybeCopy<T> {
283 fn from(value: T) -> Self {
284 Self::new(value)
285 }
286 }
287}
288
289pub mod unchecked {
291 use core::{cell::UnsafeCell, mem::MaybeUninit, ptr};
292
293 #[derive(Debug)]
295 #[repr(transparent)]
296 pub struct Maybe<T> {
297 data: UnsafeCell<MaybeUninit<T>>,
298 }
299
300 impl<T> Maybe<T> {
301 #[inline(always)]
303 pub const fn empty() -> Self {
304 Self {
305 data: UnsafeCell::new(MaybeUninit::uninit()),
306 }
307 }
308
309 #[inline(always)]
311 pub const fn new(data: T) -> Self {
312 Self {
313 data: UnsafeCell::new(MaybeUninit::new(data)),
314 }
315 }
316
317 #[inline(always)]
319 pub unsafe fn as_ptr(&self) -> *const T {
320 (&*self.data.get()).as_ptr()
321 }
322
323 #[inline(always)]
325 pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
326 (&mut *self.data.get()).as_mut_ptr()
327 }
328
329 #[inline(always)]
332 pub unsafe fn as_ref(&self) -> &T {
333 &*(&*self.data.get()).as_ptr()
334 }
335
336 #[inline(always)]
338 pub unsafe fn as_mut(&mut self) -> &mut T {
339 &mut *(&mut *self.data.get()).as_mut_ptr()
340 }
341
342 #[inline]
346 pub fn set_loaded(&self, _loaded: bool) {}
347
348 #[inline(always)]
350 pub unsafe fn clear(&self) {
351 ptr::drop_in_place((&mut *self.data.get()).as_mut_ptr())
352 }
353
354 #[inline(always)]
356 pub unsafe fn load(&self) -> T {
357 ptr::read(self.data.get()).assume_init()
358 }
359
360 #[inline(always)]
362 pub unsafe fn replace(&self, value: T) -> T {
363 let result = self.load();
364 self.data.get().write(MaybeUninit::new(value));
365 result
366 }
367
368 #[inline(always)]
370 pub unsafe fn store(&self, value: T) {
371 self.data.get().write(MaybeUninit::new(value))
372 }
373 }
374
375 impl<T> From<T> for Maybe<T> {
376 fn from(value: T) -> Self {
377 Self::new(value)
378 }
379 }
380
381 #[derive(Debug)]
384 #[repr(transparent)]
385 pub struct MaybeCopy<T> {
386 data: UnsafeCell<MaybeUninit<T>>,
387 }
388
389 impl<T> MaybeCopy<T> {
391 #[inline]
393 pub const fn empty() -> Self {
394 Self {
395 data: UnsafeCell::new(MaybeUninit::uninit()),
396 }
397 }
398
399 #[inline]
401 pub const fn new(data: T) -> Self {
402 Self {
403 data: UnsafeCell::new(MaybeUninit::new(data)),
404 }
405 }
406 }
407
408 impl<T: Copy> MaybeCopy<T> {
409 #[inline(always)]
411 pub unsafe fn as_ptr(&self) -> *const T {
412 (&*self.data.get()).as_ptr()
413 }
414
415 #[inline(always)]
417 pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
418 (&mut *self.data.get()).as_mut_ptr()
419 }
420
421 #[inline(always)]
424 pub unsafe fn as_ref(&self) -> &T {
425 &*(&*self.data.get()).as_ptr()
426 }
427
428 #[inline(always)]
430 pub unsafe fn as_mut(&mut self) -> &mut T {
431 &mut *(&mut *self.data.get()).as_mut_ptr()
432 }
433
434 #[inline]
438 pub fn set_loaded(&self, _loaded: bool) {}
439
440 #[inline(always)]
442 pub unsafe fn load(&self) -> T {
443 ptr::read(self.data.get()).assume_init()
444 }
445
446 pub unsafe fn replace(&self, value: T) -> T {
448 let result = self.load();
449 self.data.get().write(MaybeUninit::new(value));
450 result
451 }
452
453 #[inline(always)]
455 pub unsafe fn store(&self, value: T) {
456 self.data.get().write(MaybeUninit::new(value))
457 }
458 }
459
460 impl<T: Copy> From<T> for MaybeCopy<T> {
461 fn from(value: T) -> Self {
462 Self::new(value)
463 }
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use super::{checked, unchecked};
470
471 #[test]
472 fn checked_init_read_write() {
473 unsafe {
474 let cell = checked::Maybe::new(1);
475 assert_eq!(cell.load(), 1);
476 cell.store(2);
477 assert_eq!(cell.load(), 2);
478 }
479 }
480
481 #[test]
482 fn unchecked_init_read_write() {
483 unsafe {
484 let cell = unchecked::Maybe::new(1);
485 assert_eq!(cell.load(), 1);
486 cell.store(2);
487 assert_eq!(cell.load(), 2);
488 }
489 }
490}