rustpython_common/
static_cell.rs1#[cfg(feature = "threading")]
2mod threading {
3 use crate::lock::OnceCell;
4
5 pub struct StaticCell<T: 'static> {
6 inner: OnceCell<T>,
7 }
8
9 impl<T> StaticCell<T> {
10 #[doc(hidden)]
11 pub const fn _from_once_cell(inner: OnceCell<T>) -> Self {
12 Self { inner }
13 }
14
15 pub fn get(&'static self) -> Option<&'static T> {
16 self.inner.get()
17 }
18
19 pub fn set(&'static self, value: T) -> Result<(), T> {
20 self.inner.set(value)
21 }
22
23 pub fn get_or_init<F>(&'static self, f: F) -> &'static T
24 where
25 F: FnOnce() -> T,
26 {
27 self.inner.get_or_init(f)
28 }
29
30 pub fn get_or_try_init<F, E>(&'static self, f: F) -> Result<&'static T, E>
31 where
32 F: FnOnce() -> Result<T, E>,
33 {
34 if let Some(val) = self.inner.get() {
35 return Ok(val);
36 }
37 let val = f()?;
38 let _ = self.inner.set(val);
39 Ok(self.inner.get().unwrap())
40 }
41 }
42
43 #[macro_export]
44 macro_rules! static_cell {
45 ($($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty;)+) => {
46 $($(#[$attr])*
47 $vis static $name: $crate::static_cell::StaticCell<$t> =
48 $crate::static_cell::StaticCell::_from_once_cell($crate::lock::OnceCell::new());)+
49 };
50 }
51}
52#[cfg(feature = "threading")]
53pub use threading::*;
54
55#[cfg(all(not(feature = "threading"), feature = "std"))]
56mod non_threading {
57 use crate::lock::OnceCell;
58 use std::thread::LocalKey;
59
60 pub struct StaticCell<T: 'static> {
61 inner: &'static LocalKey<OnceCell<&'static T>>,
62 }
63
64 fn leak<T>(x: T) -> &'static T {
65 Box::leak(Box::new(x))
66 }
67
68 impl<T> StaticCell<T> {
69 #[doc(hidden)]
70 #[must_use]
71 pub const fn _from_local_key(inner: &'static LocalKey<OnceCell<&'static T>>) -> Self {
72 Self { inner }
73 }
74
75 #[must_use]
76 pub fn get(&'static self) -> Option<&'static T> {
77 self.inner.with(|x| x.get().copied())
78 }
79
80 pub fn set(&'static self, value: T) -> Result<(), T> {
81 self.inner.with(|x| {
82 if x.get().is_some() {
83 Err(value)
84 } else {
85 let _ = x.set(leak(value));
86 Ok(())
87 }
88 })
89 }
90
91 pub fn get_or_init<F>(&'static self, f: F) -> &'static T
92 where
93 F: FnOnce() -> T,
94 {
95 self.inner.with(|x| *x.get_or_init(|| leak(f())))
96 }
97
98 pub fn get_or_try_init<F, E>(&'static self, f: F) -> Result<&'static T, E>
99 where
100 F: FnOnce() -> Result<T, E>,
101 {
102 self.inner.with(|x| {
103 if let Some(val) = x.get() {
104 Ok(*val)
105 } else {
106 let val = leak(f()?);
107 let _ = x.set(val);
108 Ok(val)
109 }
110 })
111 }
112 }
113
114 #[macro_export]
115 macro_rules! static_cell {
116 ($($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty;)+) => {
117 $($(#[$attr])*
118 $vis static $name: $crate::static_cell::StaticCell<$t> = {
119 ::std::thread_local! {
120 $vis static $name: $crate::lock::OnceCell<&'static $t> = const {
121 $crate::lock::OnceCell::new()
122 };
123 }
124 $crate::static_cell::StaticCell::_from_local_key(&$name)
125 };)+
126 };
127 }
128}
129#[cfg(all(not(feature = "threading"), feature = "std"))]
130pub use non_threading::*;
131
132#[cfg(all(not(feature = "threading"), not(feature = "std")))]
134mod no_std {
135 use crate::lock::OnceCell;
136
137 struct SyncOnceCell<T>(OnceCell<T>);
139 unsafe impl<T> Sync for SyncOnceCell<T> {}
141
142 pub struct StaticCell<T: 'static> {
143 inner: SyncOnceCell<T>,
144 }
145
146 impl<T> StaticCell<T> {
147 #[doc(hidden)]
148 pub const fn _from_once_cell(inner: OnceCell<T>) -> Self {
149 Self {
150 inner: SyncOnceCell(inner),
151 }
152 }
153
154 pub fn get(&'static self) -> Option<&'static T> {
155 self.inner.0.get()
156 }
157
158 pub fn set(&'static self, value: T) -> Result<(), T> {
159 self.inner.0.set(value)
160 }
161
162 pub fn get_or_init<F>(&'static self, f: F) -> &'static T
163 where
164 F: FnOnce() -> T,
165 {
166 self.inner.0.get_or_init(f)
167 }
168
169 pub fn get_or_try_init<F, E>(&'static self, f: F) -> Result<&'static T, E>
170 where
171 F: FnOnce() -> Result<T, E>,
172 {
173 if let Some(val) = self.inner.0.get() {
174 return Ok(val);
175 }
176 let val = f()?;
177 let _ = self.inner.0.set(val);
178 Ok(self.inner.0.get().unwrap())
179 }
180 }
181
182 #[macro_export]
183 macro_rules! static_cell {
184 ($($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty;)+) => {
185 $($(#[$attr])*
186 $vis static $name: $crate::static_cell::StaticCell<$t> =
187 $crate::static_cell::StaticCell::_from_once_cell($crate::lock::OnceCell::new());)+
188 };
189 }
190}
191#[cfg(all(not(feature = "threading"), not(feature = "std")))]
192pub use no_std::*;