#[cfg(not(feature = "threading"))] mod non_threading { use crate::lock::OnceCell; use std::thread::LocalKey; pub struct StaticCell { inner: &'static LocalKey>, } fn leak(x: T) -> &'static T { Box::leak(Box::new(x)) } impl StaticCell { #[doc(hidden)] pub const fn _from_local_key(inner: &'static LocalKey>) -> Self { Self { inner } } pub fn get(&'static self) -> Option<&'static T> { self.inner.with(|x| x.get().copied()) } pub fn set(&'static self, value: T) -> Result<(), T> { // thread-safe because it's a unsync::OnceCell self.inner.with(|x| { if x.get().is_some() { Err(value) } else { // will never fail let _ = x.set(leak(value)); Ok(()) } }) } pub fn get_or_init(&'static self, f: F) -> &'static T where F: FnOnce() -> T, { self.inner.with(|x| *x.get_or_init(|| leak(f()))) } pub fn get_or_try_init(&'static self, f: F) -> Result<&'static T, E> where F: FnOnce() -> Result, { self.inner .with(|x| x.get_or_try_init(|| f().map(leak)).copied()) } } #[macro_export] macro_rules! static_cell { ($($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty;)+) => { $($(#[$attr])* $vis static $name: $crate::static_cell::StaticCell<$t> = { ::std::thread_local! { $vis static $name: $crate::lock::OnceCell<&'static $t> = const { $crate::lock::OnceCell::new() }; } $crate::static_cell::StaticCell::_from_local_key(&$name) };)+ }; } } #[cfg(not(feature = "threading"))] pub use non_threading::*; #[cfg(feature = "threading")] mod threading { use crate::lock::OnceCell; pub struct StaticCell { inner: OnceCell, } impl StaticCell { #[doc(hidden)] pub const fn _from_once_cell(inner: OnceCell) -> Self { Self { inner } } pub fn get(&'static self) -> Option<&'static T> { self.inner.get() } pub fn set(&'static self, value: T) -> Result<(), T> { self.inner.set(value) } pub fn get_or_init(&'static self, f: F) -> &'static T where F: FnOnce() -> T, { self.inner.get_or_init(f) } pub fn get_or_try_init(&'static self, f: F) -> Result<&'static T, E> where F: FnOnce() -> Result, { self.inner.get_or_try_init(f) } } #[macro_export] macro_rules! static_cell { ($($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty;)+) => { $($(#[$attr])* $vis static $name: $crate::static_cell::StaticCell<$t> = $crate::static_cell::StaticCell::_from_once_cell($crate::lock::OnceCell::new());)+ }; } } #[cfg(feature = "threading")] pub use threading::*;