dope 0.5.6

The manifold runtime
Documentation
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};

use super::{ConnectOutcome, Connector};
use crate::fiber::{Holding, Io};
use crate::transport::Transport;
use crate::transport::wire::Wire;

enum Stage<T: Transport> {
    Init { addr: T::Addr, opts: T::StreamOpts },
    Ticket(u32),
    // Terminal: the connection, if any, now belongs to the returned `Io`, so
    // `Drop` must not cancel it.
    Done,
}

pub struct Connect<'d, const ID: u8, T: Transport, W: Wire>
where
    T::Addr: Clone,
{
    host: Holding<'d, Connector<ID, T, W>>,
    stage: Stage<T>,
}

impl<'d, const ID: u8, T: Transport, W: Wire> Connect<'d, ID, T, W>
where
    T::Addr: Clone,
{
    pub(super) fn new(
        host: Holding<'d, Connector<ID, T, W>>,
        addr: T::Addr,
        opts: T::StreamOpts,
    ) -> Self {
        Self {
            host,
            stage: Stage::Init { addr, opts },
        }
    }
}

impl<const ID: u8, T: Transport, W: Wire> Unpin for Connect<'_, ID, T, W> where T::Addr: Clone {}

impl<'d, const ID: u8, T: Transport, W: Wire> Drop for Connect<'d, ID, T, W>
where
    T::Addr: Clone,
{
    fn drop(&mut self) {
        let Stage::Ticket(tag) = self.stage else {
            return;
        };
        let mut h = self.host.hold();
        h.as_mut().cancel_connect(tag);
    }
}

impl<'d, const ID: u8, T: Transport, W: Wire> Future for Connect<'d, ID, T, W>
where
    T::Addr: Clone,
{
    type Output = io::Result<Io<'d, Connector<ID, T, W>>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.get_mut();
        let host_clone = this.host;
        let mut h = this.host.hold();
        let tag = match this.stage {
            Stage::Done => return Poll::Pending,
            Stage::Ticket(t) => t,
            Stage::Init { ref addr, opts } => {
                let addr = addr.clone();
                let Some(t) = h.as_mut().try_connect(addr, opts) else {
                    return Poll::Ready(Err(io::Error::other(
                        "fiber::Connector: pending pool exhausted",
                    )));
                };
                this.stage = Stage::Ticket(t);
                t
            }
        };
        match h.as_mut().try_resolve(tag, cx.waker()) {
            ConnectOutcome::Conn(token) => {
                this.stage = Stage::Done;
                Poll::Ready(Ok(Io::new(host_clone, token)))
            }
            ConnectOutcome::Failed(e) => {
                this.stage = Stage::Done;
                Poll::Ready(Err(e))
            }
            ConnectOutcome::Pending => Poll::Pending,
        }
    }
}