dope-net 0.43.0

Owned network transports for dope
use std::mem;

use dope_core::{
    dope_sys::engine::admit::Cancelled,
    driver,
    driver::{
        result,
        retained::{flight, flight::cancel},
        route,
        route::Identity,
        schedule::clock,
    },
    io::{
        event::net::socket::{Completion, Failure, Finished},
        fd::handles,
        socket,
        socket::{option, pending},
    },
};
use o3::{base::time::Positive, mem::Rejected};

use crate::link::oneshot::{
    Error,
    states::{ConnectRetry, Connecting, Creating, Sending},
};

pub(super) enum Retry<'d> {
    Cancel(Result<Cancellation<'d>, cancel::Failure>),
    Connect(Dial<'d>),
    Send(SendProgress<'d>),
    Idle,
}
pub(super) enum Socket<'d> {
    Pending,
    Cancelled(handles::Descriptor<'d>),
    Retry,
    Failed(Error, handles::Descriptor<'d>),
    Finished(Error),
    Stale,
}
pub(super) enum Dial<'d> {
    Pending,
    Retry(result::SubmitError),
    Failed(Error, handles::Descriptor<'d>),
}
pub(super) enum Progress<'d> {
    Connected(clock::Deadline<'d>, SendProgress<'d>),
    Failed(Error, handles::Descriptor<'d>),
    Cancelled(handles::Descriptor<'d>),
}
pub(super) enum SendProgress<'d> {
    Complete(handles::Descriptor<'d>),
    Submitted,
    Retry(result::SubmitError),
    Cancelled(handles::Descriptor<'d>),
    Failed(Error, handles::Descriptor<'d>),
}
pub(super) enum Cancellation<'d> {
    Idle(handles::Descriptor<'d>),
    Pending,
    Retry(result::SubmitError),
}

pub(super) enum Phase<'d> {
    Creating(Creating<'d>),
    CreatingCancelled(handles::Creation<'d, pending::Cancelled>),
    ConnectRetry(ConnectRetry<'d>),
    Connecting(Connecting<'d>),
    ConnectingCancelled(pending::Connection<'d, pending::Cancelled>),
    SendRetry(handles::Descriptor<'d>),
    Sending(Sending<'d>),
    Retired,
}

impl<'d> Phase<'d> {
    pub(super) fn creating(
        socket: handles::Creation<'d>,
        opts: option::Set,
        window: Positive,
    ) -> Self {
        Self::Creating(Creating {
            socket,
            options: opts,
            send_window: window,
        })
    }

    pub(super) fn socket<ID: Identity, A: socket::Prepared>(
        self,
        done: Completion<'d>,
        addr: &A,
        target: route::Target<'d, ID>,
        slots: &flight::Slots<'d, ID>,
        driver: &mut driver::Context<'_, 'd>,
        stopped: bool,
    ) -> (Self, Socket<'d>) {
        let build = match self {
            Self::Creating(build) => build,
            Self::CreatingCancelled(socket) => {
                return match done.try_finish(socket) {
                    Ok(Finished::Created(fd)) => (Self::Retired, Socket::Cancelled(fd)),
                    Ok(Finished::Failed(Failure::Create(error))) => {
                        (Self::Retired, Socket::Finished(Error::Socket(error)))
                    }
                    Ok(Finished::Failed(Failure::Retired)) => {
                        (Self::Retired, Socket::Finished(Error::Abandoned))
                    }
                    Err(mismatch) => {
                        let socket = mismatch.reclaim();
                        (Self::CreatingCancelled(socket), Socket::Stale)
                    }
                };
            }
            state => {
                done.reclaim();
                return (state, Socket::Stale);
            }
        };
        let Creating {
            socket,
            options: opts,
            send_window: window,
        } = build;
        let fd = match done.try_finish(socket) {
            Ok(Finished::Created(fd)) if stopped => {
                return (Self::Retired, Socket::Cancelled(fd));
            }
            Ok(Finished::Created(fd)) => fd,
            Ok(Finished::Failed(Failure::Create(error))) => {
                return (Self::Retired, Socket::Finished(Error::Socket(error)));
            }
            Ok(Finished::Failed(Failure::Retired)) => {
                return (Self::Retired, Socket::Finished(Error::Abandoned));
            }
            Err(mismatch) => {
                let socket = mismatch.reclaim();
                return (Self::creating(socket, opts, window), Socket::Stale);
            }
        };
        let (state, dial) = ConnectRetry {
            fd,
            options: opts,
            send_window: window,
        }
        .submit(addr, target, slots, driver);
        let outcome = match dial {
            Dial::Pending => Socket::Pending,
            Dial::Retry(_) => Socket::Retry,
            Dial::Failed(error, fd) => Socket::Failed(error, fd),
        };
        (state, outcome)
    }

    pub(super) fn cancel(
        self,
        driver: &mut driver::Context<'_, 'd>,
    ) -> (Self, Result<Cancellation<'d>, cancel::Failure>) {
        let (phase, progress) = match self {
            Self::Creating(build) => {
                let Creating {
                    socket,
                    options,
                    send_window: window,
                } = build;
                match socket.try_cancel(driver).map_err(Rejected::into_parts) {
                    Ok((
                        socket,
                        Cancelled::Submitted | Cancelled::Queued | Cancelled::Completed,
                    )) => (Self::CreatingCancelled(socket), Cancellation::Pending),
                    Err((socket, cause)) => {
                        let restored = Self::Creating(Creating {
                            socket,
                            options,
                            send_window: window,
                        });
                        return match cause {
                            cancel::Error::Full(error) => {
                                (restored, Ok(Cancellation::Retry(error)))
                            }
                            cancel::Error::Rejected(cause) => (restored, Err(cause)),
                        };
                    }
                }
            }
            Self::Connecting(dial) => return dial.cancel(driver),
            Self::Sending(tx) => return tx.cancel(driver),
            Self::ConnectRetry(retry) => (Self::Retired, Cancellation::Idle(retry.fd)),
            Self::SendRetry(fd) => (Self::Retired, Cancellation::Idle(fd)),
            state => (state, Cancellation::Pending),
        };
        (phase, Ok(progress))
    }
}

const _: () = assert!(mem::size_of::<Phase<'static>>() <= 88);