1use std::time::{Duration, Instant};
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct Deadline {
10 instant: Instant,
11}
12
13impl Deadline {
14 #[must_use]
16 pub fn after(duration: Duration) -> Self {
17 Self {
18 instant: Instant::now() + duration,
19 }
20 }
21
22 #[must_use]
24 pub const fn at(instant: Instant) -> Self {
25 Self { instant }
26 }
27
28 #[must_use]
30 pub fn is_expired(&self) -> bool {
31 Instant::now() >= self.instant
32 }
33
34 #[must_use]
36 pub fn remaining(&self) -> Duration {
37 self.instant.saturating_duration_since(Instant::now())
38 }
39
40 #[must_use]
42 pub const fn instant(&self) -> Instant {
43 self.instant
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
49pub struct DurationBudget {
50 pub millis: u64,
52}
53
54impl DurationBudget {
55 #[must_use]
57 pub const fn from_millis(millis: u64) -> Self {
58 Self { millis }
59 }
60
61 #[must_use]
63 pub const fn as_duration(self) -> Duration {
64 Duration::from_millis(self.millis)
65 }
66
67 #[must_use]
69 pub fn to_deadline(self) -> Deadline {
70 Deadline::after(self.as_duration())
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn expired_zero() {
80 let d = Deadline::after(Duration::ZERO);
81 assert!(d.remaining().is_zero() || d.is_expired());
82 }
83}