1use bevy_platform::time::Instant;
2#[cfg(feature = "bevy_reflect")]
3use bevy_reflect::{std_traits::ReflectDefault, Reflect};
4use core::time::Duration;
5
6use crate::time::Time;
7
8#[derive(Debug, Copy, Clone)]
44#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Clone, Default))]
45pub struct Real {
46 startup: Instant,
47 first_update: Option<Instant>,
48 last_update: Option<Instant>,
49}
50
51impl Default for Real {
52 fn default() -> Self {
53 Self {
54 startup: Instant::now(),
55 first_update: None,
56 last_update: None,
57 }
58 }
59}
60
61impl Time<Real> {
62 pub fn new(startup: Instant) -> Self {
65 Self::new_with(Real {
66 startup,
67 ..Default::default()
68 })
69 }
70
71 pub fn update(&mut self) {
77 let instant = Instant::now();
78 self.update_with_instant(instant);
79 }
80
81 pub fn update_with_duration(&mut self, duration: Duration) {
89 let last_update = self.context().last_update.unwrap_or(self.context().startup);
90 self.update_with_instant(last_update + duration);
91 }
92
93 pub fn update_with_instant(&mut self, instant: Instant) {
100 let Some(last_update) = self.context().last_update else {
101 let context = self.context_mut();
102 context.first_update = Some(instant);
103 context.last_update = Some(instant);
104 return;
105 };
106 let delta = instant - last_update;
107 self.advance_by(delta);
108 self.context_mut().last_update = Some(instant);
109 }
110
111 #[inline]
115 pub fn startup(&self) -> Instant {
116 self.context().startup
117 }
118
119 #[inline]
124 pub fn first_update(&self) -> Option<Instant> {
125 self.context().first_update
126 }
127
128 #[inline]
133 pub fn last_update(&self) -> Option<Instant> {
134 self.context().last_update
135 }
136}
137
138#[cfg(test)]
139mod test {
140 use super::*;
141
142 fn wait() {
150 let start = Instant::now();
151 while Instant::now() <= start {}
152 }
153
154 #[test]
155 fn test_update() {
156 let startup = Instant::now();
157 let mut time = Time::<Real>::new(startup);
158
159 assert_eq!(time.startup(), startup);
160 assert_eq!(time.first_update(), None);
161 assert_eq!(time.last_update(), None);
162 assert_eq!(time.delta(), Duration::ZERO);
163 assert_eq!(time.elapsed(), Duration::ZERO);
164
165 wait();
166 time.update();
167
168 assert_ne!(time.first_update(), None);
169 assert_ne!(time.last_update(), None);
170 assert_eq!(time.delta(), Duration::ZERO);
171 assert_eq!(time.elapsed(), Duration::ZERO);
172
173 wait();
174 time.update();
175
176 assert_ne!(time.first_update(), None);
177 assert_ne!(time.last_update(), None);
178 assert_ne!(time.last_update(), time.first_update());
179 assert_ne!(time.delta(), Duration::ZERO);
180 assert_eq!(time.elapsed(), time.delta());
181
182 wait();
183 let prev_elapsed = time.elapsed();
184 time.update();
185
186 assert_ne!(time.delta(), Duration::ZERO);
187 assert_eq!(time.elapsed(), prev_elapsed + time.delta());
188 }
189
190 #[test]
191 fn test_update_with_instant() {
192 let startup = Instant::now();
193 let mut time = Time::<Real>::new(startup);
194
195 wait();
196 let first_update = Instant::now();
197 time.update_with_instant(first_update);
198
199 assert_eq!(time.startup(), startup);
200 assert_eq!(time.first_update(), Some(first_update));
201 assert_eq!(time.last_update(), Some(first_update));
202 assert_eq!(time.delta(), Duration::ZERO);
203 assert_eq!(time.elapsed(), Duration::ZERO);
204
205 wait();
206 let second_update = Instant::now();
207 time.update_with_instant(second_update);
208
209 assert_eq!(time.first_update(), Some(first_update));
210 assert_eq!(time.last_update(), Some(second_update));
211 assert_eq!(time.delta(), second_update - first_update);
212 assert_eq!(time.elapsed(), second_update - first_update);
213
214 wait();
215 let third_update = Instant::now();
216 time.update_with_instant(third_update);
217
218 assert_eq!(time.first_update(), Some(first_update));
219 assert_eq!(time.last_update(), Some(third_update));
220 assert_eq!(time.delta(), third_update - second_update);
221 assert_eq!(time.elapsed(), third_update - first_update);
222 }
223
224 #[test]
225 fn test_update_with_duration() {
226 let startup = Instant::now();
227 let mut time = Time::<Real>::new(startup);
228
229 time.update_with_duration(Duration::from_secs(1));
230
231 assert_eq!(time.startup(), startup);
232 assert_eq!(time.first_update(), Some(startup + Duration::from_secs(1)));
233 assert_eq!(time.last_update(), Some(startup + Duration::from_secs(1)));
234 assert_eq!(time.delta(), Duration::ZERO);
235 assert_eq!(time.elapsed(), Duration::ZERO);
236
237 time.update_with_duration(Duration::from_secs(1));
238
239 assert_eq!(time.first_update(), Some(startup + Duration::from_secs(1)));
240 assert_eq!(time.last_update(), Some(startup + Duration::from_secs(2)));
241 assert_eq!(time.delta(), Duration::from_secs(1));
242 assert_eq!(time.elapsed(), Duration::from_secs(1));
243
244 time.update_with_duration(Duration::from_secs(1));
245
246 assert_eq!(time.first_update(), Some(startup + Duration::from_secs(1)));
247 assert_eq!(time.last_update(), Some(startup + Duration::from_secs(3)));
248 assert_eq!(time.delta(), Duration::from_secs(1));
249 assert_eq!(time.elapsed(), Duration::from_secs(2));
250 }
251}