dope-uring 0.43.0

Owned io_uring backend for dope
Documentation
use std::marker;

use dope_sys::{
    io::{Close, Retry},
    memory,
    memory::{Error, Failure, buffer::provided},
    probe::Stopped,
};
use o3::mem::Rejected;

use crate::reactor::{
    buffers::{self, Entry, Producer},
    mappings,
};

#[derive(Debug)]
pub struct Cleanup<L: memory::raw::Receive>(Rejected<Pending<L>, Error>);

#[derive(Debug)]
pub enum Create<L: memory::raw::Receive> {
    Failure(Error),
    Cleanup { primary: Error, cleanup: Cleanup<L> },
}

#[derive(Debug)]
pub struct Open<L> {
    state: mappings::Open,
    layout: marker::PhantomData<fn(L) -> L>,
}

/// Live mappings after a failure has been returned to their owning caller.
#[derive(Debug)]
pub struct Pending<L: memory::raw::Receive> {
    current: mappings::Region,
    context: Option<buffers::raw::Context<L>>,
}

impl<L: memory::raw::Receive> provided::Cleanup for Cleanup<L> {
    type Context = buffers::raw::Context<L>;
    type Producer = Producer<L>;

    fn entries(
        current: <mappings::Mapping<Entry> as Close>::State,
        context: buffers::raw::Context<L>,
    ) -> Self {
        Self::with_region(current, context)
    }

    fn payload(current: <mappings::Mapping<u8> as Close>::State) -> Self {
        Self::region(current)
    }

    fn producer(current: <mappings::Mapping<Entry> as Close>::State) -> Self {
        Self::region(current)
    }
}

impl<L: memory::raw::Receive>
    From<Stopped<buffers::raw::Context<L>, <mappings::Region as Close>::State>> for Cleanup<L>
{
    fn from(
        stopped: Stopped<buffers::raw::Context<L>, <mappings::Region as Close>::State>,
    ) -> Self {
        Self::with_region(stopped.cause, stopped.state)
    }
}

impl<L: memory::raw::Receive> Failure for Cleanup<L> {
    fn failure(&self) -> Error {
        *self.0.error()
    }
}

impl<L: memory::raw::Receive> Retry for Cleanup<L> {
    type Failure = Error;
    type Owner = Pending<L>;

    fn recover(self) -> Rejected<Self::Owner, Error> {
        self.0
    }
}

impl<L: memory::raw::Receive> Close for Pending<L> {
    type State = Cleanup<L>;

    fn try_close(self) -> Result<(), Self::State> {
        use provided::Cleanup as _;

        let Self { current, context } = self;
        match current.try_close() {
            Ok(()) => match context {
                Some(context) => context.try_close().map_err(Cleanup::payload),
                None => Ok(()),
            },
            Err(current) => Err(Cleanup(current.map(|current| Self { current, context }))),
        }
    }
}

impl<L: memory::raw::Receive> Cleanup<L> {
    fn region(current: <mappings::Region as Close>::State) -> Self {
        Self(current.map(|current| Pending {
            current,
            context: None,
        }))
    }

    fn with_region(
        current: <mappings::Region as Close>::State,
        context: buffers::raw::Context<L>,
    ) -> Self {
        Self(current.map(|current| Pending {
            current,
            context: Some(context),
        }))
    }

    pub(super) fn close(
        producer: Producer<L>,
        context: buffers::raw::Context<L>,
    ) -> Result<(), Self> {
        use provided::Cleanup as _;

        let (context, ()) = Stopped::attach(context, producer.try_close())?;
        context.try_close().map_err(Self::payload)
    }
}

impl<L> From<mappings::Open> for Open<L> {
    fn from(state: mappings::Open) -> Self {
        Self {
            state,
            layout: marker::PhantomData,
        }
    }
}

impl<L: memory::raw::Receive> provided::Failure for Open<L> {
    type Cleanup = Cleanup<L>;

    fn into_parts(self) -> (Error, Option<Self::Cleanup>) {
        match self.state {
            mappings::Open::Failure(primary) => (primary, None),
            mappings::Open::Cleanup { primary, current } => {
                (primary, Some(Cleanup::region(current)))
            }
        }
    }
}

impl<L: memory::raw::Receive> provided::Open for Open<L> {
    type Context = buffers::raw::Context<L>;

    fn close(self, context: buffers::raw::Context<L>) -> Create<L> {
        use provided::Cleanup as _;

        match self.state {
            mappings::Open::Failure(primary) => match context.try_close() {
                Ok(()) => Create::Failure(primary),
                Err(current) => Create::Cleanup {
                    primary,
                    cleanup: Cleanup::payload(current),
                },
            },
            mappings::Open::Cleanup { primary, current } => Create::Cleanup {
                primary,
                cleanup: Cleanup::with_region(current, context),
            },
        }
    }
}

impl<L: memory::raw::Receive> From<Open<L>> for Create<L> {
    fn from(state: Open<L>) -> Self {
        Self::from(state.state)
    }
}

impl<L: memory::raw::Receive> From<mappings::Open> for Create<L> {
    fn from(state: mappings::Open) -> Self {
        match state {
            mappings::Open::Failure(primary) => Self::Failure(primary),
            mappings::Open::Cleanup { primary, current } => Self::Cleanup {
                primary,
                cleanup: Cleanup::region(current),
            },
        }
    }
}

impl<L: memory::raw::Receive> provided::Failure for Create<L> {
    type Cleanup = Cleanup<L>;

    fn into_parts(self) -> (Error, Option<Cleanup<L>>) {
        match self {
            Self::Failure(primary) => (primary, None),
            Self::Cleanup { primary, cleanup } => (primary, Some(cleanup)),
        }
    }
}