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