1#[derive(Clone, Debug, Default)]
7pub struct Window<'a> {
8 pub valid_from: Option<&'a str>,
9 pub valid_until: Option<&'a str>,
10 pub expires_at: Option<&'a str>,
11 pub not_before: Option<&'a str>,
12 pub not_after: Option<&'a str>,
13}
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub enum ExpirationVerdict<'a> {
17 Ok,
18 NotYetValid { threshold: &'a str },
19 Expired { threshold: &'a str },
20}
21
22impl<'a> ExpirationVerdict<'a> {
23 pub fn ok(&self) -> bool {
24 matches!(self, ExpirationVerdict::Ok)
25 }
26}
27
28pub fn check_window<'a>(window: &'a Window<'a>, now: &str) -> ExpirationVerdict<'a> {
29 let start = window.valid_from.or(window.not_before);
30 let end = window
31 .valid_until
32 .or(window.expires_at)
33 .or(window.not_after);
34 if let Some(s) = start {
35 if now < s {
36 return ExpirationVerdict::NotYetValid { threshold: s };
37 }
38 }
39 if let Some(e) = end {
40 if now > e {
41 return ExpirationVerdict::Expired { threshold: e };
42 }
43 }
44 ExpirationVerdict::Ok
45}
46
47pub fn is_within_window(window: &Window<'_>, now: &str) -> bool {
48 matches!(check_window(window, now), ExpirationVerdict::Ok)
49}
50
51pub fn is_expired(window: &Window<'_>, now: &str) -> bool {
52 matches!(check_window(window, now), ExpirationVerdict::Expired { .. })
53}