atomic_ptr_cell/lib.rs
1//! # `atomic_ptr_cell`
2//! Safe `no_std` repr(transparent) wrapper for `AtomicPtr` and &`AtomicPtr` with an api similar to a cell.
3//!
4//! The crate requires an allocator using `extern crate alloc;` if used without std.
5//! # Example using owned `AtomicPtr`:
6//! ```rust
7//! use std::thread;
8//! use atomic_ptr_cell::*;
9//!
10//! static CELL: AtomicPointerCell<String> = AtomicPointerCell::new();
11//!
12//! fn test() {
13//! CELL.set("Hello".to_string());
14//! let guard = CELL.borrow().unwrap();
15//! assert_eq!("Hello", guard.as_str());
16//! let jh = thread::spawn(|| {
17//! CELL.set("World".to_string());
18//! let guard = CELL.borrow().unwrap();
19//! assert!("Hello" == guard.as_str() || "World" == guard.as_str());
20//! drop(guard);
21//!
22//! });
23//! drop(guard);
24//!
25//! //This small example already has a surprising amount of possible outcomes :D
26//!
27//! let Some(value) = CELL.take() else {
28//! _= jh.join();
29//! let value = CELL.take().unwrap();
30//! assert!("Hello" == value.as_str() || "World" == value.as_str());
31//! return;
32//! };
33//!
34//! assert!("Hello" == value.as_str() || "World" == value.as_str());
35//! _= jh.join();
36//! if let Some(value2) = CELL.take() {
37//! //Depending on the order of execution CELL.take() may return None here.
38//! assert_ne!(value, value2);
39//! }
40//! }
41//! ```
42//!
43//! # Example using `&AtomicPtr` reference
44//! ```rust
45//! use atomic_ptr_cell::*;
46//! use std::ptr::null_mut;
47//! use std::sync::atomic::AtomicPtr;
48//! use std::thread;
49//!
50//! static CELL: AtomicPtr<String> = AtomicPtr::new(null_mut());
51//!
52//! fn test() {
53//! // Safety: Caller must guarantee that the AtomicPtr never contains a non-null pointer that is not from Box::into_raw
54//! let cell: AtomicPtrCell<String> = unsafe { AtomicPtrCell::new(&CELL) };
55//! cell.set("Hello".to_string());
56//! let guard = cell.borrow().unwrap();
57//! assert_eq!("Hello", guard.as_str());
58//! let jh = thread::spawn(move || {
59//! //The AtomicPtrCell is copy as its layout is equivalent to &AtomicPtr
60//! // making it easy to use in closures and threads.
61//! // You just need to ensure the lifetime of &AtomicPtr outlives the scope.
62//! // In this example the lifetime is static.
63//! cell.set("World".to_string());
64//! let guard = cell.borrow().unwrap();
65//! assert!("Hello" == guard.as_str() || "World" == guard.as_str());
66//! drop(guard);
67//! });
68//! drop(guard);
69//!
70//! //This small example already has a surprising amount of possible outcomes :D
71//!
72//! let Some(value) = cell.take() else {
73//! _ = jh.join();
74//! let value = cell.take().unwrap();
75//! assert!("Hello" == value.as_str() || "World" == value.as_str());
76//! return;
77//! };
78//!
79//! assert!("Hello" == value.as_str() || "World" == value.as_str());
80//! _ = jh.join();
81//! if let Some(value2) = cell.take() {
82//! //Depending on the order of execution CELL.take() may return None here.
83//! assert_ne!(value, value2);
84//! }
85//! }
86//! ```
87#![no_std]
88#![deny(clippy::correctness)]
89#![deny(
90 clippy::perf,
91 clippy::complexity,
92 clippy::style,
93 clippy::nursery,
94 clippy::pedantic,
95 clippy::clone_on_ref_ptr,
96 clippy::decimal_literal_representation,
97 clippy::float_cmp_const,
98 clippy::missing_docs_in_private_items,
99 clippy::multiple_inherent_impl,
100 clippy::unwrap_used,
101 clippy::cargo_common_metadata,
102 clippy::used_underscore_binding
103)]
104
105#[cfg(target_has_atomic = "ptr")]
106pub use inner::*;
107
108/// inner module that contains the actual implementation.
109#[cfg(target_has_atomic = "ptr")]
110mod inner {
111 extern crate alloc;
112 use alloc::boxed::Box;
113 use core::fmt::{Debug, Formatter};
114 use core::ops::{Deref, DerefMut};
115 use core::ptr::null_mut;
116 use core::sync::atomic::Ordering::SeqCst;
117 use core::sync::atomic::{AtomicPtr, Ordering};
118
119 /// Result enum to indicate the outcomes of a `borrow_swap` operation.
120 pub enum BorrowSwapResult<'a, T: Sync + Send + 'static, E: Sync + Send + 'static> {
121 /// Borrow swap succeeded and the returned guard should be used.
122 BorrowSwapped(BorrowGuard<'a, T>),
123 /// Cell was empty when the borrow swap operation was performed
124 CellWasEmpty(E),
125 }
126
127 impl<T: Sync + Send + Debug + 'static, E: Sync + Send + Debug + 'static> Debug
128 for BorrowSwapResult<'_, T, E>
129 {
130 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
131 match self {
132 BorrowSwapResult::BorrowSwapped(inner) => {
133 f.write_fmt(format_args!("BorrowSwapped({inner:?})"))
134 }
135 BorrowSwapResult::CellWasEmpty(inner) => {
136 f.write_fmt(format_args!("CellWasEmpty({inner:?})"))
137 }
138 }
139 }
140 }
141
142 impl<'a, T: Sync + Send + 'static, E: Sync + Send + 'static> BorrowSwapResult<'a, T, E> {
143 /// Unwraps the borrow guard
144 /// # Panics
145 /// if `CellWasEmpty`
146 pub fn unwrap(self) -> BorrowGuard<'a, T> {
147 match self {
148 BorrowSwapResult::BorrowSwapped(inner) => inner,
149 BorrowSwapResult::CellWasEmpty(_) => {
150 panic!("unwrap called on BorrowSwapResult::CellWasEmpty()")
151 }
152 }
153 }
154
155 pub const fn is_ok(&self) -> bool {
156 matches!(self, BorrowSwapResult::BorrowSwapped(_))
157 }
158
159 pub const fn is_err(&self) -> bool {
160 matches!(self, BorrowSwapResult::CellWasEmpty(_))
161 }
162
163 /// Unwraps the value intended as replacement as result of a failed operation.
164 /// # Panics
165 /// if `BorrowSwapped`
166 pub fn unwrap_err(self) -> E {
167 match self {
168 BorrowSwapResult::BorrowSwapped(_) => {
169 panic!("unwrap_err called on BorrowSwapResult::BorrowSwapped()")
170 }
171 BorrowSwapResult::CellWasEmpty(inner) => inner,
172 }
173 }
174
175 /// Maps the type in the `CellWasEmpty` case. Does nothing for `BorrowSwapped`.
176 pub fn map_err<X: Sync + Send + 'static>(
177 self,
178 f: impl FnOnce(E) -> X,
179 ) -> BorrowSwapResult<'a, T, X> {
180 match self {
181 BorrowSwapResult::BorrowSwapped(inner) => {
182 BorrowSwapResult::BorrowSwapped::<T, X>(inner)
183 }
184 BorrowSwapResult::CellWasEmpty(inner) => BorrowSwapResult::CellWasEmpty(f(inner)),
185 }
186 }
187
188 /// Transforms this into a `core::Result` type.
189 /// # Errors
190 /// In case of `CellWasEmpty`
191 pub fn into_result(self) -> Result<BorrowGuard<'a, T>, E> {
192 match self {
193 BorrowSwapResult::BorrowSwapped(inner) => Ok(inner),
194 BorrowSwapResult::CellWasEmpty(inner) => Err(inner),
195 }
196 }
197 }
198
199 impl<'a, T: Sync + Send + 'static, E: Sync + Send + 'static> From<BorrowSwapResult<'a, T, E>>
200 for Result<BorrowGuard<'a, T>, E>
201 {
202 fn from(value: BorrowSwapResult<'a, T, E>) -> Self {
203 value.into_result()
204 }
205 }
206
207 pub enum PresentResult<T: Sync + Send + 'static> {
208 /// The cell had a value when the operation was performed
209 CellHadValue(T),
210 /// The cell did not have a value when the operation was performed.
211 CellWasEmpty(T),
212 }
213
214 impl<T: Sync + Send + Debug + 'static> Debug for PresentResult<T> {
215 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
216 match self {
217 Self::CellHadValue(inner) => f.write_fmt(format_args!("CellHadValue({inner:?})")),
218 Self::CellWasEmpty(inner) => f.write_fmt(format_args!("CellWasEmpty({inner:?})")),
219 }
220 }
221 }
222
223 impl<T: Sync + Send + 'static> PresentResult<T> {
224 /// Unwraps the `PresentResult`, this call never fails but the information what type of value is referred to is lost.
225 pub fn unwrap(self) -> T {
226 match self {
227 Self::CellHadValue(inner) | Self::CellWasEmpty(inner) => inner,
228 }
229 }
230
231 /// Unwraps the `PresentResult::CellWasEmpty` result.
232 /// # Panics
233 /// if called on `PresentResult::CellHadValue`
234 pub fn unwrap_empty(self) -> T {
235 match self {
236 Self::CellHadValue(_) => {
237 panic!("unwrap_empty() on PresentResult::CellHadValue")
238 }
239 Self::CellWasEmpty(inner) => inner,
240 }
241 }
242
243 /// Unwraps the `PresentResult::CellHadValue` result.
244 /// # Panics
245 /// if called on `PresentResult::CellWasEmpty`
246 pub fn unwrap_value(self) -> T {
247 match self {
248 Self::CellHadValue(inner) => inner,
249 Self::CellWasEmpty(_) => {
250 panic!("unwrap_value() on PresentResult::CellWasEmpty")
251 }
252 }
253 }
254
255 /// Returns true if the result is a result from a Cell value.
256 pub const fn is_value(&self) -> bool {
257 matches!(self, Self::CellHadValue(_))
258 }
259
260 /// Returns true if the result contains data not from the cell because the cell was empty.
261 pub const fn is_empty(&self) -> bool {
262 matches!(self, Self::CellWasEmpty(_))
263 }
264
265 /// Maps the value in the `PresentResult`
266 pub fn map<X: Sync + Send + 'static>(self, f: impl FnOnce(T) -> X) -> PresentResult<X> {
267 match self {
268 Self::CellHadValue(inner) => PresentResult::CellHadValue(f(inner)),
269 Self::CellWasEmpty(inner) => PresentResult::CellWasEmpty(f(inner)),
270 }
271 }
272 }
273
274 ///
275 /// This is a helper struct that is guaranteed to have the exact same layout as `AtomicPtr<T>`.
276 ///
277 /// It offers high level safe manipulation functions to move data in and out of the pointer.
278 /// It offers boxed and non-boxed variants for operation.
279 /// In general all boxed operations are marginally faster because the "Box" is already on the heap
280 /// and the data must not be moved from the stack to the heap and vice versa.
281 ///
282 #[repr(transparent)]
283 #[derive(Debug)]
284 pub struct AtomicPointerCell<T: Sync + Send + 'static>(AtomicPtr<T>);
285
286 impl<T: Sync + Send + 'static> AtomicPointerCell<T> {
287 /// Constructs a new `AtomicPointerCell` without a value.
288 #[must_use]
289 pub const fn new() -> Self {
290 Self(AtomicPtr::new(null_mut()))
291 }
292
293 ///
294 /// # Safety
295 /// The ptr must contain 0 or a pointer created by `Box::into_raw`
296 /// Any external write to the pointer may also not violate this constraint
297 /// during the lifetime of the returned `AtomicPointerCell`.
298 #[must_use]
299 pub const unsafe fn from_ptr(ptr: AtomicPtr<T>) -> Self {
300 Self(ptr)
301 }
302
303 ///
304 /// # Safety
305 /// Every pointer in the slice must either be null or crated by `Box::into_raw` and be of type T.
306 /// Any external writes to the pointers may also not violate this constraint during the lifetime of the returned slice.
307 #[must_use]
308 pub const unsafe fn from_ptr_slice(value: &mut [*mut T]) -> &mut [Self] {
309 core::slice::from_raw_parts_mut(value.as_mut_ptr().cast::<Self>(), value.len())
310 }
311
312 ///
313 /// # Safety
314 /// Every `AtomicPtr` in the slice must either contain null or a pointer crated by `Box::into_raw` and be of type T.
315 /// Any external writes to the pointers may also not violate this constraint during the lifetime of the returned slice.
316 #[must_use]
317 pub const unsafe fn from_slice(value: &[AtomicPtr<T>]) -> &[Self] {
318 core::slice::from_raw_parts(value.as_ptr().cast::<Self>(), value.len())
319 }
320
321 /// Constructs a new `AtomicPointerCell` with a value.
322 #[must_use]
323 pub fn from_value(value: T) -> Self {
324 Self(AtomicPtr::new(Box::into_raw(Box::new(value))))
325 }
326
327 /// Constructs a new `AtomicPointerCell` with a boxed value.
328 #[must_use]
329 pub fn from_box(value: Box<T>) -> Self {
330 Self(AtomicPtr::new(Box::into_raw(value)))
331 }
332
333 /// Deconstructs this `AtomicPointerCell` into its raw `AtomicPtr`.
334 #[must_use]
335 pub const fn into_inner(self) -> AtomicPtr<T> {
336 self.0
337 }
338
339 /// Gets an unowned `AtomicPtrCell`.
340 /// It is subject to the lifetime of this `AtomicPointerCell`,
341 /// but otherwise refers to the same underlying `AtomicPtr`
342 ///
343 /// The layout of the `AtomicPtrCell` is guaranteed to be equivalent to that of a `&AtomicPtr`.
344 #[must_use]
345 pub const fn as_ptr_cell(&self) -> AtomicPtrCell<'_, T> {
346 AtomicPtrCell::from_internal(&self.0)
347 }
348
349 /// returns true if the cell is currently observed to be empty according to the given ordering.
350 pub fn is_empty(&self) -> bool {
351 self.as_ptr_cell().is_empty()
352 }
353
354 /// Atomically swap the current value with the given value.
355 /// returns None if the pointer was null
356 pub fn swap(&self, value: T) -> Option<T> {
357 self.as_ptr_cell().swap(value)
358 }
359
360 /// Atomically swap the current value with the given value.
361 /// returns None if the pointer was null
362 pub fn swap_boxed(&self, value: Box<T>) -> Option<Box<T>> {
363 self.as_ptr_cell().swap_boxed(value)
364 }
365
366 /// Atomically Take T out of the pointer or return None if the pointer was null.
367 pub fn take(&self) -> Option<T> {
368 self.take_boxed().map(|v| *v)
369 }
370
371 /// Atomically Take T out of the pointer or return None if the pointer was null.
372 pub fn take_boxed(&self) -> Option<Box<T>> {
373 self.as_ptr_cell().take_boxed()
374 }
375
376 /// Atomically sets the value of the pointer to T.
377 /// This fn is also guaranteed to invoke the Drop
378 /// of a previous value if one was present before returning.
379 pub fn set(&self, value: T) {
380 self.as_ptr_cell().set(value);
381 }
382
383 /// Atomically sets the value of the pointer to T.
384 /// This fn is also guaranteed to invoke the Drop
385 /// of a previous value if one was present before returning.
386 pub fn set_boxed(&self, value: Box<T>) {
387 self.as_ptr_cell().set_boxed(value);
388 }
389
390 /// Atomically sets the value in the cell if the cell was empty.
391 /// If the Cell was not empty then Some is returned containing
392 /// the value that was intended to be written into the cell.
393 pub fn set_if_absent(&self, value: T) -> Option<T> {
394 self.as_ptr_cell().set_if_absent(value)
395 }
396
397 /// Atomically sets the value in the cell if the cell was empty.
398 /// If the Cell was not empty then Some is returned containing
399 /// the value that was intended to be written into the cell.
400 pub fn set_if_absent_boxed(&self, value: Box<T>) -> Option<Box<T>> {
401 self.as_ptr_cell().set_if_absent_boxed(value)
402 }
403
404 /// Atomically replaces the value in a Cell if the Cell is not empty.
405 /// If the cell is empty then this fn does not modify the cell and instead returns `PresetResult::CellWasEmpty` with the value that would have been stored in the cell otherwise.
406 /// If the cell was not empty then `PresetResult::WasPresent` is returned containing the value that was atomically replaced.
407 pub fn set_if_present(&self, value: T) -> PresentResult<T> {
408 self.as_ptr_cell().set_if_present(value)
409 }
410
411 /// Atomically replaces the value in a Cell if the Cell is not empty.
412 /// If the cell is empty then this fn does not modify the cell and instead returns `PresetResult::CellWasEmpty` with the value that would have been stored in the cell otherwise.
413 /// If the cell was not empty then `PresetResult::WasPresent` is returned containing the value that was atomically replaced.
414 pub fn set_if_present_boxed(&self, value: Box<T>) -> PresentResult<Box<T>> {
415 self.as_ptr_cell().set_if_present_boxed(value)
416 }
417
418 /// Moves the value out of the cell and put it in a `BorrowGuard`.
419 /// The returned guard Deref's the value.
420 /// Once the guard is dropped the value is moved back
421 /// into the cell if it is empty at that time.
422 /// Otherwise, dropping the guard drops the value.
423 pub fn borrow(&self) -> Option<BorrowGuard<'_, T>> {
424 self.as_ptr_cell().borrow()
425 }
426
427 /// Moves the value out of the cell and put it in a `BorrowGuard`.
428 /// The returned guard Deref's the value.
429 /// Once the guard is dropped the value is moved back
430 /// into the cell if it is empty at that time.
431 /// Otherwise, dropping the guard drops the value.
432 ///
433 /// If the cell is empty this fn calls the `FnOnce` to create a value to put into the `BorrowGuard`.
434 /// The value will be moved into the Cell once the
435 ///
436 pub fn borrow_or_else(&self, f: impl FnOnce() -> T) -> BorrowGuard<'_, T> {
437 self.as_ptr_cell().borrow_or_else(f)
438 }
439
440 /// Moves the value out of the cell and put it in a `BorrowGuard`.
441 /// The returned guard Deref's the value.
442 /// Once the guard is dropped the value is moved back
443 /// into the cell if it is empty at that time.
444 /// Otherwise, dropping the guard drops the value.
445 ///
446 /// If the cell is empty this fn calls the `FnOnce` to create a value to put into the `BorrowGuard`.
447 /// The value will be moved into the Cell once the
448 ///
449 pub fn borrow_or_else_boxed(&self, f: impl FnOnce() -> Box<T>) -> BorrowGuard<'_, T> {
450 self.as_ptr_cell().borrow_or_else_boxed(f)
451 }
452
453 /// Borrows the current value in the cell and in doing so atomically replaces the value with the given value.
454 /// If the cell was empty then this fn returns `CellWasEmpty` with value that should
455 /// have been stored in the cell and the cell is left empty.
456 pub fn borrow_swap(&self, value: T) -> BorrowSwapResult<T, T> {
457 self.as_ptr_cell().borrow_swap(value)
458 }
459
460 /// Borrows the current value in the cell and in doing so atomically replaces the value with the given value.
461 /// If the cell was empty then this fn returns `CellWasEmpty` with value that should
462 /// have been stored in the cell and the cell is left empty.
463 pub fn borrow_swap_boxed(&self, value: Box<T>) -> BorrowSwapResult<T, Box<T>> {
464 self.as_ptr_cell().borrow_swap_boxed(value)
465 }
466
467 ///
468 /// Get the inner ptr.
469 /// # Safety
470 /// The caller must guarantee that no values other than pointers created by `Box::into_raw` or null can be read from the underlying pointer.
471 /// The easiest way to guarantee this is to never write those "garbage" values into the pointer.
472 ///
473 /// In addition, the caller can assume that any invocation of any fn of this crate in any thread may move the value behind the pointer or drop it making the pointer dangling.
474 /// If the caller wants to get a "ref" to the underlying value of the pointer then it must therefore ensure that no such calls occur
475 ///
476 pub const unsafe fn inner(&self) -> &AtomicPtr<T> {
477 &self.0
478 }
479
480 ///
481 /// Get the inner ptr as a mut.
482 ///
483 /// # Safety
484 /// The caller must guarantee that no values other than pointers created by `Box::into_raw` or null can be read from the underlying pointer.
485 /// The easiest way to guarantee this is to never write those "garbage" values into the pointer.
486 ///
487 /// In addition, the caller can assume that any invocation of any fn of this crate may move the value behind the pointer or drop it making the pointer dangling.
488 /// If the caller wants to get a "ref" to the underlying value of the pointer then it must therefore ensure that no such calls occur
489 ///
490 pub const unsafe fn inner_mut(&mut self) -> &mut AtomicPtr<T> {
491 &mut self.0
492 }
493 }
494
495 ///
496 /// This is a helper struct that is guaranteed to have the exact same layout as `&AtomicPtr<T>`.
497 ///
498 /// It offers high level safe manipulation functions to move data in and out of the pointer.
499 /// It offers boxed and non-boxed variants for operation.
500 /// In general all boxed operations are marginally faster because the "Box" is already on the heap
501 /// and the data must not be moved from the stack to the heap and vice versa.
502 ///
503 #[repr(transparent)]
504 #[derive(Debug)]
505 pub struct AtomicPtrCell<'a, T: Sync + Send + 'static>(&'a AtomicPtr<T>);
506
507 impl<'a, T: Sync + Send + 'static> AtomicPtrCell<'a, T> {
508 ///
509 /// Construct a new non-owned `AtomicPtrCell` from a given `AtomicPtr`.
510 /// # Safety
511 /// `AtomicPtr` must contain null or a pointer made by `Box<T>::into_raw`
512 ///
513 pub const unsafe fn new(value: &'a AtomicPtr<T>) -> Self {
514 Self(value)
515 }
516
517 ///
518 /// # Safety
519 /// The pointer must contain null or a pointer made by `Box<T>::into_raw`
520 /// Pointer must be valid for the lifetime `'a`.
521 ///
522 pub const unsafe fn from_ptr(value: *mut *mut T) -> Self {
523 Self(AtomicPtr::from_ptr(value))
524 }
525
526 ///
527 /// # Safety
528 /// Each `AtomicPtr` in the slice must either contain null or a pointer made by `Box<T>::into_raw`
529 ///
530 pub const unsafe fn from_slice<'b>(value: &'b [&'a AtomicPtr<T>]) -> &'b [Self] {
531 core::slice::from_raw_parts(value.as_ptr().cast::<AtomicPtrCell<T>>(), value.len())
532 }
533
534 ///
535 /// # Safety
536 /// The slice must not contain null elements.
537 /// Each Pointer in the slice must point to a pointer which is either null or was made by `Box<T>::into_raw`
538 /// The pointers must be valid for the lifetime 'a.
539 ///
540 pub const unsafe fn from_ptr_slice(value: &[*mut *mut T]) -> &[Self] {
541 core::slice::from_raw_parts(value.as_ptr().cast::<AtomicPtrCell<T>>(), value.len())
542 }
543
544 /// Internal constructor where safety guarantees can be made.
545 pub(crate) const fn from_internal(value: &'a AtomicPtr<T>) -> Self {
546 Self(value)
547 }
548
549 /// Helper fn to turn the moved raw ptr into a Box if it was not null.
550 fn inner_from_raw(value: *mut T) -> Option<Box<T>> {
551 if value.is_null() {
552 return None;
553 }
554
555 Some(unsafe { Box::from_raw(value) })
556 }
557
558 /// returns true if the cell is currently observed to be empty according to the given ordering.
559 #[must_use]
560 pub fn is_empty(&self) -> bool {
561 self.0.load(SeqCst).is_null()
562 }
563
564 /// Atomically swaps the value out of the cell returning the previous value if there was one.
565 #[must_use]
566 pub fn swap(&self, value: T) -> Option<T> {
567 self.swap_boxed(Box::new(value)).map(|v| *v)
568 }
569
570 /// Atomically swaps the value out of the cell returning the previous value if there was one.
571 #[must_use]
572 pub fn swap_boxed(&self, value: Box<T>) -> Option<Box<T>> {
573 Self::inner_from_raw(self.0.swap(Box::into_raw(value), SeqCst))
574 }
575
576 /// Atomically moves the value out of the cell leaving it empty.
577 /// returns none if the cell was already empty.
578 #[must_use = "use take_boxed() instead if you want to just discard the value as it is just slightly faster."]
579 pub fn take(&self) -> Option<T> {
580 self.take_boxed().map(|v| *v)
581 }
582
583 /// Atomically moves the value out of the cell leaving it empty.
584 /// returns none if the cell was already empty.
585 #[allow(clippy::must_use_candidate)]
586 pub fn take_boxed(&self) -> Option<Box<T>> {
587 Self::inner_from_raw(self.0.swap(null_mut(), SeqCst))
588 }
589
590 /// Atomically sets the value in the cell.
591 /// If the cell was not empty then the previous value is dropped in the current thread before this fn returns.
592 pub fn set(&self, value: T) {
593 self.set_boxed(Box::new(value));
594 }
595
596 /// Atomically sets the value in the cell.
597 /// If the cell was not empty then the previous value is dropped in the current thread before this fn returns.
598 pub fn set_boxed(&self, value: Box<T>) {
599 _ = self.swap_boxed(value);
600 }
601
602 /// Atomically sets the value in the cell if the cell was empty.
603 /// If the Cell was not empty then Some is returned containing
604 /// the value that was intended to be written into the cell.
605 #[allow(clippy::must_use_candidate)]
606 pub fn set_if_absent(&self, value: T) -> Option<T> {
607 self.set_if_absent_boxed(Box::new(value)).map(|v| *v)
608 }
609
610 /// Atomically sets the value in the cell if the cell was empty.
611 /// If the Cell was not empty then Some is returned containing
612 /// the value that was intended to be written into the cell.
613 #[allow(clippy::must_use_candidate)]
614 pub fn set_if_absent_boxed(&self, value: Box<T>) -> Option<Box<T>> {
615 let raw = Box::into_raw(value);
616 if self
617 .0
618 .compare_exchange(null_mut(), raw, SeqCst, Ordering::Acquire)
619 .is_err()
620 {
621 return Some(unsafe { Box::from_raw(raw) });
622 };
623
624 None
625 }
626
627 /// Atomically replaces the value in a Cell if the Cell is not empty.
628 /// If the cell is empty then this fn does not modify the cell and instead returns `PresetResult::CellWasEmpty` with the value that would have been stored in the cell otherwise.
629 /// If the cell was not empty then `PresetResult::WasPresent` is returned containing the value that was atomically replaced.
630 #[allow(clippy::must_use_candidate)]
631 pub fn set_if_present(&self, value: T) -> PresentResult<T> {
632 self.set_if_present_boxed(Box::new(value)).map(|v| *v)
633 }
634
635 /// Atomically replaces the value in a Cell if the Cell is not empty.
636 /// If the cell is empty then this fn does not modify the cell and instead returns `PresetResult::CellWasEmpty` with the value that would have been stored in the cell otherwise.
637 /// If the cell was not empty then `PresetResult::WasPresent` is returned containing the value that was atomically replaced.
638 #[allow(clippy::must_use_candidate)]
639 pub fn set_if_present_boxed(&self, value: Box<T>) -> PresentResult<Box<T>> {
640 let raw = Box::into_raw(value);
641
642 let mut cur = self.0.load(SeqCst);
643 loop {
644 if cur.is_null() {
645 return PresentResult::CellWasEmpty(unsafe { Box::from_raw(raw) });
646 }
647
648 cur = match self.0.compare_exchange(cur, raw, SeqCst, SeqCst) {
649 Ok(actual) => {
650 return PresentResult::CellHadValue(unsafe { Box::from_raw(actual) })
651 }
652 Err(actual) => actual,
653 };
654 }
655 }
656
657 /// Moves the value out of the cell and put it in a `BorrowGuard`.
658 /// The returned guard Deref's the value.
659 /// Once the guard is dropped the value is moved back
660 /// into the cell if it is empty at that time.
661 /// Otherwise, dropping the guard drops the value.
662 ///
663 /// This fn returns none if the cell is empty.
664 #[must_use]
665 pub fn borrow(&self) -> Option<BorrowGuard<'a, T>> {
666 self.take_boxed().map(|b| BorrowGuard(Some(b), self.0))
667 }
668
669 /// Moves the value out of the cell and put it in a `BorrowGuard`.
670 /// The returned guard Deref's the value.
671 /// Once the guard is dropped the value is moved back
672 /// into the cell if it is empty at that time.
673 /// Otherwise, dropping the guard drops the value.
674 ///
675 /// If the cell is empty this fn calls the `FnOnce` to create a value to put into the `BorrowGuard`.
676 /// The value will be moved into the Cell once the
677 ///
678 pub fn borrow_or_else(&self, f: impl FnOnce() -> T) -> BorrowGuard<'a, T> {
679 self.borrow_or_else_boxed(|| Box::new(f()))
680 }
681
682 /// Moves the value out of the cell and put it in a `BorrowGuard`.
683 /// The returned guard Deref's the value.
684 /// Once the guard is dropped the value is moved back
685 /// into the cell if it is empty at that time.
686 /// Otherwise, dropping the guard drops the value.
687 ///
688 /// If the cell is empty this fn calls the `FnOnce` to create a value to put into the `BorrowGuard`.
689 /// The value will be moved into the Cell once the
690 ///
691 pub fn borrow_or_else_boxed(&self, f: impl FnOnce() -> Box<T>) -> BorrowGuard<'a, T> {
692 self.borrow()
693 .unwrap_or_else(|| BorrowGuard(Some(f()), self.0))
694 }
695
696 /// Borrows the current value in the cell and in doing so atomically replaces the value with the given value.
697 /// If the cell was empty then this fn returns `CellWasEmpty` with value that should
698 /// have been stored in the cell and the cell is left empty.
699 pub fn borrow_swap(&self, value: T) -> BorrowSwapResult<'a, T, T> {
700 self.borrow_swap_boxed(Box::new(value)).map_err(|v| *v)
701 }
702
703 /// Borrows the current value in the cell and in doing so atomically replaces the value with the given value.
704 /// If the cell was empty then this fn returns `CellWasEmpty` with value that should
705 /// have been stored in the cell and the cell is left empty.
706 #[must_use]
707 pub fn borrow_swap_boxed(&self, value: Box<T>) -> BorrowSwapResult<'a, T, Box<T>> {
708 match self.set_if_present_boxed(value) {
709 PresentResult::CellHadValue(value) => {
710 BorrowSwapResult::BorrowSwapped(BorrowGuard(Some(value), self.0))
711 }
712 PresentResult::CellWasEmpty(np) => BorrowSwapResult::CellWasEmpty(np),
713 }
714 }
715
716 ///
717 /// Get the inner ptr.
718 /// # Safety
719 /// The caller must guarantee that no values other than pointers created by `Box::into_raw` or null can be read from the underlying pointer.
720 /// The easiest way to guarantee this is to never write those "garbage" values into the pointer.
721 ///
722 /// In addition, the caller can assume that any invocation of any fn of this crate in any thread may move the value behind the pointer or drop it making the pointer dangling.
723 /// If the caller wants to get a "ref" to the underlying value of the pointer then it must therefore ensure that no such calls occur
724 #[must_use]
725 pub const unsafe fn inner(&self) -> &'a AtomicPtr<T> {
726 self.0
727 }
728 }
729
730 /// Borrow guard of a `AtomicCell`. Once this cell is dropped the value is moved back into the cell
731 /// if the cell is empty at that time.
732 ///
733 /// This guard has no knowledge of what is happening to the cell in the meantime.
734 /// It is entirely possible that during the lifetime of the guard the cell is filled and emptied multiple times.
735 /// This has no effect on the behavior of the guard.
736 /// The guard and its fn's only care about the state it can atomically observe when an action occurs, not what happened in the meantime.
737 /// Essentially it does not solve the ABA problem and cannot be used for use cases where solving the ABA Problem is required.
738 ///
739 pub struct BorrowGuard<'a, T: Sync + Send + 'static>(Option<Box<T>>, &'a AtomicPtr<T>);
740 impl<T: Sync + Send + 'static> BorrowGuard<'_, T> {
741 /// Drop the borrow guard while discarding the value
742 pub fn discard(mut self) {
743 self.0 = None;
744 //DROP IT
745 }
746
747 /// Drop the borrow guard and discard the value if the cell is empty.
748 pub fn discard_if_absent(mut self) {
749 _ = AtomicPtrCell::from_internal(self.1)
750 .set_if_present_boxed(unsafe { self.0.take().unwrap_unchecked() });
751 self.0 = None;
752 //DROP IT
753 }
754
755 /// Try to swap the borrowed value with the value in the cell.
756 /// Returns true if the value was swapped. false if the cell was empty.
757 pub fn try_swap(&mut self) -> bool {
758 let boxed = unsafe { self.0.take().unwrap_unchecked() };
759 match AtomicPtrCell::from_internal(self.1).set_if_present_boxed(boxed) {
760 PresentResult::CellHadValue(bx) => {
761 self.0 = Some(bx);
762 true
763 }
764 PresentResult::CellWasEmpty(bx) => {
765 self.0 = Some(bx);
766 false
767 }
768 }
769 }
770
771 /// Drop the borrow guard and write the value back into the cell.
772 /// This may also drop the value in the cell that is replaced.
773 pub fn force(mut self) {
774 AtomicPtrCell::from_internal(self.1)
775 .set_boxed(unsafe { self.0.take().unwrap_unchecked() });
776 self.0 = None;
777 //DROP IT
778 }
779
780 /// Drops the borrow guard if the value can be written back into the cell (i.e. the cell was empty)
781 /// Returns Some(self) if the cell was not empty.
782 #[allow(clippy::must_use_candidate)]
783 pub fn try_drop(mut self) -> Option<Self> {
784 if let Some(me) = AtomicPtrCell::from_internal(self.1)
785 .set_if_absent_boxed(unsafe { self.0.take().unwrap_unchecked() })
786 {
787 self.0 = Some(me);
788 return Some(self);
789 }
790
791 None
792 }
793
794 /// Drops the Borrow guard while yielding the inner value to the caller. The Cell is left untouched by this call.
795 #[must_use]
796 pub fn into_inner(mut self) -> T {
797 unsafe { *self.0.take().unwrap_unchecked() }
798 }
799
800 /// Drops the Borrow guard while yielding the inner value to the caller. The Cell is left untouched by this call.
801 #[must_use]
802 pub fn into_inner_box(mut self) -> Box<T> {
803 unsafe { self.0.take().unwrap_unchecked() }
804 }
805 }
806
807 impl<T: Sync + Send + 'static> Drop for BorrowGuard<'_, T> {
808 fn drop(&mut self) {
809 if let Some(boxed) = self.0.take() {
810 _ = AtomicPtrCell::from_internal(self.1).set_if_absent_boxed(boxed);
811 }
812 }
813 }
814
815 impl<T: Sync + Send + 'static> Deref for BorrowGuard<'_, T> {
816 type Target = T;
817
818 fn deref(&self) -> &Self::Target {
819 unsafe { self.0.as_ref().unwrap_unchecked() }
820 }
821 }
822
823 impl<T: Sync + Send + 'static> DerefMut for BorrowGuard<'_, T> {
824 fn deref_mut(&mut self) -> &mut Self::Target {
825 unsafe { self.0.as_mut().unwrap_unchecked() }
826 }
827 }
828
829 impl<T: Sync + Send + Debug + 'static> Debug for BorrowGuard<'_, T> {
830 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
831 f.write_fmt(format_args!("BorrowGuard({:?}, {:?})", self.0, self.1))
832 }
833 }
834
835 impl<T: Sync + Send + 'static> From<T> for AtomicPointerCell<T> {
836 fn from(value: T) -> Self {
837 Self::from_value(value)
838 }
839 }
840
841 impl<T: Sync + Send + 'static> Default for AtomicPointerCell<T> {
842 fn default() -> Self {
843 Self::new()
844 }
845 }
846
847 impl<T: Sync + Send + 'static> From<AtomicPointerCell<T>> for AtomicPtr<T> {
848 fn from(value: AtomicPointerCell<T>) -> Self {
849 value.into_inner()
850 }
851 }
852
853 impl<'a, T: Sync + Send + 'static> From<&'a AtomicPointerCell<T>> for AtomicPtrCell<'a, T> {
854 fn from(value: &'a AtomicPointerCell<T>) -> Self {
855 value.as_ptr_cell()
856 }
857 }
858
859 impl<T: Sync + Send + 'static> Clone for AtomicPtrCell<'_, T> {
860 fn clone(&self) -> Self {
861 *self
862 }
863 }
864
865 impl<T: Sync + Send + 'static> Copy for AtomicPtrCell<'_, T> {}
866}