1use crate::{
3 Child, ChildPulse, Execution, NodeId, Observer, Outcome, Phase, PhaseSpec, PlanError, Pulse,
4 Report, Reporter, SharedPulse, Stop, StopReason, Total, sync::OwnerCell,
5};
6use alloc::{boxed::Box, sync::Arc, vec::Vec};
7use core::{
8 fmt,
9 sync::atomic::{AtomicBool, AtomicU8, Ordering},
10};
11
12#[must_use = "finish the root after its work joins; dropping it unfinished records Abandoned"]
16pub struct PulseTree {
17 node: TreePulse<Arc<dyn Stop>>,
18}
19impl PulseTree {
20 pub fn new(phase: Phase, stop: impl Stop + 'static) -> Self {
22 Self {
23 node: TreePulse::new(phase, Arc::new(stop) as Arc<dyn Stop>),
24 }
25 }
26 pub fn observer(&self) -> Observer {
28 self.node.observer()
29 }
30 pub fn id(&self) -> NodeId {
32 self.node.state.observer.id()
33 }
34 pub fn finish(self, outcome: Outcome) -> Result<(), PlanError> {
36 self.node.finish(outcome)
37 }
38}
39impl fmt::Debug for PulseTree {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 f.debug_struct("PulseTree")
42 .field("root", &self.id())
43 .finish()
44 }
45}
46const UNPLANNED: u8 = 0;
47const COUNTING: u8 = 1;
48const SPLIT: u8 = 2;
49const FINISHED: u8 = 3;
50
51pub(crate) trait Policy: Clone + Send + Sync + 'static {
54 #[track_caller]
55 fn check(&self, phase: &Observer) -> Result<(), StopReason>;
56 fn may_stop(&self) -> bool;
57}
58impl Policy for Arc<dyn Stop> {
59 #[track_caller]
60 fn check(&self, _phase: &Observer) -> Result<(), StopReason> {
61 Stop::check(self)
62 }
63 fn may_stop(&self) -> bool {
64 Stop::may_stop(self)
65 }
66}
67
68struct State<S: Policy> {
70 owner: OwnerCell<Phase>,
71 reporter: Reporter,
72 observer: Observer,
73 stop: S,
74 activity: AtomicU8,
75 closed: AtomicBool,
76}
77pub(crate) struct TreePulse<S: Policy> {
78 state: Arc<State<S>>,
79}
80#[derive(Clone)]
81struct View<S: Policy> {
82 state: Arc<State<S>>,
83}
84impl<S: Policy> TreePulse<S> {
85 pub(crate) fn observer(&self) -> Observer {
86 self.state.observer.clone()
87 }
88 pub(crate) fn finish(self, outcome: Outcome) -> Result<(), PlanError> {
89 self.state.finish(outcome)
90 }
91 pub(crate) fn new(phase: Phase, stop: S) -> Self {
92 Self {
93 state: Arc::new(State {
94 reporter: phase.deferred_reporter(),
95 observer: phase.observer(),
96 owner: OwnerCell::new(phase),
97 stop,
98 activity: AtomicU8::new(UNPLANNED),
99 closed: AtomicBool::new(false),
100 }),
101 }
102 }
103}
104impl<S: Policy> State<S> {
105 fn complete(&self, outcome: Outcome) -> Result<(), PlanError> {
106 self.with_owner(|phase| phase.record_outcome(outcome))??;
107 self.activity.store(FINISHED, Ordering::Release);
108 Ok(())
109 }
110 fn start(&self) -> Result<(), PlanError> {
111 self.with_owner(Phase::start)?
112 }
113 fn set_total(&self, total: Total) -> Result<(), PlanError> {
114 self.with_owner(|p| p.set_total(total))?
115 }
116 fn share(self: &Arc<Self>) -> Result<SharedPulse, PlanError> {
117 Ok(SharedPulse::new(View {
118 state: Arc::clone(self),
119 }))
120 }
121
122 fn with_owner<R>(&self, f: impl FnOnce(&mut Phase) -> R) -> Result<R, PlanError> {
125 if self.closed.load(Ordering::Acquire) {
126 return Err(PlanError::Finished);
127 }
128 self.owner.with(f).ok_or(PlanError::Finished)
129 }
130 fn close(&self) {
131 self.closed.store(true, Ordering::Release);
132 self.activity.store(FINISHED, Ordering::Release);
133 drop(self.owner.take());
136 }
137 fn finish(&self, outcome: Outcome) -> Result<(), PlanError> {
138 let result = self.with_owner(|phase| phase.finish_with(outcome))?;
139 if result.is_ok() {
140 self.activity.store(FINISHED, Ordering::Release);
141 }
142 result
143 }
144 fn split(
145 &self,
146 execution: Execution,
147 parts: &[PhaseSpec<'_>],
148 ) -> Result<Vec<Child<'static>>, PlanError> {
149 PhaseSpec::validate_split(parts)?;
150 self.activity
151 .compare_exchange(UNPLANNED, SPLIT, Ordering::AcqRel, Ordering::Acquire)
152 .map_err(|s| {
153 if s == FINISHED {
154 PlanError::Finished
155 } else {
156 PlanError::AlreadyInUse
157 }
158 })?;
159 let mut children = Vec::with_capacity(parts.len());
160 let split = self.with_owner(|phase| {
161 phase.split_each(execution, parts, &mut |phase| {
162 children.push(Child::new(TreePulse::new(phase, self.stop.clone())));
163 })
164 });
165 match split {
166 Ok(Ok(())) => Ok(children),
167 Ok(Err(error)) | Err(error) => {
168 let _ = self.activity.compare_exchange(
170 SPLIT,
171 UNPLANNED,
172 Ordering::AcqRel,
173 Ordering::Acquire,
174 );
175 Err(error)
176 }
177 }
178 }
179}
180impl<S: Policy> Stop for State<S> {
181 #[track_caller]
182 fn check(&self) -> Result<(), StopReason> {
183 self.stop.check(&self.observer)
184 }
185 fn may_stop(&self) -> bool {
186 self.stop.may_stop()
187 }
188}
189impl<S: Policy> Report for State<S> {
190 #[track_caller]
191 fn advance(&self, n: u64) {
192 if n == 0 {
193 return;
194 }
195 if self.activity.load(Ordering::Acquire) == COUNTING
198 || matches!(
199 self.activity.compare_exchange(
200 UNPLANNED,
201 COUNTING,
202 Ordering::AcqRel,
203 Ordering::Acquire
204 ),
205 Ok(_) | Err(COUNTING) | Err(SPLIT)
206 )
207 {
208 self.reporter.advance(n);
209 }
210 }
211 fn may_report(&self) -> bool {
212 self.activity.load(Ordering::Relaxed) != FINISHED && self.reporter.may_report()
213 }
214}
215impl<S: Policy> Drop for TreePulse<S> {
216 fn drop(&mut self) {
217 self.state.close();
218 }
219}
220impl<S: Policy> ChildPulse for TreePulse<S> {
221 fn complete_inferred(self: Box<Self>, outcome: Outcome) {
222 let _ = self
223 .state
224 .with_owner(|phase| phase.complete_inferred(outcome));
225 }
226 fn complete_as(self: Box<Self>, outcome: Outcome) {
227 let _ = self.state.complete(outcome);
228 }
229 fn finish(self: Box<Self>, outcome: Outcome) -> Result<(), PlanError> {
230 self.state.finish(outcome)
231 }
232}
233
234impl<S: Policy> how_far::Complete for TreePulse<S> {
235 fn complete_as(self, outcome: Outcome) {
236 let _ = self.state.complete(outcome);
237 }
238}
239
240impl how_far::Complete for PulseTree {
241 fn complete_as(self, outcome: Outcome) {
242 let _ = self.node.state.complete(outcome);
243 }
244}
245macro_rules! pulse_view {
247 ([$($generic:ident : $bound:path)?] $ty:ty, $field:ident $(, #[$hint:meta])?) => {
248 impl$(<$generic: $bound>)? Stop for $ty {
249 $(#[$hint])?
250 #[track_caller]
251 fn check(&self) -> Result<(), StopReason> {
252 self.$field.check()
253 }
254 fn may_stop(&self) -> bool {
255 self.$field.may_stop()
256 }
257 }
258 impl$(<$generic: $bound>)? Report for $ty {
259 $(#[$hint])?
260 #[track_caller]
261 fn advance(&self, n: u64) {
262 self.$field.advance(n)
263 }
264 fn may_report(&self) -> bool {
265 self.$field.may_report()
266 }
267 }
268 impl$(<$generic: $bound>)? Pulse for $ty {
269 fn split(
270 &self,
271 e: Execution,
272 parts: &[PhaseSpec<'_>],
273 ) -> Result<Vec<Child<'_>>, PlanError> {
274 self.$field.split(e, parts)
275 }
276 fn start(&self) -> Result<(), PlanError> {
277 self.$field.start()
278 }
279 fn set_total(&self, total: Total) -> Result<(), PlanError> {
280 self.$field.set_total(total)
281 }
282 fn share(&self) -> Result<SharedPulse, PlanError> {
283 self.$field.share()
284 }
285 }
286 };
287}
288pulse_view!([S: Policy] TreePulse<S>, state, #[inline]);
289pulse_view!([S: Policy] View<S>, state, #[inline]);
290pulse_view!([] PulseTree, node);