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>,
}
#[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)),
}
}
}