Skip to main content

dope_core/driver/storage/
mod.rs

1use std::{convert, error, fmt, io};
2
3use o3::cell::region;
4
5use crate::driver::{self, flight, lifecycle::routing, route, schedule::timer};
6
7mod impossible;
8mod never;
9pub(super) mod ownership;
10pub(super) mod retirements;
11
12pub(super) use impossible::Impossible;
13pub use never::Never;
14
15/// Restricted construction context for driver-domain storage.
16///
17/// This exposes stable domain identities and route reservation, but
18/// deliberately cannot submit operations. A factory therefore cannot publish
19/// a pointer into its output before the runtime has pinned that output.
20///
21/// ```compile_fail
22/// use dope_core::driver::{
23///     ops::Submit,
24///     storage::Context,
25///     route::{KeyTag, Operation},
26/// };
27///
28/// fn submit_during_build<'d>(
29///     context: &mut Context<'_, 'd>,
30///     target: Operation<'d, KeyTag<1>>,
31/// ) {
32///     let _ = Submit::cancel(context, target);
33/// }
34/// ```
35pub struct Context<'a, 'd> {
36    context: driver::Context<'a, 'd>,
37}
38
39impl<'a, 'd> Context<'a, 'd> {
40    pub(super) fn new(context: driver::Context<'a, 'd>) -> Self {
41        Self { context }
42    }
43
44    pub fn driver(&self) -> driver::Reference<'d> {
45        self.context.driver_ref()
46    }
47
48    pub fn region(&self) -> &region::Token<'d> {
49        self.context.region_token_ref()
50    }
51
52    pub fn timer(&self) -> &'d timer::Timer<'d> {
53        self.context.timer()
54    }
55
56    #[doc(hidden)]
57    pub fn flight_slots<Tag: route::Tag>(
58        &mut self,
59        capacity: usize,
60    ) -> io::Result<flight::Slots<'d, Tag>> {
61        self.context.flight_slots(capacity)
62    }
63
64    pub fn reserve_route<const ID: u8>(&mut self) -> io::Result<routing::Reserved<'d, ID>> {
65        use crate::driver::route::FRAMEWORK;
66
67        if ID == FRAMEWORK {
68            return Err(io::Error::new(
69                io::ErrorKind::InvalidInput,
70                "dope: reserved route",
71            ));
72        }
73        routing::Reserved::reserve_allowed(&mut self.context)
74    }
75}
76
77/// Constructs driver-domain storage through the non-submitting [`Context`].
78pub trait Factory: 'static {
79    type Output<'d>: 'd;
80    type Error: error::Error + Send + Sync + 'static;
81
82    fn build<'d>(self, context: &mut Context<'_, 'd>) -> Result<Self::Output<'d>, Self::Error>;
83}
84
85pub struct Value<T>(T);
86
87impl<T> Value<T> {
88    pub const fn new(value: T) -> Self {
89        Self(value)
90    }
91}
92
93impl<T: 'static> Factory for Value<T> {
94    type Output<'d> = T;
95    type Error = convert::Infallible;
96
97    fn build<'d>(self, _context: &mut Context<'_, 'd>) -> Result<Self::Output<'d>, Self::Error> {
98        Ok(self.0)
99    }
100}
101
102impl Factory for () {
103    type Output<'d> = ();
104    type Error = convert::Infallible;
105
106    fn build<'d>(self, _context: &mut Context<'_, 'd>) -> Result<Self::Output<'d>, Self::Error> {
107        Ok(())
108    }
109}
110
111impl<F: Factory> Factory for Option<F> {
112    type Output<'d> = Option<F::Output<'d>>;
113    type Error = F::Error;
114
115    fn build<'d>(self, context: &mut Context<'_, 'd>) -> Result<Self::Output<'d>, Self::Error> {
116        self.map(|factory| factory.build(context)).transpose()
117    }
118}
119
120#[derive(Debug)]
121pub enum PairError<A, B> {
122    First(A),
123    Second(B),
124}
125
126impl<A: fmt::Display, B: fmt::Display> fmt::Display for PairError<A, B> {
127    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
128        match self {
129            Self::First(error) => error.fmt(formatter),
130            Self::Second(error) => error.fmt(formatter),
131        }
132    }
133}
134
135impl<A, B> error::Error for PairError<A, B>
136where
137    A: error::Error + 'static,
138    B: error::Error + 'static,
139{
140}
141
142impl<A: Factory, B: Factory> Factory for (A, B) {
143    type Output<'d> = (A::Output<'d>, B::Output<'d>);
144    type Error = PairError<A::Error, B::Error>;
145
146    fn build<'d>(self, context: &mut Context<'_, 'd>) -> Result<Self::Output<'d>, Self::Error> {
147        let first = Factory::build(self.0, context).map_err(PairError::First)?;
148        let second = Factory::build(self.1, context).map_err(PairError::Second)?;
149        Ok((first, second))
150    }
151}