saa_common/types/
expiration.rs

1use saa_schema::{saa_type};
2use saa_schema::strum_macros::Display;
3use std::cmp::Ordering;
4use std::ops::Add;
5use crate::AuthError;
6use super::timestamp::Timestamp;
7
8
9
10
11#[saa_type]
12#[derive(Display)]
13pub enum Expiration {
14    /// AtHeight will expire when `env.block.height` >= height
15    #[strum(to_string = "expiration height: {0}")]
16    AtHeight(u64),
17    /// AtTime will expire when `env.block.time` >= time
18    #[strum(to_string = "expiration time: {0}")]
19    AtTime(Timestamp),
20    /// Never will never expire. Used to express the empty variant
21    #[strum(to_string = "expiration: never")]
22    Never {},
23}
24
25
26/// The default (empty value) is to never expire
27impl Default for Expiration {
28    fn default() -> Self {
29        Expiration::Never {}
30    }
31}
32
33
34
35/// Duration is a delta of time. You can add it to a BlockInfo or Expiration to
36/// move that further in the future. Note that an height-based Duration and
37/// a time-based Expiration cannot be combined
38#[saa_type]
39#[derive(Display, Copy)]
40pub enum Duration {
41    /// Height in blocks
42    #[strum(to_string = "height: {0}")]
43    Height(u64),
44    /// Time in seconds
45    #[strum(to_string = "time: {0}")]
46    Time(u64),
47}
48
49
50
51#[cfg(feature = "wasm")]
52impl Expiration {
53    pub fn is_expired(&self, block: &crate::wasm::BlockInfo) -> bool {
54        match self {
55            Expiration::AtHeight(height) => block.height >= *height,
56            Expiration::AtTime(time) => block.time.seconds() >= time.seconds(),
57            Expiration::Never {} => false,
58        }
59    }
60}
61
62
63impl Add<Duration> for Expiration {
64    type Output = Result<Expiration, AuthError>;
65
66    fn add(self, duration: Duration) -> Result<Expiration, AuthError> {
67        match (self, duration) {
68            (Expiration::AtTime(t), Duration::Time(delta)) => {
69                Ok(Expiration::AtTime(t.plus_seconds(delta)))
70            }
71            (Expiration::AtHeight(h), Duration::Height(delta)) => {
72                Ok(Expiration::AtHeight(h + delta))
73            }
74            (Expiration::Never {}, _) => Ok(Expiration::Never {}),
75            _ => Err(AuthError::generic("Cannot add height and time")),
76        }
77    }
78}
79
80
81impl PartialOrd for Expiration {
82    fn partial_cmp(&self, other: &Expiration) -> Option<Ordering> {
83        match (self, other) {
84            // compare if both height or both time
85            (Expiration::AtHeight(h1), Expiration::AtHeight(h2)) => Some(h1.cmp(h2)),
86            (Expiration::AtTime(t1), Expiration::AtTime(t2)) => Some(t1.cmp(t2)),
87            // if at least one is never, we can compare with anything
88            (Expiration::Never {}, Expiration::Never {}) => Some(Ordering::Equal),
89            (Expiration::Never {}, _) => Some(Ordering::Greater),
90            (_, Expiration::Never {}) => Some(Ordering::Less),
91            // if they are mis-matched finite ends, no compare possible
92            _ => None,
93        }
94    }
95}