You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
1.3 KiB
Rust
61 lines
1.3 KiB
Rust
#[cfg(test)]
|
|
mod tests;
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
use std::task::Waker;
|
|
|
|
pub struct SpawnBlocking<T>(Arc<Mutex<Shared<T>>>);
|
|
|
|
struct Shared<T> {
|
|
value: Option<T>,
|
|
waker: Option<Waker>,
|
|
}
|
|
|
|
pub fn spawn_blocking<T, F>(closure: F) -> SpawnBlocking<T>
|
|
where F: FnOnce() -> T,
|
|
F: Send + 'static,
|
|
T: Send + 'static,
|
|
{
|
|
let inner = Arc::new(Mutex::new(Shared {
|
|
value: None,
|
|
waker: None,
|
|
}));
|
|
|
|
std::thread::spawn({
|
|
let inner = inner.clone();
|
|
move || {
|
|
let value = closure();
|
|
|
|
let maybe_waker = {
|
|
let mut guard = inner.lock().unwrap();
|
|
guard.value = Some(value);
|
|
guard.waker.take()
|
|
};
|
|
|
|
if let Some(waker) = maybe_waker {
|
|
waker.wake();
|
|
}
|
|
}
|
|
});
|
|
|
|
SpawnBlocking(inner)
|
|
}
|
|
|
|
use std::future::Future;
|
|
use std::pin::Pin;
|
|
use std::task::{Context, Poll};
|
|
|
|
impl<T: Send> Future for SpawnBlocking<T> {
|
|
type Output = T;
|
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
|
|
let mut guard = self.0.lock().unwrap();
|
|
if let Some(value) = guard.value.take() {
|
|
return Poll::Ready(value);
|
|
}
|
|
|
|
guard.waker = Some(cx.waker().clone());
|
|
Poll::Pending
|
|
}
|
|
}
|