architect_api/utils/
half_open_range.rs1use chrono::{DateTime, Utc};
2#[cfg(feature = "netidx")]
3use derive::FromValue;
4#[cfg(feature = "netidx")]
5use netidx_derive::Pack;
6use schemars::JsonSchema;
7use serde_derive::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
10#[cfg_attr(feature = "netidx", derive(Pack, FromValue))]
11pub struct HalfOpenRange<T: 'static> {
12 pub from_inclusive: T,
13 pub to_exclusive: T,
14}
15
16impl<T> HalfOpenRange<T> {
17 pub fn new(from_inclusive: T, to_exclusive: T) -> Self {
18 Self { from_inclusive, to_exclusive }
19 }
20}
21
22impl<T: Copy> HalfOpenRange<T> {
23 pub fn infinitesimal(at: T) -> Self {
24 Self { from_inclusive: at, to_exclusive: at }
25 }
26}
27
28impl<T: Ord> HalfOpenRange<T> {
29 pub fn contains(&self, x: T) -> bool {
30 self.from_inclusive <= x && x < self.to_exclusive
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
35#[cfg_attr(feature = "netidx", derive(Pack, FromValue))]
36pub enum ClampSign {
37 Forwards, Backwards, }
40
41impl HalfOpenRange<DateTime<Utc>> {
42 pub fn clamp(&self, max_width: chrono::Duration, sign: ClampSign) -> Self {
43 match sign {
44 ClampSign::Forwards => self.clamp_to(max_width),
45 ClampSign::Backwards => self.clamp_from(max_width),
46 }
47 }
48
49 fn clamp_from(&self, max_width: chrono::Duration) -> Self {
50 Self {
51 from_inclusive: std::cmp::max(
52 self.to_exclusive - max_width,
53 self.from_inclusive,
54 ),
55 ..*self
56 }
57 }
58
59 fn clamp_to(&self, max_width: chrono::Duration) -> Self {
60 Self {
61 to_exclusive: std::cmp::min(
62 self.from_inclusive + max_width,
63 self.to_exclusive,
64 ),
65 ..*self
66 }
67 }
68}
69
70impl HalfOpenRange<Option<DateTime<Utc>>> {
71 pub fn clamp(&self, max_width: chrono::Duration, sign: ClampSign) -> Self {
72 match sign {
73 ClampSign::Forwards => self.clamp_to(max_width),
74 ClampSign::Backwards => self.clamp_from(max_width),
75 }
76 }
77
78 fn clamp_from(&self, max_width: chrono::Duration) -> Self {
79 match (self.from_inclusive, self.to_exclusive) {
80 (Some(l), Some(r)) => {
81 Self { from_inclusive: Some(std::cmp::max(r - max_width, l)), ..*self }
82 }
83 _ => *self,
84 }
85 }
86
87 fn clamp_to(&self, max_width: chrono::Duration) -> Self {
88 match (self.from_inclusive, self.to_exclusive) {
89 (Some(l), Some(r)) => {
90 Self { to_exclusive: Some(std::cmp::min(l + max_width, r)), ..*self }
91 }
92 _ => *self,
93 }
94 }
95}