perseus/utils/
decode_time_str.rs

1#[cfg(engine)]
2mod engine {
3    use super::InvalidDuration;
4    use chrono::Utc;
5    use std::time;
6
7    /// Represents a duration that can be computed relative to the current time.
8    /// This should be created through [`PerseusDuration::into_computed`] only.
9    #[derive(Debug, Clone)]
10    pub struct ComputedDuration(chrono::Duration);
11
12    impl ComputedDuration {
13        /// Get the timestamp of the duration added to the current time.
14        pub fn compute_timestamp(&self) -> String {
15            let current = Utc::now();
16            let datetime = current + self.0;
17            datetime.to_rfc3339()
18        }
19    }
20
21    /// A trait that represents anything we'll accept for specifying durations
22    /// for revalidation. Anything that implements thus must be able to be
23    /// transformed into a [`ComputedDuration`];
24    pub trait PerseusDuration {
25        /// Converts this into a `[ComputedDuration]` for use in Perseus'
26        /// internal revalidation systems.
27        fn into_computed(self) -> Result<ComputedDuration, InvalidDuration>;
28    }
29
30    // We'll accept strings, and standard library durations.
31    // We don't accept Chrono durations because that would create a difference to
32    // the browser dummy API (since Chrono is only used on the engine side), and
33    // Chrono durations can be trivially converted into standard ones.
34    impl PerseusDuration for chrono::Duration {
35        fn into_computed(self) -> Result<ComputedDuration, InvalidDuration> {
36            Ok(ComputedDuration(self))
37        }
38    }
39    impl PerseusDuration for &str {
40        // NOTE: Logic to define how we parse time strings is here
41        fn into_computed(self) -> Result<ComputedDuration, InvalidDuration> {
42            let mut duration = chrono::Duration::zero();
43
44            // A working variable to store the '123' part of an interval until we reach the
45            // indicator and can do the full conversion
46            let mut curr_duration_length = String::new();
47
48            for c in self.chars() {
49                // If we have a number, append it to the working cache
50                // If we have an indicator character, we'll match it to a duration
51                if c.is_numeric() {
52                    curr_duration_length.push(c);
53                } else {
54                    let interval_length: i64 = curr_duration_length.parse().unwrap(); // It's just a string of numbers, we know more than the compiler
55                    if interval_length <= 0 {
56                        return Err(InvalidDuration);
57                    }
58
59                    match c {
60                        's' => duration = duration + chrono::Duration::seconds(interval_length),
61                        'm' => duration = duration + chrono::Duration::minutes(interval_length),
62                        'h' => duration = duration + chrono::Duration::hours(interval_length),
63                        'd' => duration = duration + chrono::Duration::days(interval_length),
64                        'w' => duration = duration + chrono::Duration::weeks(interval_length),
65                        'M' => duration = duration + chrono::Duration::days(interval_length * 30), /* Assumed length of a month */
66                        'y' => duration = duration + chrono::Duration::days(interval_length * 365), /* Assumed length of a year */
67                        _ => return Err(InvalidDuration),
68                    };
69
70                    curr_duration_length = String::new();
71                }
72            }
73
74            Ok(ComputedDuration(duration))
75        }
76    }
77    impl PerseusDuration for time::Duration {
78        fn into_computed(self) -> Result<ComputedDuration, InvalidDuration> {
79            let duration = chrono::Duration::from_std(self).map_err(|_| InvalidDuration)?;
80            Ok(ComputedDuration(duration))
81        }
82    }
83}
84#[cfg(client)]
85mod browser {
86    use super::InvalidDuration;
87    use std::time;
88
89    /// Represents a duration that can be computed relative to the current time.
90    /// This should be created through [`PerseusDuration::into_computed`] only.
91    #[derive(Debug, Clone)]
92    pub struct ComputedDuration;
93
94    /// A trait that represents anything we'll accept for specifying durations
95    /// for revalidation. Anything that implements thus must be able to be
96    /// transformed into a [`ComputedDuration`];
97    pub trait PerseusDuration {
98        /// Converts this into a `[ComputedDuration]` for use in Perseus'
99        /// internal revalidation systems.
100        fn into_computed(self) -> Result<ComputedDuration, InvalidDuration>
101        where
102            Self: Sized,
103        {
104            // In the browser, this function should never be called
105            unreachable!("computed durations can only be created on the engine-side")
106        }
107    }
108
109    // Dummy implementations for the browser follow (we only need this for generic
110    // validation)
111    impl PerseusDuration for &str {}
112    impl PerseusDuration for time::Duration {}
113}
114
115/// An error type for invalid durations.
116#[derive(Debug)]
117pub struct InvalidDuration;
118
119#[cfg(client)]
120pub use browser::{ComputedDuration, PerseusDuration};
121#[cfg(engine)]
122pub use engine::{ComputedDuration, PerseusDuration};
123
124// // We can convert from our duration type into the standard library's
125// impl From<Duration> for time::Duration {
126//     fn from(duration: Duration) -> Self {
127//         let duration = chrono::Duration::seconds(duration.seconds)
128//             + chrono::Duration::minutes(duration.minutes)
129//             + chrono::Duration::hours(duration.hours)
130//             + chrono::Duration::days(duration.days)
131//             + chrono::Duration::weeks(duration.weeks)
132//             + chrono::Duration::days(duration.months * 30)  // Assumed length
133// of a month             + chrono::Duration::days(duration.years * 365); //
134// Assumed length of a year
135
136//         duration.to_std().unwrap()
137//     }
138// }