signals_receipts/premade/receipts.rs
1use crate::SignalNumber;
2use core::{cmp::Ordering, mem, ops::ControlFlow};
3
4
5/// Representation of receipt of delivery of a signal, as given to delegates declared in uses of
6/// the [`premade`](crate::premade!) macro or delegates given to the premade
7/// [`consume_count_then_delegate`](crate::consume_count_then_delegate) helper (which is
8/// automatically used by the `premade` macro).
9///
10/// `B` is the type of the final value that the processing finishes with. `C` is the type of the
11/// state value that is passed in and out of all delegates during processing.
12#[non_exhaustive]
13#[must_use]
14#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
15pub struct Receipt<U, B = (), C = ()> {
16 /// Signal number that was received.
17 pub sig_num: SignalNumber,
18 /// Current count of how many times the signal designated by `sig_num` was received since
19 /// last time its consuming was run.
20 pub cur_count: U,
21 /// Control whether the processing of subsequent receipts will continue or finish after the
22 /// current delegate (which is processing this instance) returns.
23 ///
24 /// Initialized to `Continue` with the current state value, so that continuing is what
25 /// is done by default. Intended to be mutated to `Break` by a delegate that wants to cause
26 /// finishing.
27 ///
28 /// When `Continue`, the contained value can be used as a mutable state that is passed
29 /// to and returned from all delegates during processing.
30 pub flow: ControlFlow<B, C>,
31}
32
33
34impl<U, B, C> Receipt<U, B, C> {
35 const NOT_STATE_MSG: &'static str = "should be `ControlFlow::Continue` to get state";
36
37 /// Cause the processing to finish.
38 ///
39 /// Assigns `self.flow = ControlFlow::Break(B::default())`.
40 #[inline]
41 pub fn break_loop(&mut self)
42 where
43 B: Default,
44 {
45 self.break_loop_with(B::default());
46 }
47
48 /// Cause the processing to finish with the given value.
49 ///
50 /// Assigns `self.flow = ControlFlow::Break(val)`.
51 #[inline]
52 pub fn break_loop_with(&mut self, val: B) { self.flow = ControlFlow::Break(val); }
53
54 /// Return a reference to the state value (which is held in `self.flow`).
55 ///
56 /// # Panics
57 /// If `self.flow` is not `ControlFlow::Continue`. When a `Receipt` is given to a delegate,
58 /// it is guaranteed to hold `Continue`, and so this won't panic.
59 #[must_use]
60 #[inline]
61 pub fn get_state_ref(&self) -> &C {
62 match &self.flow {
63 ControlFlow::Continue(state) => state,
64 #[allow(clippy::panic)]
65 ControlFlow::Break(_) => panic!("{}", Self::NOT_STATE_MSG),
66 }
67 }
68
69 /// Like [`Self::get_state_ref`] but returns a mutable reference.
70 ///
71 /// # Panics
72 /// Same as `Self::get_state_ref`.
73 #[must_use]
74 #[inline]
75 pub fn get_state_mut(&mut self) -> &mut C {
76 match &mut self.flow {
77 ControlFlow::Continue(state) => state,
78 #[allow(clippy::panic)]
79 ControlFlow::Break(_) => panic!("{}", Self::NOT_STATE_MSG),
80 }
81 }
82
83 /// Cause the processing to continue with the given state value.
84 ///
85 /// Assigns `self.flow = ControlFlow::Continue(val)`.
86 #[inline]
87 pub fn set_state(&mut self, val: C) { self.flow = ControlFlow::Continue(val); }
88
89 /// Apply the given `updater` function to the state value as mutable, to update it.
90 ///
91 /// The `updater` can mutate or replace the value in-place.
92 ///
93 /// # Panics
94 /// Same as [`Self::get_state_mut`].
95 #[inline]
96 pub fn update_state<F: FnOnce(&mut C)>(&mut self, updater: F) {
97 updater(self.get_state_mut());
98 }
99
100 /// Replace the state with the given `val` and return the previous value.
101 ///
102 /// # Panics
103 /// Same as [`Self::get_state_mut`].
104 #[must_use]
105 #[inline]
106 pub fn replace_state(&mut self, val: C) -> C { mem::replace(self.get_state_mut(), val) }
107
108 /// Return the current state value and replace it with the default.
109 ///
110 /// # Panics
111 /// Same as [`Self::get_state_mut`].
112 #[must_use]
113 #[inline]
114 pub fn take_state(&mut self) -> C
115 where
116 C: Default,
117 {
118 mem::take(self.get_state_mut())
119 }
120}
121
122
123/// Manual impl because [`ControlFlow`] doesn't impl `PartialOrd`.
124impl<U: Ord, B: Ord, C: Ord> PartialOrd for Receipt<U, B, C> {
125 #[inline]
126 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
127}
128
129/// Manual impl because [`ControlFlow`] doesn't impl `Ord`.
130impl<U: Ord, B: Ord, C: Ord> Ord for Receipt<U, B, C> {
131 #[inline]
132 fn cmp(&self, other: &Self) -> Ordering {
133 match self.sig_num.cmp(&other.sig_num) {
134 Ordering::Equal => match self.cur_count.cmp(&other.cur_count) {
135 Ordering::Equal => match (&self.flow, &other.flow) {
136 (ControlFlow::Continue(c1), ControlFlow::Continue(c2)) => c1.cmp(c2),
137 (ControlFlow::Continue(_), ControlFlow::Break(_)) => Ordering::Less,
138 (ControlFlow::Break(_), ControlFlow::Continue(_)) => Ordering::Greater,
139 (ControlFlow::Break(b1), ControlFlow::Break(b2)) => b1.cmp(b2),
140 },
141 ord @ (Ordering::Less | Ordering::Greater) => ord,
142 },
143 ord @ (Ordering::Less | Ordering::Greater) => ord,
144 }
145 }
146}