#![unstable(feature = "thread_local_internals", issue = "none")]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
#[cfg(test)]
mod dynamic_tests;
use crate::cell::{Cell, RefCell};
use crate::error::Error;
use crate::fmt;
#[cfg_attr(not(test), rustc_diagnostic_item = "LocalKey")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LocalKey<T: 'static> {
inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>,
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: 'static> fmt::Debug for LocalKey<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LocalKey").finish_non_exhaustive()
}
}
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
#[allow_internal_unstable(thread_local_internals)]
macro_rules! thread_local {
() => {};
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => (
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
$crate::thread_local!($($rest)*);
);
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => (
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
);
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
$crate::thread_local!($($rest)*);
);
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
);
}
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
#[non_exhaustive]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct AccessError;
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
impl fmt::Debug for AccessError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AccessError").finish()
}
}
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
impl fmt::Display for AccessError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt("already destroyed", f)
}
}
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
impl Error for AccessError {}
impl<T: 'static> LocalKey<T> {
#[doc(hidden)]
#[unstable(
feature = "thread_local_internals",
reason = "recently added to create a key",
issue = "none"
)]
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
pub const unsafe fn new(
inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>,
) -> LocalKey<T> {
LocalKey { inner }
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with<F, R>(&'static self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
self.try_with(f).expect(
"cannot access a Thread Local Storage value \
during or after destruction",
)
}
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
#[inline]
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
where
F: FnOnce(&T) -> R,
{
unsafe {
let thread_local = (self.inner)(None).ok_or(AccessError)?;
Ok(f(thread_local))
}
}
fn initialize_with<F, R>(&'static self, init: T, f: F) -> R
where
F: FnOnce(Option<T>, &T) -> R,
{
unsafe {
let mut init = Some(init);
let reference = (self.inner)(Some(&mut init)).expect(
"cannot access a Thread Local Storage value \
during or after destruction",
);
f(init, reference)
}
}
}
impl<T: 'static> LocalKey<Cell<T>> {
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn set(&'static self, value: T) {
self.initialize_with(Cell::new(value), |value, cell| {
if let Some(value) = value {
cell.set(value.into_inner());
}
});
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn get(&'static self) -> T
where
T: Copy,
{
self.with(|cell| cell.get())
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn take(&'static self) -> T
where
T: Default,
{
self.with(|cell| cell.take())
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn replace(&'static self, value: T) -> T {
self.with(|cell| cell.replace(value))
}
}
impl<T: 'static> LocalKey<RefCell<T>> {
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn with_borrow<F, R>(&'static self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
self.with(|cell| f(&cell.borrow()))
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
self.with(|cell| f(&mut cell.borrow_mut()))
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn set(&'static self, value: T) {
self.initialize_with(RefCell::new(value), |value, cell| {
if let Some(value) = value {
*cell.borrow_mut() = value.into_inner();
}
});
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn take(&'static self) -> T
where
T: Default,
{
self.with(|cell| cell.take())
}
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
pub fn replace(&'static self, value: T) -> T {
self.with(|cell| cell.replace(value))
}
}