-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Thread local try with #43158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thread local try with #43158
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -232,6 +232,32 @@ pub enum LocalKeyState { | |
Destroyed, | ||
} | ||
|
||
/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). | ||
#[unstable(feature = "thread_local_state", | ||
reason = "state querying was recently added", | ||
issue = "27716")] | ||
pub struct AccessError { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you reexport this outside the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, but comment not marked as outdated. |
||
_private: (), | ||
} | ||
|
||
#[unstable(feature = "thread_local_state", | ||
reason = "state querying was recently added", | ||
issue = "27716")] | ||
impl fmt::Debug for AccessError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_struct("AccessError").finish() | ||
} | ||
} | ||
|
||
#[unstable(feature = "thread_local_state", | ||
reason = "state querying was recently added", | ||
issue = "27716")] | ||
impl fmt::Display for AccessError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
fmt::Display::fmt("already destroyed", f) | ||
} | ||
} | ||
|
||
impl<T: 'static> LocalKey<T> { | ||
#[doc(hidden)] | ||
#[unstable(feature = "thread_local_internals", | ||
|
@@ -331,6 +357,32 @@ impl<T: 'static> LocalKey<T> { | |
} | ||
} | ||
} | ||
|
||
/// 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 a ThreadLocalError. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This function will still `panic!()` if the key is uninitialized and the | ||
/// key's initializer panics. | ||
#[unstable(feature = "thread_local_state", | ||
reason = "state querying was recently added", | ||
issue = "27716")] | ||
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> | ||
where F: FnOnce(&T) -> R { | ||
unsafe { | ||
let slot = (self.inner)().ok_or(AccessError { | ||
_private: (), | ||
})?; | ||
Ok(f(match *slot.get() { | ||
Some(ref inner) => inner, | ||
None => self.init(slot), | ||
})) | ||
} | ||
} | ||
} | ||
|
||
#[doc(hidden)] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// ignore-emscripten no threads support | ||
|
||
#![feature(thread_local_state)] | ||
|
||
use std::thread; | ||
|
||
struct Foo; | ||
|
||
thread_local!(static FOO: Foo = Foo {}); | ||
|
||
impl Drop for Foo { | ||
fn drop(&mut self) { | ||
assert!(FOO.try_with(|_| panic!("`try_with` closure run")).is_err()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add an assertion that this code is run as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, but comment not marked as outdated. |
||
} | ||
} | ||
|
||
fn main() { | ||
thread::spawn(|| { | ||
assert_eq!(FOO.try_with(|_| { | ||
132 | ||
}).expect("`try_with` failed"), 132); | ||
}).join().unwrap(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite the same behavior as before because
Uninitialized
would route to the global logger whereas this implementation would lazily run initialization and then route to the global logger.