dope_core/driver/schedule/clock/
mod.rs1use std::{borrow, cell, cmp, marker, mem, ops, time};
4
5use o3::base::marker::ThreadBound;
6
7use crate::driver;
8
9mod range;
10pub mod timer;
11#[doc(hidden)]
12pub mod watchdog;
13
14pub use range::Range;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17#[repr(C)]
18struct Point<'d> {
19 at: time::Instant,
20 driver: (driver::Invariant<'d>, ThreadBound),
21}
22impl PartialOrd for Point<'_> {
23 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
24 Some(self.cmp(other))
25 }
26}
27impl Ord for Point<'_> {
28 fn cmp(&self, other: &Self) -> cmp::Ordering {
29 self.at.cmp(&other.at)
30 }
31}
32#[derive(Clone, Copy)]
34#[repr(transparent)]
35pub struct Clock<'turn, 'd> {
36 source: &'turn cell::Cell<time::Instant>,
37 driver: (driver::Invariant<'d>, ThreadBound),
38}
39#[derive(Clone, Copy)]
42pub struct Scope<'d> {
43 proof: (driver::Invariant<'d>, ThreadBound),
44}
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47#[repr(transparent)]
48pub struct Origin(time::Instant);
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
56#[repr(transparent)]
57pub struct Moment<'d>(Point<'d>);
58#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
61#[repr(transparent)]
62pub struct Deadline<'d>(Point<'d>);
63#[repr(transparent)]
66pub struct Bound<'d, T> {
67 inner: T,
68 driver: (driver::Invariant<'d>, ThreadBound),
69}
70#[repr(C)]
72pub struct At<'d, A> {
73 access: A,
74 now: Moment<'d>,
75}
76
77#[derive(Clone, Copy)]
79#[repr(transparent)]
80pub struct Sample(time::Instant);
81
82impl Sample {
83 pub const fn new(now: time::Instant) -> Self {
85 Self(now)
86 }
87
88 pub(in crate::driver) const fn into_raw(self) -> time::Instant {
89 self.0
90 }
91}
92
93impl Scope<'_> {
94 pub fn run<R>(run: impl for<'d> FnOnce(Scope<'d>) -> R) -> R {
96 run(Scope::new())
97 }
98}
99
100impl<'d> Scope<'d> {
101 const fn new() -> Self {
102 Self {
103 proof: (driver::Invariant(marker::PhantomData), ThreadBound::NEW),
104 }
105 }
106
107 pub fn now(self) -> Moment<'d> {
108 Moment::new(time::Instant::now(), self.proof)
109 }
110}
111
112impl Origin {
113 pub fn elapsed(self) -> time::Duration {
114 self.0.elapsed()
115 }
116}
117
118impl<'d> Point<'d> {
119 const fn new(at: time::Instant, driver: (driver::Invariant<'d>, ThreadBound)) -> Self {
120 Self { at, driver }
121 }
122
123 const fn at(self, at: time::Instant) -> Self {
124 Self::new(at, self.driver)
125 }
126
127 const fn get(self) -> time::Instant {
128 self.at
129 }
130
131 fn try_add<D: Copy + borrow::Borrow<time::Duration>>(
132 self,
133 duration: D,
134 ) -> Result<Self, Range<D>> {
135 match self.at.checked_add(*duration.borrow()) {
136 Some(at) => Ok(self.at(at)),
137 None => Err(Range::new(Origin(self.at), duration)),
138 }
139 }
140
141 fn clamp_add<D: Copy + borrow::Borrow<time::Duration>>(self, duration: D) -> Self {
142 match self.try_add(duration) {
143 Ok(point) => point,
144 Err(range) => self.at(range.furthest()),
145 }
146 }
147}
148
149impl<'turn, 'd> Clock<'turn, 'd> {
150 pub(in crate::driver) const fn new(
151 source: &'turn cell::Cell<time::Instant>,
152 driver: driver::Invariant<'d>,
153 ) -> Self {
154 Self {
155 source,
156 driver: (driver, ThreadBound::NEW),
157 }
158 }
159
160 pub fn now(self) -> Moment<'d> {
162 Moment::new(self.source.get(), self.driver)
163 }
164
165 pub fn attach<T>(self, build: impl FnOnce(time::Instant) -> T) -> Bound<'d, T> {
167 Bound::new(build(self.source.get()), self.driver)
168 }
169
170 pub fn try_attach<T, E>(
172 self,
173 build: impl FnOnce(time::Instant) -> Result<T, E>,
174 ) -> Result<Bound<'d, T>, E> {
175 build(self.source.get()).map(|inner| Bound::new(inner, self.driver))
176 }
177
178 pub fn deadline_at(self, at: time::Instant) -> Deadline<'d> {
180 Deadline(Point::new(at, self.driver))
181 }
182
183 pub fn at<A>(self, access: A) -> At<'d, A> {
185 At {
186 access,
187 now: self.now(),
188 }
189 }
190}
191
192impl<'d, T> Bound<'d, T> {
193 const fn new(inner: T, driver: (driver::Invariant<'d>, ThreadBound)) -> Self {
194 Self { inner, driver }
195 }
196
197 pub fn map<U>(self, map: impl FnOnce(T) -> U) -> Bound<'d, U> {
198 Bound::new(map(self.inner), self.driver)
199 }
200}
201
202impl<T> ops::Deref for Bound<'_, T> {
203 type Target = T;
204
205 fn deref(&self) -> &Self::Target {
206 &self.inner
207 }
208}
209
210impl<T> ops::DerefMut for Bound<'_, T> {
211 fn deref_mut(&mut self) -> &mut Self::Target {
212 &mut self.inner
213 }
214}
215
216impl<'d, A> At<'d, A> {
217 pub fn apply<R>(self, apply: impl FnOnce(A, time::Instant) -> R) -> R {
218 apply(self.access, self.now.0.get())
219 }
220
221 pub fn deadline(
222 self,
223 project: impl FnOnce(A, time::Instant) -> Option<time::Instant>,
224 ) -> Option<Deadline<'d>> {
225 project(self.access, self.now.0.get()).map(|at| Deadline(self.now.0.at(at)))
226 }
227}
228
229impl<'d, T: ?Sized> At<'d, &mut T> {
230 pub fn apply_mut<R>(&mut self, apply: impl FnOnce(&mut T, Moment<'d>) -> R) -> R {
234 apply(&mut *self.access, self.now)
235 }
236}
237
238impl<'d> Moment<'d> {
239 const fn new(at: time::Instant, driver: (driver::Invariant<'d>, ThreadBound)) -> Self {
240 Self(Point::new(at, driver))
241 }
242
243 pub const fn retain(self) -> Origin {
245 Origin(self.0.get())
246 }
247
248 pub fn try_add<D: Copy + borrow::Borrow<time::Duration>>(
249 self,
250 duration: D,
251 ) -> Result<Deadline<'d>, Range<D>> {
252 Ok(Deadline(self.0.try_add(duration)?))
253 }
254
255 pub fn clamp_add<D: Copy + borrow::Borrow<time::Duration>>(self, duration: D) -> Deadline<'d> {
257 Deadline(self.0.clamp_add(duration))
258 }
259
260 pub fn at<A>(self, access: A) -> At<'d, A> {
262 At { access, now: self }
263 }
264
265 pub fn moment_at(self, at: time::Instant) -> Self {
266 Self(self.0.at(at))
267 }
268
269 pub fn deadline_at(self, at: time::Instant) -> Deadline<'d> {
270 Deadline(self.0.at(at))
271 }
272
273 pub fn since(self, earlier: Self) -> time::Duration {
274 self.0.get().duration_since(earlier.0.get())
275 }
276
277 pub fn clamp_since(self, earlier: Self) -> time::Duration {
278 self.0.get().saturating_duration_since(earlier.0.get())
279 }
280
281 pub fn try_since(self, earlier: Self) -> Option<time::Duration> {
282 self.0.get().checked_duration_since(earlier.0.get())
283 }
284
285 pub fn past_due(self, earlier: Deadline<'d>) -> time::Duration {
286 self.0.get().duration_since(earlier.0.get())
287 }
288
289 pub const fn into_raw(self) -> time::Instant {
291 self.0.get()
292 }
293}
294
295impl<'d> Deadline<'d> {
296 pub fn try_add<D: Copy + borrow::Borrow<time::Duration>>(
297 self,
298 duration: D,
299 ) -> Result<Self, Range<D>> {
300 Ok(Self(self.0.try_add(duration)?))
301 }
302
303 pub fn clamp_add<D: Copy + borrow::Borrow<time::Duration>>(self, duration: D) -> Self {
305 Self(self.0.clamp_add(duration))
306 }
307
308 pub fn checked_sub(self, duration: time::Duration) -> Option<Self> {
309 self.0
310 .get()
311 .checked_sub(duration)
312 .map(|at| Self(self.0.at(at)))
313 }
314
315 pub fn is_due(self, now: Moment<'d>) -> bool {
316 self.0.get() <= now.0.get()
317 }
318
319 pub fn try_left(self, now: Moment<'d>) -> Option<time::Duration> {
320 self.0.get().checked_duration_since(now.0.get())
321 }
322
323 pub const fn into_raw(self) -> time::Instant {
325 self.0.get()
326 }
327}
328
329impl From<Moment<'_>> for time::Instant {
330 fn from(moment: Moment<'_>) -> Self {
331 moment.0.at
332 }
333}
334
335impl<'d> From<Moment<'d>> for Deadline<'d> {
336 fn from(moment: Moment<'d>) -> Self {
337 Self(moment.0)
338 }
339}
340
341impl<'d> PartialEq<Moment<'d>> for Deadline<'d> {
342 fn eq(&self, other: &Moment<'d>) -> bool {
343 self.0.get() == other.0.get()
344 }
345}
346
347impl<'d> PartialOrd<Moment<'d>> for Deadline<'d> {
348 fn partial_cmp(&self, other: &Moment<'d>) -> Option<cmp::Ordering> {
349 self.0.get().partial_cmp(&other.0.get())
350 }
351}
352
353impl<'d> PartialEq<Deadline<'d>> for Moment<'d> {
354 fn eq(&self, other: &Deadline<'d>) -> bool {
355 self.0.get() == other.0.get()
356 }
357}
358
359impl<'d> PartialOrd<Deadline<'d>> for Moment<'d> {
360 fn partial_cmp(&self, other: &Deadline<'d>) -> Option<cmp::Ordering> {
361 self.0.get().partial_cmp(&other.0.get())
362 }
363}
364
365const _: () = {
366 assert!(mem::size_of::<Scope<'static>>() == 0);
367 assert!(mem::size_of::<Origin>() == mem::size_of::<time::Instant>());
368 assert!(mem::align_of::<Origin>() == mem::align_of::<time::Instant>());
369 assert!(!mem::needs_drop::<Origin>());
370 assert!(mem::size_of::<Clock<'static, 'static>>() == mem::size_of::<usize>());
371 assert!(mem::align_of::<Clock<'static, 'static>>() == mem::align_of::<usize>());
372 assert!(mem::size_of::<Moment<'static>>() == mem::size_of::<time::Instant>());
373 assert!(mem::align_of::<Moment<'static>>() == mem::align_of::<time::Instant>());
374 assert!(mem::size_of::<Deadline<'static>>() == mem::size_of::<time::Instant>());
375 assert!(mem::align_of::<Deadline<'static>>() == mem::align_of::<time::Instant>());
376 assert!(!mem::needs_drop::<Moment<'static>>());
377 assert!(!mem::needs_drop::<Deadline<'static>>());
378 assert!(
379 mem::size_of::<At<'static, &'static mut ()>>()
380 == mem::size_of::<&mut ()>() + mem::size_of::<Moment<'static>>()
381 );
382 assert!(mem::align_of::<At<'static, &'static mut ()>>() == mem::align_of::<time::Instant>());
383 assert!(!mem::needs_drop::<At<'static, &'static mut ()>>());
384 assert!(mem::size_of::<Bound<'static, time::Instant>>() == mem::size_of::<time::Instant>());
385 assert!(mem::align_of::<Bound<'static, time::Instant>>() == mem::align_of::<time::Instant>());
386 assert!(mem::size_of::<Sample>() == mem::size_of::<time::Instant>());
387};