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