dope-core 0.35.0

Owned native I/O and completion driver for dope
Documentation
use dope_sys::{
    io::{reactor::complete, socket::addr},
    kernel, memory, probe,
    probe::{accept, receive, session},
    ring::{create, inspect, map, prepare::Rejection},
};

use crate::{
    Engine,
    driver::{
        life::native::{
            create::{Kernel, Mapping},
            host::{Receive, Selection},
        },
        result,
        result::{IoOperation, poll::fault},
        settings,
    },
    io::{socket, transfer},
};

pub(crate) use crate::driver::storage::Failure;

impl<E> From<probe::Syscall<result::Probe, E>> for Failure
where
    Kernel: From<E>,
{
    fn from(cause: probe::Syscall<result::Probe, E>) -> Self {
        Self::Kernel {
            operation: IoOperation::Probe(cause.probe),
            cause: Kernel::from(cause.error),
        }
    }
}

impl From<probe::Syscall<result::Probe, probe::Creation>> for Failure {
    fn from(cause: probe::Syscall<result::Probe, probe::Creation>) -> Self {
        match cause.error {
            probe::Creation::Syscall(error)
            | probe::Creation::Local(addr::Local::Syscall(error)) => probe::Syscall {
                probe: cause.probe,
                error,
            }
            .into(),
            probe::Creation::Local(addr::Local::Length { actual, capacity }) => {
                Self::Probe(result::ProbeError::new(
                    cause.probe,
                    result::Violation::InvalidAddress(socket::Error::Storage { actual, capacity }),
                ))
            }
        }
    }
}

impl From<accept::Check<result::Probe>> for Failure {
    fn from(check: accept::Check<result::Probe>) -> Self {
        let (probe, cause) = match check {
            accept::Check::Early(probe) => (probe, result::Violation::EarlyTermination),
            accept::Check::Outside { probe, cause } => {
                (probe, result::Violation::EscapedSlot(cause.into()))
            }
        };
        Self::Probe(result::ProbeError::new(probe, cause))
    }
}

impl From<memory::Error> for Failure {
    fn from(error: memory::Error) -> Self {
        Self::Mapping(Mapping::from(error))
    }
}

impl<R, U> From<session::Primary<R, U>> for Failure
where
    Kernel: From<R> + From<U>,
{
    fn from(primary: session::Primary<R, U>) -> Self {
        let (op, cause) = match primary {
            session::Primary::Register(error) => {
                (IoOperation::RegisterCanaryBuffers, Kernel::from(error))
            }
            session::Primary::Unregister(error) => {
                (IoOperation::UnregisterCanaryBuffers, Kernel::from(error))
            }
        };
        Self::Kernel {
            operation: op,
            cause,
        }
    }
}

impl<E> From<receive::Install<E>> for Failure
where
    Kernel: From<E>,
{
    fn from(failure: receive::Install<E>) -> Self {
        let op = match failure.mode {
            receive::Mode::Data => IoOperation::InstallReceiveFile,
            receive::Mode::Message => IoOperation::InstallReceiveMessageFile,
        };
        Self::Kernel {
            operation: op,
            cause: Kernel::from(failure.error),
        }
    }
}

impl<O, E, I, L, C> From<session::Checked<result::Probe, O, E, I, L, C, result::ProbeError>>
    for Failure
where
    Engine: complete::Observe<Observation = O>,
    Kernel: From<E>,
    Selection: From<(I, settings::Buffers)>,
    transfer::Len: From<L>,
    transfer::NonZero: From<C>,
{
    fn from(cause: session::Checked<result::Probe, O, E, I, L, C, result::ProbeError>) -> Self {
        use dope_sys::memory::buffer::canary;
        use session::Checked;

        let (probe, fault) = match cause {
            Checked::Wait(cause) => return cause.into(),
            Checked::MissingBuffer(probe) => (probe, result::Violation::MissingBuffer),
            Checked::Terminated(probe) => (probe, result::Violation::EarlyTermination),
            Checked::Buffer { probe, failure } => {
                let fault = match failure {
                    canary::Failure::Inspect(error) => {
                        return Self::Probe(error);
                    }
                    canary::Failure::Index(index) => {
                        let layout = <Receive as memory::raw::Canary>::LAYOUT;
                        result::Violation::InvalidBuffer(
                            Selection::from((index, layout.0.buffers())).into_public(),
                        )
                    }
                    canary::Failure::Length { actual, capacity } => {
                        result::Violation::BufferLength {
                            actual: actual.into(),
                            capacity: capacity.into(),
                        }
                    }
                };
                (probe, fault)
            }
        };
        Self::Probe(result::ProbeError::new(probe, fault))
    }
}

