1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Module that implements the encode_cf method for`CFDatetime` and `Vec<CFDatetime>`.

use crate::{
    calendars::Calendar,
    datetime::CFDatetime,
    utils::{get_datetime_and_unit_from_units, unit_to_encode},
};

pub trait CFEncoder<T> {
    fn encode_cf(&self, units: &str, calendar: Calendar) -> Result<T, crate::errors::Error>;
}

macro_rules! impl_cf_encoder {
    ($type:ty) => {
        impl CFEncoder<$type> for CFDatetime {
            fn encode_cf(
                &self,
                units: &str,
                calendar: Calendar,
            ) -> Result<$type, crate::errors::Error> {
                let (cf_datetime, unit) = get_datetime_and_unit_from_units(units, calendar)?;
                let duration = self - cf_datetime;
                let result = unit_to_encode(&unit, duration);
                Ok(result as $type)
            }
        }
    };
}

impl_cf_encoder!(i64);
impl_cf_encoder!(i32);
impl_cf_encoder!(f32);
impl_cf_encoder!(f64);

macro_rules! impl_vec_cf_encoder {
    ($type:ty) => {
        impl CFEncoder<Vec<$type>> for Vec<CFDatetime> {
            fn encode_cf(
                &self,
                units: &str,
                calendar: Calendar,
            ) -> Result<Vec<$type>, crate::errors::Error> {
                let (cf_datetime, unit) = get_datetime_and_unit_from_units(units, calendar)?;
                let mut result: Vec<$type> = Vec::with_capacity(self.len());
                for datetime in self {
                    let duration = datetime - &cf_datetime;
                    result.push(unit_to_encode(&unit, duration) as $type);
                }
                Ok(result)
            }
        }
    };
}

impl_vec_cf_encoder!(i64);
impl_vec_cf_encoder!(i32);
impl_vec_cf_encoder!(f32);
impl_vec_cf_encoder!(f64);

macro_rules! impl_vec_ref_cf_encoder {
    ($type:ty) => {
        impl CFEncoder<Vec<$type>> for Vec<&CFDatetime> {
            fn encode_cf(
                &self,
                units: &str,
                calendar: Calendar,
            ) -> Result<Vec<$type>, crate::errors::Error> {
                let (cf_datetime, unit) = get_datetime_and_unit_from_units(units, calendar)?;
                let mut result: Vec<$type> = Vec::with_capacity(self.len());
                for datetime in self {
                    let duration = *datetime - &cf_datetime;
                    result.push(unit_to_encode(&unit, duration) as $type);
                }
                Ok(result)
            }
        }
    };
}

impl_vec_ref_cf_encoder!(i64);
impl_vec_ref_cf_encoder!(i32);
impl_vec_ref_cf_encoder!(f32);
impl_vec_ref_cf_encoder!(f64);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encode_cf() {
        let datetime = CFDatetime::from_ymd(2000, 1, 1, Calendar::Standard).unwrap();
        let result: i64 = datetime
            .encode_cf("seconds since 2000-01-01 00:00:00", Calendar::Standard)
            .unwrap();
        assert_eq!(result, 0);
        let datetime = CFDatetime::from_ymd(2023, 1, 1, Calendar::Standard).unwrap();
        let result: i64 = datetime
            .encode_cf("seconds since 1970-01-01 00:00:00", Calendar::Standard)
            .unwrap();
        assert_eq!(result, 1672531200);
    }
    #[test]
    fn test_vec_encode_cf() {
        let datetimes = vec![
            CFDatetime::from_ymd(2000, 1, 1, Calendar::Standard).unwrap(),
            CFDatetime::from_ymd(2000, 1, 2, Calendar::Standard).unwrap(),
            CFDatetime::from_ymd(2000, 1, 3, Calendar::Standard).unwrap(),
        ];
        let result: Vec<i64> = datetimes
            .encode_cf("seconds since 2000-01-01 00:00:00", Calendar::Standard)
            .unwrap();
        assert_eq!(result, vec![0, 86400, 172800]);
    }
}