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
11pub 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<O, Done>(
139 self,
140 op: O,
141 report: impl recovery::Observe,
142 finish: impl for<'owner> FnOnce(
143 Result<O::Output, EnterError<'owner, S::Error, O, O::Output>>,
144 ) -> Done,
145 ) -> Done
146 where
147 O: executor::Op<S, ()>,
148 {
149 let mut attempt = creation::Attempt::new();
150 let exec = match executor::Executor::new(&mut attempt, self.layout) {
151 Ok(exec) => exec.with_plan(self.storage),
152 Err(cause) => {
153 return finish(Err(EnterError::Runtime(domain::Rejected {
154 cause,
155 operation: op,
156 })));
157 }
158 };
159 exec.run(|run| finish(run.try_scope(op, report).map_err(EnterError::from)))
160 }
161}