all_is_cubes_base/
time.rs1use core::cmp::Ordering;
2use core::fmt;
3use core::ops;
4
5use crate::util::ConciseDebug;
6use manyfmt::Refmt as _;
7
8#[doc(no_inline)]
11pub use bevy_platform::time::Instant;
12#[doc(no_inline)]
13pub use core::time::Duration;
14
15#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
19#[non_exhaustive]
20pub enum Deadline {
21 Asap,
25 At(Instant),
27 Whenever,
33}
34
35impl Deadline {
36 #[inline]
44 pub fn remaining_since(&self, start: Instant) -> Option<Duration> {
45 match self {
46 Deadline::Asap => Some(Duration::ZERO),
47 Deadline::At(deadline) => Some(deadline.saturating_duration_since(start)),
48 Deadline::Whenever => None,
49 }
50 }
51}
52
53impl ops::Add<Duration> for Deadline {
54 type Output = Self;
55 #[inline]
56 fn add(self, rhs: Duration) -> Self::Output {
57 match self {
58 Deadline::Asap => Deadline::Asap,
59 Deadline::At(i) => Deadline::At(i + rhs),
60 Deadline::Whenever => Deadline::Whenever,
61 }
62 }
63}
64impl ops::Sub<Duration> for Deadline {
65 type Output = Self;
66 #[inline]
67 fn sub(self, rhs: Duration) -> Self::Output {
68 match self {
69 Deadline::Asap => Deadline::Asap,
70 #[allow(clippy::unchecked_time_subtraction, reason = "TODO: can we do better?")]
71 Deadline::At(i) => Deadline::At(i - rhs),
72 Deadline::Whenever => Deadline::Whenever,
73 }
74 }
75}
76
77impl PartialEq<Instant> for Deadline {
79 #[mutants::skip] #[inline]
81 fn eq(&self, other: &Instant) -> bool {
82 self.partial_cmp(other) == Some(Ordering::Equal)
83 }
84}
85impl PartialEq<Deadline> for Instant {
86 #[mutants::skip] #[inline]
88 fn eq(&self, other: &Deadline) -> bool {
89 other.eq(self)
90 }
91}
92impl PartialOrd<Instant> for Deadline {
93 #[inline]
94 fn partial_cmp(&self, other: &Instant) -> Option<Ordering> {
95 Some(match self {
96 Deadline::Asap => Ordering::Less,
97 Deadline::At(i) => i.cmp(other),
98 Deadline::Whenever => Ordering::Greater,
99 })
100 }
101}
102impl PartialOrd<Deadline> for Instant {
103 #[inline]
104 fn partial_cmp(&self, other: &Deadline) -> Option<Ordering> {
105 other.partial_cmp(self).map(Ordering::reverse)
106 }
107}
108
109impl From<Instant> for Deadline {
110 #[inline]
111 fn from(value: Instant) -> Self {
112 Self::At(value)
113 }
114}
115
116#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
126#[non_exhaustive]
127#[expect(clippy::module_name_repetitions, reason = "TODO: find a better name")]
128pub struct TimeStats {
129 pub count: usize,
131 pub sum: Duration,
133 pub min: Option<Duration>,
135 pub max: Duration,
137}
138
139impl TimeStats {
140 #[inline]
144 pub const fn one(duration: Duration) -> Self {
145 Self {
146 count: 1,
147 sum: duration,
148 min: Some(duration),
149 max: duration,
150 }
151 }
152
153 #[doc(hidden)] #[inline]
159 pub fn record_consecutive_interval(
160 &mut self,
161 last_marked_instant: &mut Instant,
162 now: Instant,
163 ) -> Duration {
164 let previous = *last_marked_instant;
165 *last_marked_instant = now;
166
167 let duration = now.saturating_duration_since(previous);
168 *self += Self::one(duration);
169 duration
170 }
171}
172
173impl ops::AddAssign for TimeStats {
174 #[inline]
175 fn add_assign(&mut self, rhs: Self) {
176 *self = TimeStats {
177 count: self.count + rhs.count,
178 sum: self.sum + rhs.sum,
179 min: self.min.map_or(rhs.min, |value| Some(value.min(rhs.min?))),
180 max: self.max.max(rhs.max),
181 };
182 }
183}
184
185impl fmt::Display for TimeStats {
186 #[allow(clippy::missing_inline_in_public_items)]
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 let max = self.max.refmt(&ConciseDebug);
189 let count = self.count;
190 let sum = self.sum.refmt(&ConciseDebug);
191 match self.min {
192 None => write!(f, "(-------- .. {max}) for {count:3}, total {sum}"),
193 Some(min) => {
194 let min = min.refmt(&ConciseDebug);
195 write!(f, "({min} .. {max}) for {count:3}, total {sum}")
196 }
197 }
198 }
199}
200
201#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn deadline_ordering() {
209 let i = Instant::now();
210 let mut deadlines = [
211 Deadline::At(i + Duration::from_secs(1)),
212 Deadline::Asap,
213 Deadline::Whenever,
214 Deadline::At(i),
215 ];
216 deadlines.sort();
217 assert_eq!(
218 deadlines,
219 [
220 Deadline::Asap,
221 Deadline::At(i),
222 Deadline::At(i + Duration::from_secs(1)),
223 Deadline::Whenever,
224 ]
225 );
226 }
227}