nodedb_types/temporal/
interval.rs1use serde::{Deserialize, Serialize};
14
15pub const OPEN_UPPER: i64 = i64::MAX;
17
18#[derive(
23 Debug,
24 Clone,
25 Copy,
26 PartialEq,
27 Eq,
28 Hash,
29 Serialize,
30 Deserialize,
31 zerompk::ToMessagePack,
32 zerompk::FromMessagePack,
33)]
34pub struct BitemporalInterval {
35 pub valid_from_ms: i64,
36 pub valid_until_ms: i64,
37 pub system_from_ms: i64,
38 pub system_until_ms: i64,
39}
40
41impl BitemporalInterval {
42 pub const fn current(valid_from_ms: i64, system_from_ms: i64) -> Self {
44 Self {
45 valid_from_ms,
46 valid_until_ms: OPEN_UPPER,
47 system_from_ms,
48 system_until_ms: OPEN_UPPER,
49 }
50 }
51
52 pub const fn is_system_current(&self) -> bool {
55 self.system_until_ms == OPEN_UPPER
56 }
57
58 pub const fn is_valid_current(&self) -> bool {
61 self.valid_until_ms == OPEN_UPPER
62 }
63
64 pub const fn is_current(&self) -> bool {
66 self.is_system_current() && self.is_valid_current()
67 }
68
69 pub const fn contains_valid(&self, t: i64) -> bool {
71 t >= self.valid_from_ms && t < self.valid_until_ms
72 }
73
74 pub const fn contains_system(&self, t: i64) -> bool {
76 t >= self.system_from_ms && t < self.system_until_ms
77 }
78
79 pub const fn overlaps_valid(&self, from: i64, to: i64) -> bool {
81 self.valid_from_ms < to && from < self.valid_until_ms
82 }
83
84 pub const fn overlaps_system(&self, from: i64, to: i64) -> bool {
86 self.system_from_ms < to && from < self.system_until_ms
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn current_is_both_open() {
96 let i = BitemporalInterval::current(100, 200);
97 assert!(i.is_current());
98 assert!(i.is_valid_current());
99 assert!(i.is_system_current());
100 }
101
102 #[test]
103 fn closed_open_contains() {
104 let i = BitemporalInterval {
105 valid_from_ms: 10,
106 valid_until_ms: 20,
107 system_from_ms: 100,
108 system_until_ms: 200,
109 };
110 assert!(i.contains_valid(10));
111 assert!(i.contains_valid(19));
112 assert!(!i.contains_valid(20));
113 assert!(!i.contains_valid(9));
114 assert!(i.contains_system(150));
115 assert!(!i.contains_system(200));
116 }
117
118 #[test]
119 fn overlap_semantics() {
120 let i = BitemporalInterval {
121 valid_from_ms: 10,
122 valid_until_ms: 20,
123 system_from_ms: 100,
124 system_until_ms: 200,
125 };
126 assert!(i.overlaps_valid(15, 25));
127 assert!(i.overlaps_valid(5, 15));
128 assert!(!i.overlaps_valid(20, 30));
130 assert!(i.overlaps_valid(0, 11));
132 }
133
134 #[test]
135 fn open_upper_is_i64_max() {
136 assert_eq!(OPEN_UPPER, i64::MAX);
137 let i = BitemporalInterval::current(0, 0);
138 assert!(i.contains_valid(i64::MAX - 1));
139 assert!(!i.contains_valid(i64::MAX));
140 }
141}