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}