Skip to main content

dope_runtime/topology/
domain.rs

1use std::convert;
2
3use dope_core::driver::{
4    life::{creation, domain, recovery},
5    settings::{self, claim, errors},
6    storage,
7};
8
9use crate::{executor, topology::EnterError};
10
11/// Fully validated driver layout plus its generative storage plan.
12pub struct Domain<S> {
13    layout: settings::Config,
14    storage: S,
15}
16
17impl<S> Domain<S> {
18    pub(super) const fn new(layout: settings::Config, store: S) -> Self {
19        Self {
20            layout,
21            storage: store,
22        }
23    }
24
25    pub const fn layout(&self) -> settings::Config {
26        self.layout
27    }
28
29    pub fn for_profile<P>(store: S) -> Result<Self, errors::Claim>
30    where
31        P: settings::Profile,
32        S: storage::Build + settings::Resource,
33    {
34        let layout = claim::Needs::from_tree(&store)?.resolve::<P>()?;
35        Ok(Self::new(layout, store))
36    }
37}
38
39impl<S> Domain<S>
40where
41    S: storage::Direct,
42{
43    pub fn enter_local<O, Done>(
44        self,
45        op: O,
46        report: impl recovery::Observe,
47        finish: impl for<'owner> FnOnce(
48            Result<O::Output, EnterError<'owner, convert::Infallible, O, O::Output>>,
49        ) -> Done,
50    ) -> Done
51    where
52        O: executor::Op<S, ()>,
53    {
54        self.enter((), op, report, finish)
55    }
56
57    pub fn enter<C, O, Done>(
58        self,
59        ctx: C,
60        op: O,
61        report: impl recovery::Observe,
62        finish: impl for<'owner> FnOnce(
63            Result<O::Output, EnterError<'owner, convert::Infallible, O, O::Output, C::Shutdown>>,
64        ) -> Done,
65    ) -> Done
66    where
67        C: executor::Build,
68        O: executor::Op<S, C::Shutdown>,
69    {
70        let mut attempt = creation::Attempt::new();
71        let exec = match ctx.try_build(&mut attempt, self.layout) {
72            Ok(exec) => exec.with_plan(self.storage),
73            Err(cause) => {
74                return finish(Err(EnterError::Runtime(domain::Rejected {
75                    cause,
76                    operation: op,
77                })));
78            }
79        };
80        exec.run(|run| {
81            finish(
82                run.enter(op, report)
83                    .map_err(|error| EnterError::from(error.map_storage(|never| match never {}))),
84            )
85        })
86    }
87}
88
89impl<S> Domain<S>
90where
91    S: storage::Build,
92{
93    pub fn try_local<O, Done>(
94        self,
95        op: O,
96        report: impl recovery::Observe,
97        finish: impl for<'owner> FnOnce(
98            Result<O::Output, EnterError<'owner, S::Error, O, O::Output>>,
99        ) -> Done,
100    ) -> Done
101    where
102        O: executor::Op<S, ()>,
103    {
104        self.try_enter((), op, report, finish)
105    }
106
107    pub fn try_enter<C, O, Done>(
108        self,
109        ctx: C,
110        op: O,
111        report: impl recovery::Observe,
112        finish: impl for<'owner> FnOnce(
113            Result<O::Output, EnterError<'owner, S::Error, O, O::Output, C::Shutdown>>,
114        ) -> Done,
115    ) -> Done
116    where
117        C: executor::Build,
118        O: executor::Op<S, C::Shutdown>,
119    {
120        let mut attempt = creation::Attempt::new();
121        let exec = match ctx.try_build(&mut attempt, self.layout) {
122            Ok(exec) => exec.with_plan(self.storage),
123            Err(cause) => {
124                return finish(Err(EnterError::Runtime(domain::Rejected {
125                    cause,
126                    operation: op,
127                })));
128            }
129        };
130        exec.run(|run| finish(run.try_enter(op, report).map_err(EnterError::from)))
131    }
132}
133
134impl<S> Domain<S>
135where
136    S: storage::Create,
137{
138    pub(super) fn try_create<C, O, Done>(
139        self,
140        ctx: C,
141        op: O,
142        report: impl recovery::Observe,
143        finish: impl for<'owner> FnOnce(
144            Result<O::Output, EnterError<'owner, S::Error, O, O::Output, C::Shutdown>>,
145        ) -> Done,
146    ) -> Done
147    where
148        C: executor::Build,
149        O: executor::Op<S, C::Shutdown>,
150    {
151        let mut attempt = creation::Attempt::new();
152        let exec = match ctx.try_build(&mut attempt, self.layout) {
153            Ok(exec) => exec.with_plan(self.storage),
154            Err(cause) => {
155                return finish(Err(EnterError::Runtime(domain::Rejected {
156                    cause,
157                    operation: op,
158                })));
159            }
160        };
161        exec.run(|run| finish(run.try_scope(op, report).map_err(EnterError::from)))
162    }
163}