use std::{mem, pin};
use dope_core::{
driver,
driver::{
life::domain::{Closing, Error, Rejected},
settings,
settings::{claim, errors},
storage,
},
};
use crate::{
executor::{self, create, drive, session},
random::{self, HashState},
};
pub mod app;
mod domain;
pub mod error;
pub mod lending;
pub mod ops;
mod prepared;
pub mod recipe;
mod worker;
pub use domain::Domain;
pub use prepared::Prepared;
pub use worker::Worker;
#[repr(transparent)]
pub struct Boot<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q> {
session: &'stage session::Scope<'scope, 'life, 'p, 'd, S, Q>,
}
impl<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q>
Boot<'stage, 'scope, 'life, 'p, 'd, S, Q>
{
fn new(session: &'stage session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> Self {
Self { session }
}
pub fn pinned(&self) -> pin::Pin<&'life S::Output<'p, 'd>> {
self.session.pinned()
}
pub fn storage(&self) -> &'life S::Output<'p, 'd> {
self.session.storage()
}
}
pub struct Stage<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q> {
session: &'stage mut session::Scope<'scope, 'life, 'p, 'd, S, Q>,
}
impl<'stage, 'scope, 'life: 'scope, 'p: 'life, 'd: 'p, S: storage::Plan + 'd, Q>
Stage<'stage, 'scope, 'life, 'p, 'd, S, Q>
{
fn new(session: &'stage mut session::Scope<'scope, 'life, 'p, 'd, S, Q>) -> Self {
Self { session }
}
pub fn storage(&self) -> &'life S::Output<'p, 'd> {
self.session.storage()
}
pub fn hash_state(&mut self, domain: random::Domain) -> HashState<'d> {
self.session.hash_state(domain)
}
pub fn driver(&mut self) -> driver::Context<'_, 'd> {
self.session.driver()
}
}
pub trait Installer<S: storage::Plan>: Sized {
type App<'life, 'p, 'd>: executor::raw::App<'d>
where
'd: 'p,
'p: 'life,
'd: 'life,
Self: 'd,
S: 'd;
type Error;
fn install<'scope, 'life, 'p, 'd, Q>(
self,
stage: &mut Stage<'_, 'scope, 'life, 'p, 'd, S, Q>,
) -> Result<Self::App<'life, 'p, 'd>, Self::Error>
where
'd: 'p,
'p: 'life,
'd: 'life,
'life: 'scope,
Self: 'd,
S: 'd,
Q: executor::Startup;
}
pub enum EnterError<'owner, S, O, T, Q = ()> {
Runtime(Rejected<create::Error<'owner>, O>),
Storage(Rejected<S, O>),
Close(Closing<'owner, Rejected<S, O>, T, Q>),
}
impl<'owner, S, O, T, Q> EnterError<'owner, S, O, T, Q> {
pub fn output(&self) -> Option<&T> {
match self {
Self::Runtime(..) | Self::Storage(..) => None,
Self::Close(state) => state.result().as_ref().ok(),
}
}
pub fn cause(&self) -> error::Cause<'_, S> {
match self {
Self::Runtime(error) => error::Cause::Runtime(error.cause.kind()),
Self::Storage(error) => error::Cause::Storage(&error.cause),
Self::Close(state) => error::Cause::closing(state),
}
}
pub fn kind(&self) -> error::Kind<'_, S, &T> {
match self {
Self::Runtime(error) => error::Kind::Runtime(error.cause.kind()),
Self::Storage(error) => error::Kind::Storage(&error.cause),
Self::Close(state) => error::Kind::closing(state),
}
}
}
#[derive(Debug)]
pub enum InstallError<E> {
Drive(drive::Error),
Install(E),
}
#[derive(Debug)]
pub enum Failure<'report, I, T> {
Run(session::Error<'report, Result<T, drive::Error>>),
Install(I),
}
impl<I, T> Failure<'_, I, T> {
pub fn cause(&self) -> error::Failure<'_, I> {
match self {
Self::Run(error) => error::Failure::Run {
cause: error.cause(),
output: match error.output() {
Some(Err(error)) => Some(error),
Some(Ok(_)) | None => None,
},
},
Self::Install(error) => error::Failure::Install(error),
}
}
}
pub enum RunError<'owner, S, I, O, T, Q = ()> {
Create(Rejected<create::Error<'owner>, O>),
Storage(Rejected<S, O>),
Failure(Failure<'owner, I, T>),
Close(ClosingRun<'owner, S, I, O, T, Q>),
}
impl<'owner, S, I, O, T, Q> RunError<'owner, S, I, O, T, Q> {
pub fn cause(&self) -> error::Run<'_, S, I> {
match self {
Self::Create(error) => error::Run::Runtime(error.cause.kind()),
Self::Storage(error) => error::Run::Storage(&error.cause),
Self::Failure(error) => error::Run::Failure(error.cause()),
Self::Close(state) => error::Run::Close {
result: match state.result() {
Ok(Ok(_)) => Ok(Ok(())),
Ok(Err(error)) => Ok(Err(error.cause())),
Err(error) => Err(&error.cause),
},
failure: state.failure(),
},
}
}
pub fn kind(&self) -> RunKind<'_, 'owner, S, I, T> {
match self {
Self::Create(error) => error::Kind::Runtime(error.cause.kind()),
Self::Storage(error) => error::Kind::Storage(&error.cause),
Self::Failure(error) => error::Kind::Run(error),
Self::Close(state) => error::Kind::closing(state),
}
}
}
impl<'owner, S, O, T, Q> From<Error<'owner, Rejected<S, O>, T, Q>>
for EnterError<'owner, S, O, T, Q>
{
fn from(error: Error<'owner, Rejected<S, O>, T, Q>) -> Self {
match error {
Error::Storage(source) => Self::Storage(source),
Error::Close(state) => Self::Close(state),
}
}
}
impl<'owner, S, I, O, T, Q> From<EnterError<'owner, S, O, Result<T, Failure<'owner, I, T>>, Q>>
for RunError<'owner, S, I, O, T, Q>
{
fn from(error: EnterError<'owner, S, O, Result<T, Failure<'owner, I, T>>, Q>) -> Self {
match error {
EnterError::Runtime(source) => Self::Create(source),
EnterError::Storage(source) => Self::Storage(source),
EnterError::Close(state) => Self::Close(state),
}
}
}
const _: () = {
assert!(
mem::size_of::<Boot<'static, 'static, 'static, 'static, 'static, (), ()>>()
== mem::size_of::<usize>()
);
assert!(
mem::align_of::<Boot<'static, 'static, 'static, 'static, 'static, (), ()>>()
== mem::align_of::<usize>()
);
assert!(
mem::size_of::<Stage<'static, 'static, 'static, 'static, 'static, (), ()>>()
== mem::size_of::<&mut session::Scope<'static, 'static, 'static, 'static, (), ()>>()
);
};
#[must_use = "a topology plan must be resolved before it can enter a driver"]
#[repr(transparent)]
pub struct Plan<S, I>((S, I));
impl<S, I> Plan<S, I> {
pub const fn new(storage: S, install: I) -> Self {
Self((storage, install))
}
pub fn into_parts(self) -> (S, I) {
self.0
}
pub fn for_profile<P>(self) -> Result<Prepared<S, I>, errors::Claim>
where
P: settings::Profile,
S: storage::Plan + settings::Resource,
I: settings::Resource,
{
let (storage, install) = self.0;
let needs = claim::Needs::from_tree(&(&storage, &install))?;
let layout = needs.resolve::<P>()?;
Ok(Prepared::new(layout, storage, install))
}
pub fn with_config(self, baseline: settings::Config) -> Result<Prepared<S, I>, errors::Claim>
where
S: storage::Plan + settings::Resource,
I: settings::Resource,
{
let (storage, install) = self.0;
let needs = claim::Needs::from_tree(&(&storage, &install))?;
let layout = needs.apply_to(baseline)?;
Ok(Prepared::new(layout, storage, install))
}
pub fn for_receive<P>(self) -> Result<Prepared<S, I>, errors::Claim>
where
P: settings::Profile,
S: storage::Plan + settings::Resource,
I: settings::Resource,
{
let (storage, install) = self.0;
let needs = claim::Needs::from_tree(&(&storage, &install))?;
let layout = needs.exact::<P>()?;
Ok(Prepared::new(layout, storage, install))
}
pub fn for_install<P>(self) -> Result<Prepared<S, I>, errors::Claim>
where
P: settings::Profile,
S: storage::Claimless,
I: settings::Resource,
{
let (storage, install) = self.0;
let needs = claim::Needs::from_tree(&install)?;
let layout = needs.resolve::<P>()?;
Ok(Prepared::new(layout, storage, install))
}
pub fn with_install(self, baseline: settings::Config) -> Result<Prepared<S, I>, errors::Claim>
where
S: storage::Claimless,
I: settings::Resource,
{
let (storage, install) = self.0;
let needs = claim::Needs::from_tree(&install)?;
let layout = needs.apply_to(baseline)?;
Ok(Prepared::new(layout, storage, install))
}
}
const _: () = {
assert!(mem::size_of::<Plan<usize, u8>>() == mem::size_of::<(usize, u8)>());
assert!(mem::align_of::<Plan<usize, u8>>() == mem::align_of::<(usize, u8)>());
assert!(mem::needs_drop::<Plan<String, ()>>() == mem::needs_drop::<String>());
};
type ClosingRun<'owner, S, I, O, T, Q> =
Closing<'owner, Rejected<S, O>, Result<T, Failure<'owner, I, T>>, Q>;
type RunKind<'a, 'owner, S, I, T> =
error::Kind<'a, S, &'a Result<T, Failure<'owner, I, T>>, Failure<'owner, I, T>>;