crux_time/protocol/
instant.rs1use std::time::SystemTime;
2
3use facet::Facet;
4use serde::{Deserialize, Serialize};
5
6const NANOS_PER_SEC: u32 = 1_000_000_000;
8
9#[derive(Facet, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct Instant {
16 pub(crate) seconds: u64,
17 pub(crate) nanos: u32,
18}
19
20impl Instant {
21 #[must_use]
29 pub fn new(seconds: u64, nanos: u32) -> Self {
30 assert!(
31 nanos < NANOS_PER_SEC,
32 "nanos must be less than {NANOS_PER_SEC}"
33 );
34 Self { seconds, nanos }
35 }
36}
37
38impl From<SystemTime> for Instant {
39 fn from(time: SystemTime) -> Self {
40 let duration = time
41 .duration_since(SystemTime::UNIX_EPOCH)
42 .expect("time must be after Unix epoch");
43 let seconds = duration.as_secs();
44 let nanos = duration.subsec_nanos();
45 Self { seconds, nanos }
46 }
47}
48
49impl From<Instant> for SystemTime {
50 fn from(time: Instant) -> Self {
51 Self::UNIX_EPOCH + std::time::Duration::new(time.seconds, time.nanos)
52 }
53}
54
55#[cfg(test)]
56mod test {
57 use super::*;
58
59 #[test]
60 fn new_instant() {
61 let instant = Instant::new(1_000_000_000, 10);
62 assert_eq!(instant.seconds, 1_000_000_000);
63 assert_eq!(instant.nanos, 10);
64 }
65
66 #[test]
67 #[should_panic = "nanos must be less than 1000000000"]
68 fn new_instant_invalid_nanos() {
69 let _ = Instant::new(1_000_000_000, 1_000_000_000);
70 }
71
72 #[test]
73 fn instant_to_std() {
74 let actual: SystemTime = Instant::new(1_000_000_000, 10).into();
75 let expected = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
76 assert_eq!(actual, expected);
77 }
78
79 #[test]
80 fn std_to_instant() {
81 let sys_time = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
82 let actual: Instant = sys_time.into();
83 let expected = Instant::new(1_000_000_000, 10);
84 assert_eq!(actual, expected);
85 }
86}