use std::{mem, os::fd};
use dope_sys::engine::{self, register, shutdown};
use crate::{
driver,
driver::{life::native::create, result, storage},
};
pub struct Teardown {
closing: runtime::Closing,
}
pub struct Generation<Q = ()> {
driver: driver::Driver,
source: Source<Q>,
}
pub(super) struct Source<Q: ?Sized> {
descriptor: Option<raw::Descriptor>,
pub(super) value: Q,
}
impl<Q: ?Sized> Source<Q> {
pub(in crate::driver::life) fn descriptor(&self) -> Option<register::Source<'_>> {
self.descriptor.as_ref().map(raw::Descriptor::source)
}
}
mod raw;
pub(crate) mod runtime;
mod session;
pub use session::Session;
impl<Q> Generation<Q> {
pub fn start<'a>(self, teardown: &'a mut Teardown) -> Session<'a, Q> {
Session {
driver: self.driver,
source: self.source,
teardown,
}
}
}
impl Default for Teardown {
fn default() -> Self {
Self {
closing: runtime::Closing::closed(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Register {
Full(result::SubmitError),
Register(crate::Errno),
}
impl Register {
pub(crate) fn native(error: register::Error) -> Self {
match error {
register::Error::Full(full) => Self::Full(result::SubmitError::queue(full)),
register::Error::Register(error) => Self::Register(error),
}
}
}
pub enum Error<'a, E, T, Q = ()> {
Storage(E),
Close(Closing<'a, E, T, Q>),
}
pub struct Rejected<E, O> {
pub cause: E,
pub operation: O,
}
impl<E, O> Rejected<E, O> {
pub fn map_op<P>(self, map: impl FnOnce(O) -> P) -> Rejected<E, P> {
Rejected {
cause: self.cause,
operation: map(self.operation),
}
}
}
impl<'a, E, T, Q> Error<'a, E, T, Q> {
pub fn cause(&self) -> Cause<&E> {
match self {
Self::Storage(error) => Cause::Storage(error),
Self::Close(state) => Cause::Close {
storage: state.result.as_ref().err(),
failure: state.failure(),
},
}
}
pub fn map_storage<F>(self, map: impl FnOnce(E) -> F) -> Error<'a, F, T, Q> {
match self {
Self::Storage(error) => Error::Storage(map(error)),
Self::Close(state) => Error::Close(state.map_storage(map)),
}
}
}
pub struct Closing<'a, E, T, Q> {
result: Result<T, E>,
runtime: &'a mut runtime::Closing,
source: Source<Q>,
failure: Unmap,
}
#[derive(Clone, Copy, Debug)]
pub enum Unmap {
Backend(storage::Mapping),
Context(storage::Mapping),
}
impl Unmap {
pub(crate) fn native<E>(error: shutdown::Failure<E>) -> Self
where
create::Kernel: From<E>,
{
match error {
shutdown::Failure::Backend(error) => Self::Backend(create::Mapping::from(error)),
shutdown::Failure::Context(error) => Self::Context(create::Mapping::from(error)),
}
}
}
impl Generation<()> {
pub fn new(driver: driver::Driver) -> Self {
Self {
driver,
source: Source {
descriptor: None,
value: (),
},
}
}
pub fn fd<Q: fd::AsFd>(self, source: Q) -> Result<Generation<Q>, Register> {
self.poll(source, register::Interest::Readable)
}
pub fn poll<Q: fd::AsFd>(
self,
source: Q,
interest: register::Interest,
) -> Result<Generation<Q>, Register> {
let Generation {
mut driver,
source: Source { value: (), .. },
} = self;
let fd = register::Source {
fd: source.as_fd(),
interest,
};
unsafe { engine::raw::Register::register(&mut driver.runtime.backend, fd) }
.map_err(Register::native)?;
let receipt = unsafe { raw::Descriptor::new(fd) };
Ok(Generation {
driver,
source: Source {
descriptor: Some(receipt),
value: source,
},
})
}
}
impl<'a, E, T, Q> Closing<'a, E, T, Q> {
pub fn map_storage<F>(self, map: impl FnOnce(E) -> F) -> Closing<'a, F, T, Q> {
Closing {
result: self.result.map_err(map),
runtime: self.runtime,
source: self.source,
failure: self.failure,
}
}
pub fn result(&self) -> &Result<T, E> {
&self.result
}
pub fn failure(&self) -> Unmap {
self.failure
}
pub fn try_close(self, report: impl FnMut(Unmap)) -> Result<T, Error<'a, E, T, Q>> {
let Self {
result,
runtime,
source,
failure: _,
} = self;
match runtime.try_close(report) {
Ok(()) => result.map_err(Error::Storage),
Err((runtime, failure)) => Err(Error::Close(Self {
result,
runtime,
source,
failure,
})),
}
}
fn close(
result: Result<T, E>,
runtime: runtime::Runtime,
teardown: &'a mut Teardown,
source: Source<Q>,
) -> Result<T, Error<'a, E, T, Q>> {
teardown.closing = runtime.close();
let runtime = &mut teardown.closing;
match runtime.failure() {
Some(failure) => Err(Error::Close(Self {
result,
runtime,
source,
failure,
})),
None => result.map_err(Error::Storage),
}
}
}
const _: () = {
assert!(
mem::size_of::<Session<'static, ()>>()
== mem::size_of::<driver::Driver>()
+ mem::size_of::<(usize, Option<raw::Descriptor>)>()
);
assert!(mem::size_of::<Register>() == mem::size_of::<(u8, crate::Errno)>());
};
#[derive(Debug)]
pub enum Cause<E> {
Storage(E),
Close { storage: Option<E>, failure: Unmap },
}
impl<E> Cause<E> {
pub fn map_storage<F>(self, map: impl FnOnce(E) -> F) -> Cause<F> {
match self {
Self::Storage(error) => Cause::Storage(map(error)),
Self::Close { storage, failure } => Cause::Close {
storage: storage.map(map),
failure,
},
}
}
}