use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio_util::sync::CancellationToken;
use crate::error::SteamError;
pub struct IgnoringCancellation<F> {
inner: Pin<Box<F>>,
token: CancellationToken,
}
impl<F> IgnoringCancellation<F> {
pub fn new(inner: F, token: CancellationToken) -> IgnoringCancellation<F> {
IgnoringCancellation {
inner: Box::pin(inner),
token,
}
}
}
impl<F> fmt::Debug for IgnoringCancellation<F> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("IgnoringCancellation")
.field("cancelled", &self.token.is_cancelled())
.finish()
}
}
impl<F> Future for IgnoringCancellation<F>
where
F: Future<Output = Result<(), SteamError>>,
{
type Output = Result<(), SteamError>;
fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
match this.inner.as_mut().poll(context) {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
Poll::Ready(Err(error)) => {
if matches!(error, SteamError::Cancelled) && this.token.is_cancelled() {
Poll::Ready(Ok(()))
} else {
Poll::Ready(Err(error))
}
}
}
}
}
pub fn ignoring_cancellation<F>(task: F, token: CancellationToken) -> IgnoringCancellation<F>
where
F: Future<Output = Result<(), SteamError>>,
{
IgnoringCancellation::new(task, token)
}
pub trait TaskExtensions: Future<Output = Result<(), SteamError>> + Sized {
fn ignoring_cancellation(self, token: CancellationToken) -> IgnoringCancellation<Self> {
IgnoringCancellation::new(self, token)
}
}
impl<F> TaskExtensions for F where F: Future<Output = Result<(), SteamError>> + Sized {}