Skip to main content

dope_runtime/executor/session/
mod.rs

1use std::{mem, result::Result as StdResult, time};
2
3use dope_core::{
4    Errno,
5    driver::{life, schedule::clock},
6    io::Event,
7};
8
9use crate::executor::{InstallError, drive};
10
11mod access;
12mod app;
13mod error;
14mod lent;
15mod manual;
16pub(crate) mod run;
17mod scope;
18
19pub use access::Access;
20pub use app::App;
21pub use error::Error;
22/// Session completion preserving output when quiescence fails.
23pub type Result<'report, T> = std::result::Result<T, Error<'report, T>>;
24
25pub use drive::block::Fixed;
26pub use manual::Manual;
27pub use scope::Scope;
28
29/// Exact runtime failures borrowed independently of retained application output.
30#[derive(Debug)]
31pub enum Cause<'a> {
32    Drive(&'a drive::Error),
33    Quiesce {
34        drive: &'a drive::Error,
35        disarm: Option<Errno>,
36    },
37    Install {
38        cause: &'a InstallError,
39        disarm: Option<Errno>,
40    },
41}
42
43#[derive(Debug)]
44pub enum Kind<'a, T> {
45    Drive(&'a drive::Error),
46    Quiesce {
47        output: T,
48        drive: &'a drive::Error,
49        disarm: Option<Errno>,
50    },
51    Install {
52        cause: &'a InstallError,
53        disarm: Option<Errno>,
54    },
55}
56
57impl<'a, T> Kind<'a, T> {
58    pub fn map<U>(self, map: impl FnOnce(T) -> U) -> Kind<'a, U> {
59        match self {
60            Self::Drive(error) => Kind::Drive(error),
61            Self::Quiesce {
62                output,
63                drive,
64                disarm,
65            } => Kind::Quiesce {
66                output: map(output),
67                drive,
68                disarm,
69            },
70            Self::Install { cause, disarm } => Kind::Install { cause, disarm },
71        }
72    }
73}
74
75pub(crate) struct Core<'a, 'd, Q> {
76    pub(crate) scope: life::Scope<'a, 'd>,
77    pub(super) pending: Option<Event<'d>>,
78    pub(crate) lifecycle: &'a Q,
79}
80
81impl<'a, 'd, Q> Core<'a, 'd, Q> {
82    pub(super) fn new(scope: life::Scope<'a, 'd>, source: &'a Q) -> Self {
83        Self {
84            scope,
85            pending: None,
86            lifecycle: source,
87        }
88    }
89
90    fn admit(&self, start: Option<clock::Deadline<'d>>) -> StdResult<clock::Sample, drive::Error> {
91        let now = start.map_or_else(time::Instant::now, clock::Deadline::into_raw);
92        self.check_time(now)?;
93        Ok(clock::Sample::new(now))
94    }
95
96    fn check_time(&self, now: time::Instant) -> StdResult<(), drive::Error> {
97        let current = self.scope.driver_ref().clock().now().into_raw();
98        if now < current {
99            return Err(drive::Error::regression(now, current));
100        }
101        Ok(())
102    }
103}
104
105const _: () = {
106    assert!(
107        mem::size_of::<Core<'static, 'static, ()>>()
108            == mem::size_of::<life::Scope<'static, 'static>>()
109                + mem::size_of::<Option<Event<'static>>>()
110                + mem::size_of::<usize>()
111    );
112};
113
114/// Owns exact diagnostics after an application has relinquished its session.
115#[derive(Debug, Default)]
116pub struct Completion {
117    quiesce: Option<drive::Error>,
118}
119
120impl Completion {
121    pub const fn new() -> Self {
122        Self { quiesce: None }
123    }
124
125    pub(crate) fn failed<T>(
126        &mut self,
127        output: T,
128        drive: drive::Error,
129        disarm: Option<Errno>,
130    ) -> Error<'_, T> {
131        let drive = self.quiesce.insert(drive);
132        Error::Quiesce {
133            output,
134            drive,
135            disarm,
136        }
137    }
138}