Skip to main content

caldata/parser/
property.rs

1pub trait ParseProp: Sized {
2    fn parse_prop(
3        prop: &ContentLine,
4        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
5        default_type: &str,
6    ) -> Result<Self, ParserError>;
7}
8
9impl ParseProp for String {
10    fn parse_prop(
11        prop: &ContentLine,
12        _timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
13        _default_type: &str,
14    ) -> Result<Self, ParserError> {
15        Ok(prop.value.to_owned())
16    }
17}
18
19impl ParseProp for DateOrDateTimeOrPeriod {
20    fn parse_prop(
21        prop: &ContentLine,
22        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
23        default_type: &str,
24    ) -> Result<Self, ParserError> {
25        Self::parse_prop(prop, timezones, default_type)
26    }
27}
28
29impl ParseProp for CalDateOrDateTime {
30    fn parse_prop(
31        prop: &ContentLine,
32        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
33        default_type: &str,
34    ) -> Result<Self, ParserError> {
35        Self::parse_prop(prop, timezones, default_type)
36    }
37}
38
39impl ParseProp for CalDateTime {
40    fn parse_prop(
41        prop: &ContentLine,
42        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
43        _default_type: &str,
44    ) -> Result<Self, ParserError> {
45        Self::parse_prop(prop, timezones)
46    }
47}
48
49impl ParseProp for chrono::Duration {
50    fn parse_prop(
51        prop: &ContentLine,
52        _timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
53        _default_type: &str,
54    ) -> Result<Self, ParserError> {
55        Ok(parse_duration(&prop.value)?)
56    }
57}
58
59impl ParseProp for crate::rrule::RRule<crate::rrule::Unvalidated> {
60    fn parse_prop(
61        prop: &ContentLine,
62        _timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
63        _default_type: &str,
64    ) -> Result<Self, ParserError> {
65        Ok(crate::rrule::RRule::from_str(&prop.value)?)
66    }
67}
68
69impl<T: ParseProp> ParseProp for Vec<T> {
70    fn parse_prop(
71        prop: &ContentLine,
72        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
73        default_type: &str,
74    ) -> Result<Self, ParserError> {
75        let mut out = vec![];
76        for value in prop.value.trim_end_matches(',').split(',') {
77            let content_line = ContentLine {
78                name: prop.name.to_owned(),
79                params: prop.params.to_owned(),
80                value: value.to_owned(),
81            };
82            out.push(T::parse_prop(&content_line, timezones, default_type)?);
83        }
84        Ok(out)
85    }
86}
87
88pub trait ICalProperty: Sized {
89    const NAME: &'static str;
90    const DEFAULT_TYPE: &'static str;
91
92    fn parse_prop(
93        prop: &ContentLine,
94        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
95    ) -> Result<Self, ParserError>;
96
97    fn utc_or_local(self) -> Self;
98}
99
100macro_rules! property {
101    ($name:literal, $default_type:literal, $prop:ty) => {
102        impl crate::parser::ICalProperty for $prop {
103            const NAME: &'static str = $name;
104            const DEFAULT_TYPE: &'static str = $default_type;
105
106            #[inline]
107            fn parse_prop(
108                prop: &crate::parser::ContentLine,
109                timezones: Option<&std::collections::HashMap<String, Option<chrono_tz::Tz>>>,
110            ) -> Result<Self, crate::parser::ParserError> {
111                Ok(Self(
112                    crate::parser::ParseProp::parse_prop(prop, timezones, $default_type)?,
113                    prop.params.clone(),
114                ))
115            }
116
117            #[inline]
118            fn utc_or_local(self) -> Self {
119                let Self(dt, mut params) = self;
120                params.remove("TZID");
121                Self(crate::types::Value::utc_or_local(dt), params)
122            }
123        }
124    };
125
126    ($name:literal, $default_type:literal, $prop:ident, $inner:ty) => {
127        #[derive(Debug, Clone, PartialEq, Eq, derive_more::From)]
128        pub struct $prop(pub $inner, pub crate::parser::ContentLineParams);
129        crate::parser::property!($name, $default_type, $prop);
130
131        impl From<$prop> for crate::parser::ContentLine {
132            fn from(prop: $prop) -> Self {
133                let $prop(inner, mut params) = prop;
134                let value_type = crate::types::Value::value_type(&inner).unwrap_or($default_type);
135                if value_type != $default_type {
136                    params.replace_param("VALUE".to_owned(), value_type.to_owned());
137                }
138                crate::parser::ContentLine {
139                    name: $name.to_owned(),
140                    params,
141                    value: crate::types::Value::value(&inner),
142                }
143            }
144        }
145    };
146}
147use std::{collections::HashMap, str::FromStr};
148
149pub(crate) use property;
150
151use crate::{
152    ParserError,
153    parser::ContentLine,
154    types::{CalDateOrDateTime, CalDateTime, DateOrDateTimeOrPeriod, parse_duration},
155};