rollup merge of #23557: aturon/rfc-909
This commit implements [RFC 909](https://github.com/rust-lang/rfcs/pull/909): The `std::thread_local` module is now deprecated, and its contents are available directly in `std::thread` as `LocalKey`, `LocalKeyState`, and `ScopedKey`. The macros remain exactly as they were, which means little if any code should break. Nevertheless, this is technically a: [breaking-change] Closes #23547
This commit is contained in:
commit
2153c581ef
@ -252,30 +252,23 @@ pub mod num;
|
||||
/* Runtime and platform support */
|
||||
|
||||
#[macro_use]
|
||||
pub mod thread_local;
|
||||
|
||||
pub mod dynamic_lib;
|
||||
pub mod ffi;
|
||||
pub mod old_io;
|
||||
pub mod io;
|
||||
pub mod fs;
|
||||
pub mod net;
|
||||
pub mod os;
|
||||
pub mod env;
|
||||
pub mod path;
|
||||
pub mod old_path;
|
||||
pub mod process;
|
||||
pub mod rand;
|
||||
pub mod time;
|
||||
|
||||
/* Common data structures */
|
||||
pub mod thread;
|
||||
|
||||
pub mod collections;
|
||||
|
||||
/* Threads and communication */
|
||||
|
||||
pub mod thread;
|
||||
pub mod dynamic_lib;
|
||||
pub mod env;
|
||||
pub mod ffi;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
pub mod net;
|
||||
pub mod old_io;
|
||||
pub mod old_path;
|
||||
pub mod os;
|
||||
pub mod path;
|
||||
pub mod process;
|
||||
pub mod rand;
|
||||
pub mod sync;
|
||||
pub mod time;
|
||||
|
||||
#[macro_use]
|
||||
#[path = "sys/common/mod.rs"] mod sys_common;
|
||||
@ -308,7 +301,7 @@ mod std {
|
||||
pub use rt; // used for panic!()
|
||||
pub use vec; // used for vec![]
|
||||
pub use cell; // used for tls!
|
||||
pub use thread_local; // used for thread_local!
|
||||
pub use thread; // used for thread_local!
|
||||
pub use marker; // used for tls!
|
||||
pub use ops; // used for bitflags!
|
||||
|
||||
|
@ -15,7 +15,7 @@ use core::prelude::*;
|
||||
use cell::RefCell;
|
||||
use string::String;
|
||||
use thread::Thread;
|
||||
use thread_local::State;
|
||||
use thread::LocalKeyState;
|
||||
|
||||
struct ThreadInfo {
|
||||
stack_guard: uint,
|
||||
@ -26,7 +26,7 @@ thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(N
|
||||
|
||||
impl ThreadInfo {
|
||||
fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
|
||||
if THREAD_INFO.state() == State::Destroyed {
|
||||
if THREAD_INFO.state() == LocalKeyState::Destroyed {
|
||||
panic!("Use of std::thread::current() is not possible after \
|
||||
the thread's local data has been destroyed");
|
||||
}
|
||||
|
@ -9,40 +9,13 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Thread local storage
|
||||
//!
|
||||
//! This module provides an implementation of thread local storage for Rust
|
||||
//! programs. Thread local storage is a method of storing data into a global
|
||||
//! variable which each thread in the program will have its own copy of.
|
||||
//! Threads do not share this data, so accesses do not need to be synchronized.
|
||||
//!
|
||||
//! At a high level, this module provides two variants of storage:
|
||||
//!
|
||||
//! * Owning thread local storage. This is a type of thread local key which
|
||||
//! owns the value that it contains, and will destroy the value when the
|
||||
//! thread exits. This variant is created with the `thread_local!` macro and
|
||||
//! can contain any value which is `'static` (no borrowed pointers.
|
||||
//!
|
||||
//! * Scoped thread local storage. This type of key is used to store a reference
|
||||
//! to a value into local storage temporarily for the scope of a function
|
||||
//! call. There are no restrictions on what types of values can be placed
|
||||
//! into this key.
|
||||
//!
|
||||
//! Both forms of thread local storage provide an accessor function, `with`,
|
||||
//! which will yield a shared reference to the value to the specified
|
||||
//! closure. Thread local keys only allow shared access to values as there is no
|
||||
//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
|
||||
//! will want to make use of some form of **interior mutability** through the
|
||||
//! `Cell` or `RefCell` types.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![unstable(feature = "thread_local_internals")]
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use cell::UnsafeCell;
|
||||
|
||||
#[macro_use]
|
||||
pub mod scoped;
|
||||
|
||||
// Sure wish we had macro hygiene, no?
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "thread_local_internals")]
|
||||
@ -95,7 +68,7 @@ pub mod __impl {
|
||||
/// });
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Key<T> {
|
||||
pub struct LocalKey<T> {
|
||||
// The key itself may be tagged with #[thread_local], and this `Key` is
|
||||
// stored as a `static`, and it's not valid for a static to reference the
|
||||
// address of another thread_local static. For this reason we kinda wonkily
|
||||
@ -114,15 +87,15 @@ pub struct Key<T> {
|
||||
pub init: fn() -> T,
|
||||
}
|
||||
|
||||
/// Declare a new thread local storage key of type `std::thread_local::Key`.
|
||||
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow_internal_unstable]
|
||||
macro_rules! thread_local {
|
||||
(static $name:ident: $t:ty = $init:expr) => (
|
||||
static $name: ::std::thread_local::Key<$t> = {
|
||||
static $name: ::std::thread::LocalKey<$t> = {
|
||||
use std::cell::UnsafeCell as __UnsafeCell;
|
||||
use std::thread_local::__impl::KeyInner as __KeyInner;
|
||||
use std::thread::__local::__impl::KeyInner as __KeyInner;
|
||||
use std::option::Option as __Option;
|
||||
use std::option::Option::None as __None;
|
||||
|
||||
@ -133,13 +106,13 @@ macro_rules! thread_local {
|
||||
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
|
||||
&__KEY
|
||||
}
|
||||
::std::thread_local::Key { inner: __getit, init: __init }
|
||||
::std::thread::LocalKey { inner: __getit, init: __init }
|
||||
};
|
||||
);
|
||||
(pub static $name:ident: $t:ty = $init:expr) => (
|
||||
pub static $name: ::std::thread_local::Key<$t> = {
|
||||
pub static $name: ::std::thread::LocalKey<$t> = {
|
||||
use std::cell::UnsafeCell as __UnsafeCell;
|
||||
use std::thread_local::__impl::KeyInner as __KeyInner;
|
||||
use std::thread::__local::__impl::KeyInner as __KeyInner;
|
||||
use std::option::Option as __Option;
|
||||
use std::option::Option::None as __None;
|
||||
|
||||
@ -150,7 +123,7 @@ macro_rules! thread_local {
|
||||
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
|
||||
&__KEY
|
||||
}
|
||||
::std::thread_local::Key { inner: __getit, init: __init }
|
||||
::std::thread::LocalKey { inner: __getit, init: __init }
|
||||
};
|
||||
);
|
||||
}
|
||||
@ -183,20 +156,20 @@ macro_rules! __thread_local_inner {
|
||||
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
||||
not(target_arch = "aarch64")),
|
||||
thread_local)]
|
||||
static $name: ::std::thread_local::__impl::KeyInner<$t> =
|
||||
static $name: ::std::thread::__local::__impl::KeyInner<$t> =
|
||||
__thread_local_inner!($init, $t);
|
||||
);
|
||||
(pub static $name:ident: $t:ty = $init:expr) => (
|
||||
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
||||
not(target_arch = "aarch64")),
|
||||
thread_local)]
|
||||
pub static $name: ::std::thread_local::__impl::KeyInner<$t> =
|
||||
pub static $name: ::std::thread::__local::__impl::KeyInner<$t> =
|
||||
__thread_local_inner!($init, $t);
|
||||
);
|
||||
($init:expr, $t:ty) => ({
|
||||
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
|
||||
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
|
||||
::std::thread_local::__impl::KeyInner {
|
||||
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
|
||||
::std::thread::__local::__impl::KeyInner {
|
||||
inner: ::std::cell::UnsafeCell { value: $init },
|
||||
dtor_registered: ::std::cell::UnsafeCell { value: false },
|
||||
dtor_running: ::std::cell::UnsafeCell { value: false },
|
||||
@ -204,15 +177,15 @@ macro_rules! __thread_local_inner {
|
||||
};
|
||||
|
||||
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
|
||||
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
|
||||
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
|
||||
unsafe extern fn __destroy(ptr: *mut u8) {
|
||||
::std::thread_local::__impl::destroy_value::<$t>(ptr);
|
||||
::std::thread::__local::__impl::destroy_value::<$t>(ptr);
|
||||
}
|
||||
|
||||
::std::thread_local::__impl::KeyInner {
|
||||
::std::thread::__local::__impl::KeyInner {
|
||||
inner: ::std::cell::UnsafeCell { value: $init },
|
||||
os: ::std::thread_local::__impl::OsStaticKey {
|
||||
inner: ::std::thread_local::__impl::OS_INIT_INNER,
|
||||
os: ::std::thread::__local::__impl::OsStaticKey {
|
||||
inner: ::std::thread::__local::__impl::OS_INIT_INNER,
|
||||
dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
|
||||
},
|
||||
}
|
||||
@ -226,7 +199,7 @@ macro_rules! __thread_local_inner {
|
||||
#[unstable(feature = "std_misc",
|
||||
reason = "state querying was recently added")]
|
||||
#[derive(Eq, PartialEq, Copy)]
|
||||
pub enum State {
|
||||
pub enum LocalKeyState {
|
||||
/// All keys are in this state whenever a thread starts. Keys will
|
||||
/// transition to the `Valid` state once the first call to `with` happens
|
||||
/// and the initialization expression succeeds.
|
||||
@ -253,7 +226,7 @@ pub enum State {
|
||||
Destroyed,
|
||||
}
|
||||
|
||||
impl<T: 'static> Key<T> {
|
||||
impl<T: 'static> LocalKey<T> {
|
||||
/// Acquire a reference to the value in this TLS key.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
@ -309,16 +282,16 @@ impl<T: 'static> Key<T> {
|
||||
/// any call to `with`.
|
||||
#[unstable(feature = "std_misc",
|
||||
reason = "state querying was recently added")]
|
||||
pub fn state(&'static self) -> State {
|
||||
pub fn state(&'static self) -> LocalKeyState {
|
||||
unsafe {
|
||||
match (self.inner)().get() {
|
||||
Some(cell) => {
|
||||
match *cell.get() {
|
||||
Some(..) => State::Valid,
|
||||
None => State::Uninitialized,
|
||||
Some(..) => LocalKeyState::Valid,
|
||||
None => LocalKeyState::Uninitialized,
|
||||
}
|
||||
}
|
||||
None => State::Destroyed,
|
||||
None => LocalKeyState::Destroyed,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -327,7 +300,7 @@ impl<T: 'static> Key<T> {
|
||||
#[unstable(feature = "std_misc")]
|
||||
#[deprecated(since = "1.0.0",
|
||||
reason = "function renamed to state() and returns more info")]
|
||||
pub fn destroyed(&'static self) -> bool { self.state() == State::Destroyed }
|
||||
pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed }
|
||||
}
|
||||
|
||||
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
|
||||
@ -553,7 +526,7 @@ mod tests {
|
||||
|
||||
use sync::mpsc::{channel, Sender};
|
||||
use cell::UnsafeCell;
|
||||
use super::State;
|
||||
use super::LocalKeyState;
|
||||
use thread;
|
||||
|
||||
struct Foo(Sender<()>);
|
||||
@ -592,21 +565,21 @@ mod tests {
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
assert!(FOO.state() == State::Destroyed);
|
||||
assert!(FOO.state() == LocalKeyState::Destroyed);
|
||||
}
|
||||
}
|
||||
fn foo() -> Foo {
|
||||
assert!(FOO.state() == State::Uninitialized);
|
||||
assert!(FOO.state() == LocalKeyState::Uninitialized);
|
||||
Foo
|
||||
}
|
||||
thread_local!(static FOO: Foo = foo());
|
||||
|
||||
thread::spawn(|| {
|
||||
assert!(FOO.state() == State::Uninitialized);
|
||||
assert!(FOO.state() == LocalKeyState::Uninitialized);
|
||||
FOO.with(|_| {
|
||||
assert!(FOO.state() == State::Valid);
|
||||
assert!(FOO.state() == LocalKeyState::Valid);
|
||||
});
|
||||
assert!(FOO.state() == State::Valid);
|
||||
assert!(FOO.state() == LocalKeyState::Valid);
|
||||
}).join().ok().unwrap();
|
||||
}
|
||||
|
||||
@ -642,7 +615,7 @@ mod tests {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HITS += 1;
|
||||
if K2.state() == State::Destroyed {
|
||||
if K2.state() == LocalKeyState::Destroyed {
|
||||
assert_eq!(HITS, 3);
|
||||
} else {
|
||||
if HITS == 1 {
|
||||
@ -658,7 +631,7 @@ mod tests {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HITS += 1;
|
||||
assert!(K1.state() != State::Destroyed);
|
||||
assert!(K1.state() != LocalKeyState::Destroyed);
|
||||
assert_eq!(HITS, 2);
|
||||
K1.with(|s| *s.get() = Some(S1));
|
||||
}
|
||||
@ -679,7 +652,7 @@ mod tests {
|
||||
|
||||
impl Drop for S1 {
|
||||
fn drop(&mut self) {
|
||||
assert!(K1.state() == State::Destroyed);
|
||||
assert!(K1.state() == LocalKeyState::Destroyed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,7 +675,7 @@ mod tests {
|
||||
fn drop(&mut self) {
|
||||
let S1(ref tx) = *self;
|
||||
unsafe {
|
||||
if K2.state() != State::Destroyed {
|
||||
if K2.state() != LocalKeyState::Destroyed {
|
||||
K2.with(|s| *s.get() = Some(Foo(tx.clone())));
|
||||
}
|
||||
}
|
@ -138,9 +138,43 @@
|
||||
//! synchronization primitives; the threads already provide basic blocking/signaling.
|
||||
//!
|
||||
//! * It can be implemented very efficiently on many platforms.
|
||||
//!
|
||||
//! ## Thread-local storage
|
||||
//!
|
||||
//! This module also provides an implementation of thread local storage for Rust
|
||||
//! programs. Thread local storage is a method of storing data into a global
|
||||
//! variable which each thread in the program will have its own copy of.
|
||||
//! Threads do not share this data, so accesses do not need to be synchronized.
|
||||
//!
|
||||
//! At a high level, this module provides two variants of storage:
|
||||
//!
|
||||
//! * Owned thread-local storage. This is a type of thread local key which
|
||||
//! owns the value that it contains, and will destroy the value when the
|
||||
//! thread exits. This variant is created with the `thread_local!` macro and
|
||||
//! can contain any value which is `'static` (no borrowed pointers).
|
||||
//!
|
||||
//! * Scoped thread-local storage. This type of key is used to store a reference
|
||||
//! to a value into local storage temporarily for the scope of a function
|
||||
//! call. There are no restrictions on what types of values can be placed
|
||||
//! into this key.
|
||||
//!
|
||||
//! Both forms of thread local storage provide an accessor function, `with`,
|
||||
//! which will yield a shared reference to the value to the specified
|
||||
//! closure. Thread-local keys only allow shared access to values as there is no
|
||||
//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
|
||||
//! will want to make use of some form of **interior mutability** through the
|
||||
//! `Cell` or `RefCell` types.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::__local::{LocalKey, LocalKeyState};
|
||||
|
||||
#[unstable(feature = "scoped_tls",
|
||||
reason = "scoped TLS has yet to have wide enough use to fully consider \
|
||||
stabilizing its interface")]
|
||||
pub use self::__scoped::ScopedKey;
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use any::Any;
|
||||
@ -157,6 +191,22 @@ use time::Duration;
|
||||
|
||||
#[allow(deprecated)] use old_io::Writer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Thread-local storage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_use]
|
||||
#[doc(hidden)]
|
||||
#[path = "local.rs"] pub mod __local;
|
||||
|
||||
#[macro_use]
|
||||
#[doc(hidden)]
|
||||
#[path = "scoped.rs"] pub mod __scoped;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Builder
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Thread configuration. Provides detailed control over the properties
|
||||
/// and behavior of new threads.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -322,6 +372,10 @@ impl Builder {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Free functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Spawn a new thread, returning a `JoinHandle` for it.
|
||||
///
|
||||
/// The join handle will implicitly *detach* the child thread upon being
|
||||
@ -433,6 +487,10 @@ pub fn park_timeout(duration: Duration) {
|
||||
*guard = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Thread
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// The internal representation of a `Thread` handle
|
||||
struct Inner {
|
||||
name: Option<String>,
|
||||
@ -557,6 +615,10 @@ impl thread_info::NewThread for Thread {
|
||||
fn new(name: Option<String>) -> Thread { Thread::new(name) }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// JoinHandle and JoinGuard
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Indicates the manner in which a thread exited.
|
||||
///
|
||||
/// A thread that completes without panicking is considered to exit successfully.
|
||||
@ -689,6 +751,10 @@ impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use prelude::v1::*;
|
@ -38,9 +38,7 @@
|
||||
//! });
|
||||
//! ```
|
||||
|
||||
#![unstable(feature = "std_misc",
|
||||
reason = "scoped TLS has yet to have wide enough use to fully consider \
|
||||
stabilizing its interface")]
|
||||
#![unstable(feature = "thread_local_internals")]
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
@ -58,7 +56,10 @@ pub mod __impl {
|
||||
/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
|
||||
/// and `with`, both of which currently use closures to control the scope of
|
||||
/// their contents.
|
||||
pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
|
||||
#[unstable(feature = "scoped_tls",
|
||||
reason = "scoped TLS has yet to have wide enough use to fully consider \
|
||||
stabilizing its interface")]
|
||||
pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
|
||||
|
||||
/// Declare a new scoped thread local storage key.
|
||||
///
|
||||
@ -86,7 +87,7 @@ macro_rules! __scoped_thread_local_inner {
|
||||
target_os = "openbsd",
|
||||
target_arch = "aarch64")),
|
||||
thread_local)]
|
||||
static $name: ::std::thread_local::scoped::Key<$t> =
|
||||
static $name: ::std::thread::ScopedKey<$t> =
|
||||
__scoped_thread_local_inner!($t);
|
||||
);
|
||||
(pub static $name:ident: $t:ty) => (
|
||||
@ -96,11 +97,11 @@ macro_rules! __scoped_thread_local_inner {
|
||||
target_os = "openbsd",
|
||||
target_arch = "aarch64")),
|
||||
thread_local)]
|
||||
pub static $name: ::std::thread_local::scoped::Key<$t> =
|
||||
pub static $name: ::std::thread::ScopedKey<$t> =
|
||||
__scoped_thread_local_inner!($t);
|
||||
);
|
||||
($t:ty) => ({
|
||||
use std::thread_local::scoped::Key as __Key;
|
||||
use std::thread::ScopedKey as __Key;
|
||||
|
||||
#[cfg(not(any(windows,
|
||||
target_os = "android",
|
||||
@ -108,7 +109,7 @@ macro_rules! __scoped_thread_local_inner {
|
||||
target_os = "openbsd",
|
||||
target_arch = "aarch64")))]
|
||||
const _INIT: __Key<$t> = __Key {
|
||||
inner: ::std::thread_local::scoped::__impl::KeyInner {
|
||||
inner: ::std::thread::__scoped::__impl::KeyInner {
|
||||
inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
|
||||
}
|
||||
};
|
||||
@ -119,8 +120,8 @@ macro_rules! __scoped_thread_local_inner {
|
||||
target_os = "openbsd",
|
||||
target_arch = "aarch64"))]
|
||||
const _INIT: __Key<$t> = __Key {
|
||||
inner: ::std::thread_local::scoped::__impl::KeyInner {
|
||||
inner: ::std::thread_local::scoped::__impl::OS_INIT,
|
||||
inner: ::std::thread::__scoped::__impl::KeyInner {
|
||||
inner: ::std::thread::__scoped::__impl::OS_INIT,
|
||||
marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
|
||||
}
|
||||
};
|
||||
@ -129,7 +130,10 @@ macro_rules! __scoped_thread_local_inner {
|
||||
})
|
||||
}
|
||||
|
||||
impl<T> Key<T> {
|
||||
#[unstable(feature = "scoped_tls",
|
||||
reason = "scoped TLS has yet to have wide enough use to fully consider \
|
||||
stabilizing its interface")]
|
||||
impl<T> ScopedKey<T> {
|
||||
/// Insert a value into this scoped thread local storage slot for a
|
||||
/// duration of a closure.
|
||||
///
|
Loading…
x
Reference in New Issue
Block a user