#[cfg(not(target_arch = "wasm32"))]
mod native_impl {
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::task::{Context, Poll};
#[derive(Clone)]
pub struct CancellationToken {
cancelled: Arc<AtomicBool>,
}
pub struct CancelGuard {
cancelled: Arc<AtomicBool>,
}
impl CancellationToken {
pub fn new() -> (Self, CancelGuard) {
let cancelled = Arc::new(AtomicBool::new(false));
(
Self {
cancelled: Arc::clone(&cancelled),
},
CancelGuard { cancelled },
)
}
pub fn is_cancelled(&self) -> bool {
self.cancelled.load(Ordering::Acquire)
}
pub fn cancelled(&self) -> CancelledFuture {
CancelledFuture {
token: self.clone(),
}
}
}
impl Drop for CancelGuard {
fn drop(&mut self) {
self.cancelled.store(true, Ordering::Release);
}
}
pub struct CancelledFuture {
token: CancellationToken,
}
impl Future for CancelledFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
if self.token.is_cancelled() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub use native_impl::*;
#[cfg(target_arch = "wasm32")]
mod wasm_impl {
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
#[derive(Clone)]
pub struct CancellationToken {
inner: Rc<TokenInner>,
}
struct TokenInner {
cancelled: Cell<bool>,
waker: Cell<Option<Waker>>,
}
pub struct CancelGuard {
inner: Rc<TokenInner>,
}
impl CancellationToken {
pub fn new() -> (Self, CancelGuard) {
let inner = Rc::new(TokenInner {
cancelled: Cell::new(false),
waker: Cell::new(None),
});
let token = Self {
inner: Rc::clone(&inner),
};
let guard = CancelGuard { inner };
(token, guard)
}
pub fn is_cancelled(&self) -> bool {
self.inner.cancelled.get()
}
pub fn cancelled(&self) -> CancelledFuture {
CancelledFuture {
token: self.clone(),
}
}
}
impl Drop for CancelGuard {
fn drop(&mut self) {
self.inner.cancelled.set(true);
if let Some(waker) = self.inner.waker.take() {
waker.wake();
}
}
}
pub struct CancelledFuture {
token: CancellationToken,
}
impl Future for CancelledFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.token.is_cancelled() {
Poll::Ready(())
} else {
self.token.inner.waker.set(Some(cx.waker().clone()));
Poll::Pending
}
}
}
}
#[cfg(target_arch = "wasm32")]
pub use wasm_impl::*;