pub struct LocalKey<T>where
T: 'static,{ /* private fields */ }
Expand description
A thread local storage (TLS) key which owns its contents.
This key uses the fastest possible implementation available to it for the
target platform. It is instantiated with the thread_local!
macro and the
primary method is the with
method, though there are helpers to make
working with Cell
types easier.
The with
method yields a reference to the contained value which cannot
outlive the current thread or escape the given closure.
§Initialization and Destruction
Initialization is dynamically performed on the first call to a setter (e.g.
with
) within a thread, and values that implement Drop
get
destructed when a thread exits. Some platform-specific caveats apply, which
are explained below.
Note that, should the destructor panics, the whole process will be aborted.
A LocalKey
’s initializer cannot recursively depend on itself. Using a
LocalKey
in this way may cause panics, aborts or infinite recursion on
the first call to with
.
§Single-thread Synchronization
Though there is no potential race with other threads, it is still possible to
obtain multiple references to the thread-local data in different places on
the call stack. For this reason, only shared (&T
) references may be obtained.
To allow obtaining an exclusive mutable reference (&mut T
), typically a
Cell
or RefCell
is used (see the std::cell
for more information
on how exactly this works). To make this easier there are specialized
implementations for LocalKey<Cell<T>>
and LocalKey<RefCell<T>>
.
§Examples
use std::cell::Cell;
use std::thread;
// explicit `const {}` block enables more efficient initialization
thread_local!(static FOO: Cell<u32> = const { Cell::new(1) });
assert_eq!(FOO.get(), 1);
FOO.set(2);
// each thread starts out with the initial value of 1
let t = thread::spawn(move || {
assert_eq!(FOO.get(), 1);
FOO.set(3);
});
// wait for the thread to complete and bail out on panic
t.join().unwrap();
// we retain our original value of 2 despite the child thread
assert_eq!(FOO.get(), 2);
§Platform-specific behavior
Note that a “best effort” is made to ensure that destructors for types stored in thread local storage are run, but not all platforms can guarantee that destructors will be run for all types in thread local storage. For example, there are a number of known caveats where destructors are not run:
- On Unix systems when pthread-based TLS is being used, destructors will not be run for TLS values on the main thread when it exits. Note that the application will exit immediately after the main thread exits as well.
- On all platforms it’s possible for TLS to re-initialize other TLS slots during destruction. Some platforms ensure that this cannot happen infinitely by preventing re-initialization of any slot that has been destroyed, but not all platforms have this guard. Those platforms that do not guard typically have a synthetic limit after which point no more destructors are run.
- When the process exits on Windows systems, TLS destructors may only be run on the thread that causes the process to exit. This is because the other threads may be forcibly terminated.
§Synchronization in thread-local destructors
On Windows, synchronization operations (such as JoinHandle::join
) in
thread local destructors are prone to deadlocks and so should be avoided.
This is because the loader lock is held while a destructor is run. The
lock is acquired whenever a thread starts or exits or when a DLL is loaded
or unloaded. Therefore these events are blocked for as long as a thread
local destructor is running.
Implementations§
Source§impl<T> LocalKey<T>where
T: 'static,
impl<T> LocalKey<T>where
T: 'static,
1.0.0 · Sourcepub fn with<F, R>(&'static self, f: F) -> R
pub fn with<F, R>(&'static self, f: F) -> R
Acquires a reference to the value in this TLS key.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
This function will panic!()
if the key currently has its
destructor running, and it may panic if the destructor has
previously been run for this thread.
§Examples
thread_local! {
pub static STATIC: String = String::from("I am");
}
assert_eq!(
STATIC.with(|original_value| format!("{original_value} initialized")),
"I am initialized",
);
1.26.0 · Sourcepub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
Acquires a reference to the value in this TLS key.
This will lazily initialize the value if this thread has not referenced
this key yet. If the key has been destroyed (which may happen if this is called
in a destructor), this function will return an AccessError
.
§Panics
This function will still panic!()
if the key is uninitialized and the
key’s initializer panics.
§Examples
thread_local! {
pub static STATIC: String = String::from("I am");
}
assert_eq!(
STATIC.try_with(|original_value| format!("{original_value} initialized")),
Ok(String::from("I am initialized")),
);
Source§impl<T> LocalKey<Cell<T>>where
T: 'static,
impl<T> LocalKey<Cell<T>>where
T: 'static,
1.73.0 · Sourcepub fn set(&'static self, value: T)
pub fn set(&'static self, value: T)
Sets or initializes the contained value.
Unlike the other methods, this will not run the lazy initializer of the thread local. Instead, it will be directly initialized with the given value if it wasn’t initialized yet.
§Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::Cell;
thread_local! {
static X: Cell<i32> = panic!("!");
}
// Calling X.get() here would result in a panic.
X.set(123); // But X.set() is fine, as it skips the initializer above.
assert_eq!(X.get(), 123);
1.73.0 · Sourcepub fn get(&'static self) -> Twhere
T: Copy,
pub fn get(&'static self) -> Twhere
T: Copy,
Returns a copy of the contained value.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::Cell;
thread_local! {
static X: Cell<i32> = const { Cell::new(1) };
}
assert_eq!(X.get(), 1);
1.73.0 · Sourcepub fn take(&'static self) -> Twhere
T: Default,
pub fn take(&'static self) -> Twhere
T: Default,
Takes the contained value, leaving Default::default()
in its place.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::Cell;
thread_local! {
static X: Cell<Option<i32>> = const { Cell::new(Some(1)) };
}
assert_eq!(X.take(), Some(1));
assert_eq!(X.take(), None);
1.73.0 · Sourcepub fn replace(&'static self, value: T) -> T
pub fn replace(&'static self, value: T) -> T
Replaces the contained value, returning the old value.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::Cell;
thread_local! {
static X: Cell<i32> = const { Cell::new(1) };
}
assert_eq!(X.replace(2), 1);
assert_eq!(X.replace(3), 2);
Source§impl<T> LocalKey<RefCell<T>>where
T: 'static,
impl<T> LocalKey<RefCell<T>>where
T: 'static,
1.73.0 · Sourcepub fn with_borrow<F, R>(&'static self, f: F) -> R
pub fn with_borrow<F, R>(&'static self, f: F) -> R
Acquires a reference to the contained value.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
Panics if the value is currently mutably borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::RefCell;
thread_local! {
static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
}
X.with_borrow(|v| assert!(v.is_empty()));
1.73.0 · Sourcepub fn with_borrow_mut<F, R>(&'static self, f: F) -> R
pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R
Acquires a mutable reference to the contained value.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::RefCell;
thread_local! {
static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
}
X.with_borrow_mut(|v| v.push(1));
X.with_borrow(|v| assert_eq!(*v, vec![1]));
1.73.0 · Sourcepub fn set(&'static self, value: T)
pub fn set(&'static self, value: T)
Sets or initializes the contained value.
Unlike the other methods, this will not run the lazy initializer of the thread local. Instead, it will be directly initialized with the given value if it wasn’t initialized yet.
§Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::RefCell;
thread_local! {
static X: RefCell<Vec<i32>> = panic!("!");
}
// Calling X.with() here would result in a panic.
X.set(vec![1, 2, 3]); // But X.set() is fine, as it skips the initializer above.
X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
1.73.0 · Sourcepub fn take(&'static self) -> Twhere
T: Default,
pub fn take(&'static self) -> Twhere
T: Default,
Takes the contained value, leaving Default::default()
in its place.
This will lazily initialize the value if this thread has not referenced this key yet.
§Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::RefCell;
thread_local! {
static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
}
X.with_borrow_mut(|v| v.push(1));
let a = X.take();
assert_eq!(a, vec![1]);
X.with_borrow(|v| assert!(v.is_empty()));
1.73.0 · Sourcepub fn replace(&'static self, value: T) -> T
pub fn replace(&'static self, value: T) -> T
Replaces the contained value, returning the old value.
§Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
§Examples
use std::cell::RefCell;
thread_local! {
static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
}
let prev = X.replace(vec![1, 2, 3]);
assert!(prev.is_empty());
X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
Trait Implementations§
Auto Trait Implementations§
impl<T> Freeze for LocalKey<T>
impl<T> RefUnwindSafe for LocalKey<T>
impl<T> Send for LocalKey<T>
impl<T> Sync for LocalKey<T>
impl<T> Unpin for LocalKey<T>
impl<T> UnwindSafe for LocalKey<T>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self
with the foreground set to
value
.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red()
and
green()
, which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg()
:
use yansi::{Paint, Color};
painted.fg(Color::White);
Set foreground color to white using white()
.
use yansi::Paint;
painted.white();
Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self
with the background set to
value
.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red()
and
on_green()
, which have the same functionality but
are pithier.
§Example
Set background color to red using fg()
:
use yansi::{Paint, Color};
painted.bg(Color::Red);
Set background color to red using on_red()
.
use yansi::Paint;
painted.on_red();
Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute
value
.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold()
and
underline()
, which have the same functionality
but are pithier.
§Example
Make text bold using attr()
:
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);
Make text bold using using bold()
.
use yansi::Paint;
painted.bold();
Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi
Quirk
value
.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask()
and
wrap()
, which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk()
:
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);
Enable wrapping using wrap()
.
use yansi::Paint;
painted.wrap();
Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting()
due to conflicts with Vec::clear()
.
The clear()
method will be removed in a future release.
fn clear(&self) -> Painted<&T>
resetting()
due to conflicts with Vec::clear()
.
The clear()
method will be removed in a future release.Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition
value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted
only when both stdout
and stderr
are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self
from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self
is actually part of its subset T
(and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset
but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self
to the equivalent element of its superset.