rustpython_common/
atomic.rs1use core::ptr::{self, NonNull};
2pub use core::sync::atomic::*;
3pub use radium::Radium;
4
5mod sealed {
6 pub trait Sealed {}
7}
8pub trait PyAtomicScalar: sealed::Sealed {
9 type Radium: Radium<Item = Self>;
10}
11
12pub type PyAtomic<T> = <T as PyAtomicScalar>::Radium;
13
14#[cfg(feature = "threading")]
15macro_rules! atomic_ty {
16 ($i:ty, $atomic:ty) => {
17 $atomic
18 };
19}
20#[cfg(not(feature = "threading"))]
21macro_rules! atomic_ty {
22 ($i:ty, $atomic:ty) => {
23 core::cell::Cell<$i>
24 };
25}
26macro_rules! impl_atomic_scalar {
27 ($(($i:ty, $atomic:ty),)*) => {
28 $(
29 impl sealed::Sealed for $i {}
30 impl PyAtomicScalar for $i {
31 type Radium = atomic_ty!($i, $atomic);
32 }
33 )*
34 };
35}
36impl_atomic_scalar!(
37 (u8, AtomicU8),
38 (i8, AtomicI8),
39 (u16, AtomicU16),
40 (i16, AtomicI16),
41 (u32, AtomicU32),
42 (i32, AtomicI32),
43 (u64, AtomicU64),
44 (i64, AtomicI64),
45 (usize, AtomicUsize),
46 (isize, AtomicIsize),
47 (bool, AtomicBool),
48);
49
50impl<T> sealed::Sealed for *mut T {}
51impl<T> PyAtomicScalar for *mut T {
52 type Radium = atomic_ty!(*mut T, AtomicPtr<T>);
53}
54
55pub struct OncePtr<T> {
56 inner: PyAtomic<*mut T>,
57}
58
59impl<T> Default for OncePtr<T> {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl<T> OncePtr<T> {
66 #[inline]
67 pub fn new() -> Self {
68 OncePtr {
69 inner: Radium::new(ptr::null_mut()),
70 }
71 }
72
73 pub fn get(&self) -> Option<NonNull<T>> {
74 NonNull::new(self.inner.load(Ordering::Acquire))
75 }
76
77 pub fn set(&self, value: NonNull<T>) -> Result<(), NonNull<T>> {
78 let exchange = self.inner.compare_exchange(
79 ptr::null_mut(),
80 value.as_ptr(),
81 Ordering::AcqRel,
82 Ordering::Acquire,
83 );
84 match exchange {
85 Ok(_) => Ok(()),
86 Err(_) => Err(value),
87 }
88 }
89
90 pub fn get_or_init<F>(&self, f: F) -> NonNull<T>
91 where
92 F: FnOnce() -> Box<T>,
93 {
94 enum Void {}
95 match self.get_or_try_init(|| Ok::<_, Void>(f())) {
96 Ok(val) => val,
97 Err(void) => match void {},
98 }
99 }
100
101 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonNull<T>, E>
102 where
103 F: FnOnce() -> Result<Box<T>, E>,
104 {
105 if let Some(val) = self.get() {
106 return Ok(val);
107 }
108
109 Ok(self.initialize(f()?))
110 }
111
112 #[cold]
113 fn initialize(&self, val: Box<T>) -> NonNull<T> {
114 let ptr = Box::into_raw(val);
115 let exchange =
116 self.inner
117 .compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire);
118 let ptr = match exchange {
119 Ok(_) => ptr,
120 Err(winner) => {
121 drop(unsafe { Box::from_raw(ptr) });
122 winner
123 }
124 };
125 unsafe { NonNull::new_unchecked(ptr) }
126 }
127}