impl<C, E> From<inspect::Unsupported<C, E>> for Failure
where
    C: Into<<crate::Backend as kernel::Source>::Code>,
    Kernel: From<E>,
{
    fn from(error: inspect::Unsupported<C, E>) -> Self {
        match error {
            inspect::Unsupported::Opcode(code) => {
                Self::Capability(result::Capability::Opcode(result::Opcode::native(code)))
            }
            inspect::Unsupported::Register(error) => Self::Kernel {
                operation: IoOperation::RegisterOpcodes,
                cause: Kernel::from(error),
            },
        }
    }
}

impl From<(result::Probe, receive::Send)> for Failure {
    fn from((probe, error): (result::Probe, receive::Send)) -> Self {
        match error {
            receive::Send::Syscall(error) => Self::Kernel {
                operation: IoOperation::Probe(probe),
                cause: Kernel::from(error),
            },
            receive::Send::Partial(partial) => Self::Probe(result::ProbeError::new(
                probe,
                result::Violation::Send(fault::Send::from_partial(partial)),
            )),
        }
    }
}

impl<C, F, R> From<Rejection<C, F, R>> for Failure
where
    Kernel: From<C> + From<F> + From<R>,
{
    fn from(cause: Rejection<C, F, R>) -> Self {
        let (op, cause) = match cause {
            Rejection::Feature(feature) => {
                return Self::Capability(result::Capability::Feature(feature));
            }
            Rejection::Cancel(cause) => (IoOperation::CancelRegistrations, Kernel::from(cause)),
            Rejection::Files(cause) => (IoOperation::RegisterFileTable, Kernel::from(cause)),
            Rejection::Range(cause) => (IoOperation::RegisterFileRange, Kernel::from(cause)),
        };
        Self::Kernel {
            operation: op,
            cause,
        }
    }
}

impl<S, M> From<create::Cause<S, M>> for Failure
where
    Kernel: From<S>,
    Mapping: From<map::Map<M>>,
{
    fn from(cause: create::Cause<S, M>) -> Self {
        match cause {
            create::Cause::Setup(cause) => Self::Kernel {
                operation: IoOperation::ReactorCreate,
                cause: Kernel::from(cause),
            },
            create::Cause::Layout(cause) => Self::RingLayout(cause),
            create::Cause::Map(cause) => Self::Mapping(Mapping::from(cause)),
        }
    }
}

impl<M, R, B> From<create::Primary<M, R, B>> for Failure
where
    Self: From<M>,
    Kernel: From<R> + From<B>,
{
    fn from(primary: create::Primary<M, R, B>) -> Self {
        match primary {
            create::Primary::Ring(error) => Self::from(error),
            create::Primary::Memory(error) => {
                Self::Mapping(<Mapping as From<memory::Error>>::from(error))
            }
            create::Primary::Register(cause) => Self::Kernel {
                operation: IoOperation::RegisterReactor,
                cause: Kernel::from(cause),
            },
            create::Primary::Provided(cause) => Self::Kernel {
                operation: IoOperation::RegisterProvidedBuffers,
                cause: Kernel::from(cause),
            },
        }
    }
}

impl<S, W> From<create::Failure<S, W>> for Failure
where
    Mapping: From<S>,
    Failure: From<W>,
{
    fn from(failure: create::Failure<S, W>) -> Self {
        match failure {
            create::Failure::Storage(error) => Self::Mapping(Mapping::from(error)),
            create::Failure::Memory(error) => {
                Self::Mapping(<Mapping as From<memory::Error>>::from(error))
            }
            create::Failure::Wait(cause) => Self::from(cause),
        }
    }
}

impl<O, E> From<probe::Cause<result::Probe, O, E>> for Failure
where
    Engine: complete::Observe<Observation = O>,
    Kernel: From<E>,
{
    fn from(cause: probe::Cause<result::Probe, O, E>) -> Self {
        use probe::Cause;

        let (probe, fault) = match cause {
            Cause::Enter { probe, error } => {
                return Self::Kernel {
                    operation: IoOperation::Probe(probe),
                    cause: Kernel::from(error),
                };
            }
            Cause::Check(error) => {
                return Self::Probe(result::ProbeError::decode(error));
            }
            Cause::Missing(probe) => (probe, result::Violation::MissingCompletion),
            Cause::Unexpected { probe, observed } => (
                probe,
                result::Violation::UnexpectedCompletion {
                    expected: probe,
                    observed: fault::Observation::new(observed),
                },
            ),
            Cause::Residual {
                probe,
                submit,
                complete,
            } => (
                probe,
                result::Violation::ResidualWork {
                    submissions: fault::Pending::from(submit),
                    completions: fault::Available::from(complete),
                },
            ),
        };
        Self::Probe(result::ProbeError::new(probe, fault))
    }
}