use crate::{Arc, Condvar, Future, Mutex, TaskContext, TaskPoll, TaskWake, TaskWaker, pin};
#[doc = crate::_doc!(vendor: "pollster")]
pub(crate) fn future_block<F: Future>(future: F) -> F::Output {
let mut future = pin!(future);
let signal = Arc::new(Signal::new());
let waker = TaskWaker::from(Arc::clone(&signal));
let mut context = TaskContext::from_waker(&waker);
loop {
match future.as_mut().poll(&mut context) {
TaskPoll::Pending => signal.wait(),
TaskPoll::Ready(item) => break item,
}
}
}
struct Signal {
state: Mutex<SignalState>,
cond: Condvar,
}
enum SignalState {
Empty,
Waiting,
Notified,
}
impl TaskWake for Signal {
fn wake(self: Arc<Self>) {
self.notify();
}
}
impl Signal {
fn new() -> Self {
Self {
state: Mutex::new(SignalState::Empty),
cond: Condvar::new(),
}
}
fn wait(&self) {
let mut state = self.state.lock().unwrap();
match *state {
SignalState::Notified => {
*state = SignalState::Empty;
}
SignalState::Waiting => {
unreachable!("Multiple threads waiting on the same signal: Open a bug report!");
}
SignalState::Empty => {
*state = SignalState::Waiting;
while let SignalState::Waiting = *state {
state = self.cond.wait(state).unwrap();
}
}
}
}
fn notify(&self) {
let mut state = self.state.lock().unwrap();
match *state {
SignalState::Notified => {}
SignalState::Empty => *state = SignalState::Notified,
SignalState::Waiting => {
*state = SignalState::Empty;
self.cond.notify_one();
}
}
}
}