use crate::{Py, PyAny, PyObject};
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Waker};
#[derive(Debug, Default)]
struct Inner {
exception: Option<PyObject>,
waker: Option<Waker>,
}
#[derive(Debug, Default)]
pub struct CancelHandle(Arc<Mutex<Inner>>);
impl CancelHandle {
pub fn new() -> Self {
Default::default()
}
pub fn is_cancelled(&self) -> bool {
self.0.lock().unwrap().exception.is_some()
}
pub fn poll_cancelled(&mut self, cx: &mut Context<'_>) -> Poll<PyObject> {
let mut inner = self.0.lock().unwrap();
if let Some(exc) = inner.exception.take() {
return Poll::Ready(exc);
}
if let Some(ref waker) = inner.waker {
if cx.waker().will_wake(waker) {
return Poll::Pending;
}
}
inner.waker = Some(cx.waker().clone());
Poll::Pending
}
pub async fn cancelled(&mut self) -> PyObject {
Cancelled(self).await
}
#[doc(hidden)]
pub fn throw_callback(&self) -> ThrowCallback {
ThrowCallback(self.0.clone())
}
}
struct Cancelled<'a>(&'a mut CancelHandle);
impl Future for Cancelled<'_> {
type Output = PyObject;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.0.poll_cancelled(cx)
}
}
#[doc(hidden)]
pub struct ThrowCallback(Arc<Mutex<Inner>>);
impl ThrowCallback {
pub(super) fn throw(&self, exc: Py<PyAny>) {
let mut inner = self.0.lock().unwrap();
inner.exception = Some(exc);
if let Some(waker) = inner.waker.take() {
waker.wake();
}
}
}