use crate::rt;
pub use crate::rt::thread::AccessError;
pub use crate::rt::yield_now;
pub use std::thread::panicking;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::rc::Rc;
use std::{fmt, io};
pub struct JoinHandle<T> {
result: Rc<RefCell<Option<std::thread::Result<T>>>>,
notify: rt::Notify,
}
pub struct LocalKey<T> {
#[doc(hidden)]
pub init: fn() -> T,
#[doc(hidden)]
pub _p: PhantomData<fn(T)>,
}
#[derive(Debug)]
pub struct Builder {}
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: 'static,
T: 'static,
{
let result = Rc::new(RefCell::new(None));
let notify = rt::Notify::new(true, false);
{
let result = result.clone();
rt::spawn(move || {
*result.borrow_mut() = Some(Ok(f()));
notify.notify();
});
}
JoinHandle { result, notify }
}
impl Builder {
pub fn new() -> Builder {
Builder {}
}
pub fn name(self, _name: String) -> Builder {
self
}
pub fn stack_size(self, _size: usize) -> Builder {
self
}
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
Ok(spawn(f))
}
}
impl<T> JoinHandle<T> {
pub fn join(self) -> std::thread::Result<T> {
self.notify.wait();
self.result.borrow_mut().take().unwrap()
}
}
impl<T: fmt::Debug> fmt::Debug for JoinHandle<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("JoinHandle").finish()
}
}
impl<T: 'static> LocalKey<T> {
pub fn with<F, R>(&'static self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
self.try_with(f)
.expect("cannot access a (mock) TLS value during or after it is destroyed")
}
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
where
F: FnOnce(&T) -> R,
{
let value = match unsafe { self.get() } {
Some(v) => v?,
None => {
let value = (self.init)();
rt::execution(|execution| {
execution.threads.local_init(self, value);
});
unsafe { self.get() }.expect("bug")?
}
};
Ok(f(value))
}
unsafe fn get(&'static self) -> Option<Result<&T, AccessError>> {
unsafe fn transmute_lt<'a, 'b, T>(t: &'a T) -> &'b T {
std::mem::transmute::<&'a T, &'b T>(t)
}
rt::execution(|execution| {
let res = execution.threads.local(self)?;
let local = match res {
Ok(l) => l,
Err(e) => return Some(Err(e)),
};
Some(Ok(transmute_lt(local)))
})
}
}
impl<T: 'static> fmt::Debug for LocalKey<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("LocalKey { .. }")
}
}