async_time_mock_core/
instant.rs

1use crate::TimerRegistry;
2use std::ops::{Add, AddAssign, Sub, SubAssign};
3use std::time::Duration;
4
5#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
6pub struct Instant {
7	duration: Duration,
8	timer_registry_id: u64,
9}
10
11impl Instant {
12	pub(crate) const fn new(duration: Duration, timer_registry_id: u64) -> Self {
13		Self {
14			duration,
15			timer_registry_id,
16		}
17	}
18
19	pub(crate) const fn into_duration(self, timer_registry_id: u64) -> Duration {
20		if self.timer_registry_id != timer_registry_id {
21			panic!("Can't use Instants from one TimerRegistry in another TimerRegistry.");
22		}
23		self.duration
24	}
25
26	// std::time::Instant::now() isn't supported because it would require a TimerRegistry
27
28	/// Equivalent to [`std::time::Instant::duration_since`].
29	pub const fn duration_since(&self, earlier: Self) -> Duration {
30		self.assert_instances_are_compatible(&earlier);
31		self.duration.saturating_sub(earlier.duration)
32	}
33
34	/// Equivalent to [`std::time::Instant::checked_duration_since`].
35	pub const fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
36		self.assert_instances_are_compatible(&earlier);
37		self.duration.checked_sub(earlier.duration)
38	}
39
40	/// Equivalent to [`std::time::Instant::saturated_duration_since`].
41	pub const fn saturated_duration_since(&self, earlier: Self) -> Duration {
42		self.assert_instances_are_compatible(&earlier);
43		self.duration.saturating_sub(earlier.duration)
44	}
45
46	/// Similar to [`std::time::Instant::elapsed`], but needs a [`TimerRegistry`] to calculate the time that has passed.
47	///
48	/// # Panics
49	/// If the [`TimerRegistry`] passed in was different than the one this `Instant` was created with.
50	pub fn elapsed(&self, timer_registry: &TimerRegistry) -> Duration {
51		timer_registry.now().duration_since(*self)
52	}
53
54	/// Equivalent to [`std::time::Instant::checked_add`].
55	pub const fn checked_add(&self, duration: Duration) -> Option<Self> {
56		let timer_registry_id = self.timer_registry_id;
57		match self.duration.checked_add(duration) {
58			Some(duration) => Some(Self {
59				duration,
60				timer_registry_id,
61			}),
62			None => None,
63		}
64	}
65
66	/// Equivalent to [`std::time::Instant::checked_sub`].
67	pub const fn checked_sub(&self, duration: Duration) -> Option<Self> {
68		let timer_registry_id = self.timer_registry_id;
69		match self.duration.checked_sub(duration) {
70			Some(duration) => Some(Self {
71				duration,
72				timer_registry_id,
73			}),
74			None => None,
75		}
76	}
77
78	const fn assert_instances_are_compatible(&self, other: &Self) {
79		if self.timer_registry_id != other.timer_registry_id {
80			panic!("Operations between Instant's from different TimerRegistry instances are not supported.");
81		}
82	}
83}
84
85impl Add<Duration> for Instant {
86	type Output = Instant;
87
88	fn add(self, rhs: Duration) -> Self::Output {
89		Self {
90			duration: self.duration.add(rhs),
91			timer_registry_id: self.timer_registry_id,
92		}
93	}
94}
95
96impl AddAssign<Duration> for Instant {
97	fn add_assign(&mut self, rhs: Duration) {
98		self.duration.add_assign(rhs);
99	}
100}
101
102impl Sub<Duration> for Instant {
103	type Output = Instant;
104
105	fn sub(self, rhs: Duration) -> Self::Output {
106		Self {
107			duration: self.duration.sub(rhs),
108			timer_registry_id: self.timer_registry_id,
109		}
110	}
111}
112
113impl Sub<Instant> for Instant {
114	type Output = Duration;
115
116	fn sub(self, rhs: Instant) -> Self::Output {
117		self.assert_instances_are_compatible(&rhs);
118		self.duration.sub(rhs.duration)
119	}
120}
121
122impl SubAssign<Duration> for Instant {
123	fn sub_assign(&mut self, rhs: Duration) {
124		self.duration.sub_assign(rhs);
125	}
126}
127
128#[cfg(test)]
129mod test {
130	use super::*;
131	use std::time::Duration;
132
133	#[test]
134	#[should_panic]
135	fn should_not_allow_fetching_duration_from_incorrect_timer_registry() {
136		Instant::new(Duration::ZERO, 0).into_duration(1);
137	}
138}