Skip to content

Commit 32ae12b

Browse files
committed
Add LocalKey::try_with as an alternative to state
1 parent eb9dfb8 commit 32ae12b

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/libstd/thread/local.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,32 @@ pub enum LocalKeyState {
232232
Destroyed,
233233
}
234234

235+
/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
236+
#[unstable(feature = "thread_local_state",
237+
reason = "state querying was recently added",
238+
issue = "27716")]
239+
pub struct AccessError {
240+
_private: (),
241+
}
242+
243+
#[unstable(feature = "thread_local_state",
244+
reason = "state querying was recently added",
245+
issue = "27716")]
246+
impl fmt::Debug for AccessError {
247+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248+
f.debug_struct("AccessError").finish()
249+
}
250+
}
251+
252+
#[unstable(feature = "thread_local_state",
253+
reason = "state querying was recently added",
254+
issue = "27716")]
255+
impl fmt::Display for AccessError {
256+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257+
fmt::Display::fmt("already destroyed", f)
258+
}
259+
}
260+
235261
impl<T: 'static> LocalKey<T> {
236262
#[doc(hidden)]
237263
#[unstable(feature = "thread_local_internals",
@@ -331,6 +357,32 @@ impl<T: 'static> LocalKey<T> {
331357
}
332358
}
333359
}
360+
361+
/// Acquires a reference to the value in this TLS key.
362+
///
363+
/// This will lazily initialize the value if this thread has not referenced
364+
/// this key yet. If the key has been destroyed (which may happen if this is called
365+
/// in a destructor), this function will return a ThreadLocalError.
366+
///
367+
/// # Panics
368+
///
369+
/// This function will still `panic!()` if the key is uninitialized and the
370+
/// key's initializer panics.
371+
#[unstable(feature = "thread_local_state",
372+
reason = "state querying was recently added",
373+
issue = "27716")]
374+
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
375+
where F: FnOnce(&T) -> R {
376+
unsafe {
377+
let slot = (self.inner)().ok_or(AccessError {
378+
_private: (),
379+
})?;
380+
Ok(f(match *slot.get() {
381+
Some(ref inner) => inner,
382+
None => self.init(slot),
383+
}))
384+
}
385+
}
334386
}
335387

336388
#[doc(hidden)]

src/test/run-pass/tls-try-with.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-emscripten no threads support
12+
13+
#![feature(thread_local_state)]
14+
15+
use std::thread;
16+
17+
struct Foo;
18+
19+
thread_local!(static FOO: Foo = Foo {});
20+
21+
impl Drop for Foo {
22+
fn drop(&mut self) {
23+
assert!(FOO.try_with(|_| panic!("`try_with` closure run")).is_err());
24+
}
25+
}
26+
27+
fn main() {
28+
thread::spawn(|| {
29+
assert_eq!(FOO.try_with(|_| {
30+
132
31+
}).expect("`try_with` failed"), 132);
32+
}).join().unwrap();
33+
}

0 commit comments

Comments
 (0)