Rollup merge of #123651 - tgross35:thread-local-updates, r=Mark-Simulacrum
Thread local updates for idiomatic examples Update thread local examples to make more idiomatic use of `Cell` for `Copy` types, `RefCell` for non-`Copy` types. Also shrink the size of `unsafe` blocks, add `SAFETY` comments, and fix `clippy::redundant_closure_for_method_calls`.
This commit is contained in:
commit
7c8c2f08e1
@ -53,25 +53,25 @@
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cell::RefCell;
|
/// use std::cell::Cell;
|
||||||
/// use std::thread;
|
/// use std::thread;
|
||||||
///
|
///
|
||||||
/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
|
/// thread_local!(static FOO: Cell<u32> = Cell::new(1));
|
||||||
///
|
///
|
||||||
/// FOO.with_borrow(|v| assert_eq!(*v, 1));
|
/// assert_eq!(FOO.get(), 1);
|
||||||
/// FOO.with_borrow_mut(|v| *v = 2);
|
/// FOO.set(2);
|
||||||
///
|
///
|
||||||
/// // each thread starts out with the initial value of 1
|
/// // each thread starts out with the initial value of 1
|
||||||
/// let t = thread::spawn(move|| {
|
/// let t = thread::spawn(move|| {
|
||||||
/// FOO.with_borrow(|v| assert_eq!(*v, 1));
|
/// assert_eq!(FOO.get(), 1);
|
||||||
/// FOO.with_borrow_mut(|v| *v = 3);
|
/// FOO.set(3);
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// // wait for the thread to complete and bail out on panic
|
/// // wait for the thread to complete and bail out on panic
|
||||||
/// t.join().unwrap();
|
/// t.join().unwrap();
|
||||||
///
|
///
|
||||||
/// // we retain our original value of 2 despite the child thread
|
/// // we retain our original value of 2 despite the child thread
|
||||||
/// FOO.with_borrow(|v| assert_eq!(*v, 2));
|
/// assert_eq!(FOO.get(), 2);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Platform-specific behavior
|
/// # Platform-specific behavior
|
||||||
@ -141,15 +141,16 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
/// Publicity and attributes for each static are allowed. Example:
|
/// Publicity and attributes for each static are allowed. Example:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cell::RefCell;
|
/// use std::cell::{Cell, RefCell};
|
||||||
/// thread_local! {
|
|
||||||
/// pub static FOO: RefCell<u32> = RefCell::new(1);
|
|
||||||
///
|
///
|
||||||
/// static BAR: RefCell<f32> = RefCell::new(1.0);
|
/// thread_local! {
|
||||||
|
/// pub static FOO: Cell<u32> = Cell::new(1);
|
||||||
|
///
|
||||||
|
/// static BAR: RefCell<Vec<f32>> = RefCell::new(vec![1.0, 2.0]);
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// FOO.with_borrow(|v| assert_eq!(*v, 1));
|
/// assert_eq!(FOO.get(), 1);
|
||||||
/// BAR.with_borrow(|v| assert_eq!(*v, 1.0));
|
/// BAR.with_borrow(|v| assert_eq!(v[1], 2.0));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note that only shared references (`&T`) to the inner data may be obtained, so a
|
/// Note that only shared references (`&T`) to the inner data may be obtained, so a
|
||||||
@ -164,12 +165,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
/// track any additional state.
|
/// track any additional state.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cell::Cell;
|
/// use std::cell::RefCell;
|
||||||
|
///
|
||||||
/// thread_local! {
|
/// thread_local! {
|
||||||
/// pub static FOO: Cell<u32> = const { Cell::new(1) };
|
/// pub static FOO: RefCell<Vec<u32>> = const { RefCell::new(Vec::new()) };
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// assert_eq!(FOO.get(), 1);
|
/// FOO.with_borrow(|v| assert_eq!(v.len(), 0));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
|
/// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
|
||||||
@ -279,11 +281,10 @@ pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
|
|||||||
where
|
where
|
||||||
F: FnOnce(&T) -> R,
|
F: FnOnce(&T) -> R,
|
||||||
{
|
{
|
||||||
unsafe {
|
// SAFETY: `inner` is safe to call within the lifetime of the thread
|
||||||
let thread_local = (self.inner)(None).ok_or(AccessError)?;
|
let thread_local = unsafe { (self.inner)(None).ok_or(AccessError)? };
|
||||||
Ok(f(thread_local))
|
Ok(f(thread_local))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Acquires a reference to the value in this TLS key, initializing it with
|
/// Acquires a reference to the value in this TLS key, initializing it with
|
||||||
/// `init` if it wasn't already initialized on this thread.
|
/// `init` if it wasn't already initialized on this thread.
|
||||||
@ -301,16 +302,19 @@ fn initialize_with<F, R>(&'static self, init: T, f: F) -> R
|
|||||||
where
|
where
|
||||||
F: FnOnce(Option<T>, &T) -> R,
|
F: FnOnce(Option<T>, &T) -> R,
|
||||||
{
|
{
|
||||||
unsafe {
|
|
||||||
let mut init = Some(init);
|
let mut init = Some(init);
|
||||||
let reference = (self.inner)(Some(&mut init)).expect(
|
|
||||||
|
// SAFETY: `inner` is safe to call within the lifetime of the thread
|
||||||
|
let reference = unsafe {
|
||||||
|
(self.inner)(Some(&mut init)).expect(
|
||||||
"cannot access a Thread Local Storage value \
|
"cannot access a Thread Local Storage value \
|
||||||
during or after destruction",
|
during or after destruction",
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
f(init, reference)
|
f(init, reference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> LocalKey<Cell<T>> {
|
impl<T: 'static> LocalKey<Cell<T>> {
|
||||||
/// Sets or initializes the contained value.
|
/// Sets or initializes the contained value.
|
||||||
@ -377,7 +381,7 @@ pub fn get(&'static self) -> T
|
|||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
{
|
{
|
||||||
self.with(|cell| cell.get())
|
self.with(Cell::get)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes the contained value, leaving `Default::default()` in its place.
|
/// Takes the contained value, leaving `Default::default()` in its place.
|
||||||
@ -407,7 +411,7 @@ pub fn take(&'static self) -> T
|
|||||||
where
|
where
|
||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
self.with(|cell| cell.take())
|
self.with(Cell::take)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the contained value, returning the old value.
|
/// Replaces the contained value, returning the old value.
|
||||||
@ -578,7 +582,7 @@ pub fn take(&'static self) -> T
|
|||||||
where
|
where
|
||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
self.with(|cell| cell.take())
|
self.with(RefCell::take)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the contained value, returning the old value.
|
/// Replaces the contained value, returning the old value.
|
||||||
|
Loading…
Reference in New Issue
Block a user