use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "stream03")]
use futures_core03::Stream as Stream03;
use crate::poll::{self, PollFuture, PollInner, Project};
pub struct Fuse<T> {
value: Option<T>,
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> Fuse<Pin<Box<T>>> {
#[inline]
pub fn pin(value: T) -> Self {
Self {
value: Some(Box::pin(value)),
}
}
}
impl<T> Fuse<T> {
#[inline]
pub fn new(value: T) -> Self {
Self { value: Some(value) }
}
#[inline]
pub fn set(&mut self, value: T)
where
Self: Unpin,
{
self.value = Some(value);
}
#[inline]
pub fn clear(&mut self)
where
Self: Unpin,
{
self.value = None;
}
#[must_use]
#[inline]
pub fn empty() -> Self {
Fuse::default()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.value.is_none()
}
#[inline]
pub fn as_inner_ref(&self) -> Option<&T> {
self.value.as_ref()
}
#[inline]
pub async fn poll_inner<P, O>(self: Pin<&mut Self>, poll: P) -> O
where
P: FnMut(Pin<&mut T>, &mut Context<'_>) -> Poll<O>,
{
PollInner::new(ProjectFuse(self), poll).await
}
#[inline]
pub async fn poll_future<P, O>(self: Pin<&mut Self>, poll: P) -> O
where
P: FnMut(Pin<&mut T>, &mut Context<'_>) -> Poll<O>,
{
PollFuture::new(ProjectFuse(self), poll).await
}
#[inline]
pub async fn poll_stream<P, O>(self: Pin<&mut Self>, poll: P) -> Option<O>
where
P: FnMut(Pin<&mut T>, &mut Context<'_>) -> Poll<Option<O>>,
{
poll::PollStream::new(ProjectFuse(self), poll).await
}
#[inline]
pub fn as_inner_mut(&mut self) -> Option<&mut T>
where
Self: Unpin,
{
self.value.as_mut()
}
#[inline]
pub fn as_pin_mut(&mut self) -> Pin<&mut Self>
where
Self: Unpin,
{
Pin::new(self)
}
#[cfg(feature = "stream03")]
#[cfg_attr(docsrs, doc(cfg(feature = "stream03")))]
pub async fn next(&mut self) -> Option<T::Item>
where
Self: Unpin,
T: Stream03,
{
self.as_pin_mut().poll_stream(Stream03::poll_next).await
}
#[inline]
fn project(self: Pin<&mut Self>) -> Pin<&mut Option<T>> {
unsafe { Pin::map_unchecked_mut(self, |this| &mut this.value) }
}
}
impl<T> Future for Fuse<T>
where
T: Future,
{
type Output = T::Output;
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut PollFuture::new(ProjectFuse(self), Future::poll)).poll(cx)
}
}
#[cfg(feature = "stream03")]
#[cfg_attr(docsrs, doc(cfg(feature = "stream03")))]
impl<T> Stream03 for Fuse<T>
where
T: Stream03,
{
type Item = T::Item;
#[inline]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Pin::new(&mut poll::PollStream::new(
ProjectFuse(self),
Stream03::poll_next,
))
.poll(cx)
}
}
impl<T> From<Option<T>> for Fuse<T> {
#[inline]
fn from(value: Option<T>) -> Self {
Self { value }
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> From<Box<T>> for Fuse<Pin<Box<T>>> {
#[inline]
fn from(value: Box<T>) -> Self {
Self {
value: Some(value.into()),
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> From<Option<Box<T>>> for Fuse<Pin<Box<T>>> {
#[inline]
fn from(value: Option<Box<T>>) -> Self {
Self {
value: value.map(Into::into),
}
}
}
impl<T> Default for Fuse<T> {
#[inline]
fn default() -> Self {
Self { value: None }
}
}
struct ProjectFuse<'a, T>(Pin<&'a mut Fuse<T>>);
impl<T> Project for ProjectFuse<'_, T> {
type Value = T;
#[inline]
fn clear(&mut self) {
self.0.as_mut().project().set(None);
}
#[inline]
fn project(&mut self) -> Poll<Pin<&mut Self::Value>> {
match self.0.as_mut().project().as_pin_mut() {
Some(value) => Poll::Ready(value),
None => Poll::Pending,
}
}
}