vcard_parser/vcard/parameter/
mod.rs

1//! The parameter module represents a single property parameter, as per [RFC 6350 Section 5](https://datatracker.ietf.org/doc/html/rfc6350#section-5)
2//!
3//! Parameters can be created using [`Parameter::try_from`] or [`Parameter::default`]. The format should strictly follow RFC guidelines,
4//! e.g. ";ALTID=1" for the ALTID parameter with "1" as the value. Parsed parameters must begin with a semi-colon as per [RFC 6350 Section 3.3](https://datatracker.ietf.org/doc/html/rfc6350#section-3.3).
5//!
6//! For more information on values, see the [values](super::value) module.
7//!
8//! # Examples
9//!
10//! ## Creating a new parameter.
11//! ```
12//! use vcard_parser::vcard::parameter::Parameter;
13//!
14//! let mut parameter = Parameter::default("ALTID");
15//! ```
16//!
17//! ## Parsing a parameter.
18//! ```
19//! use vcard_parser::vcard::parameter::Parameter;
20//!
21//! let mut parameter = Parameter::try_from(";ALTID=1").expect("Unable to parse parameter.");
22//! ```
23//!
24//! ## Updating a parameter.
25//! ```
26//! use vcard_parser::traits::HasValue;
27//! use vcard_parser::vcard::parameter::Parameter;
28//! use vcard_parser::vcard::value::Value;
29//!
30//! let mut parameter = Parameter::try_from(";ALTID=1").expect("Unable to parse parameter.");
31//! let updated = Value::try_from(("INTEGER", "1")).expect("Unable to parse value.");
32//! parameter.set_value(updated).expect("Unable to update parameter.");
33//! assert_eq!(parameter.get_value().to_string(), "1");
34//! ```
35
36use std::fmt::{Display, Formatter};
37
38use crate::constants::ParameterName;
39use crate::parse::value::utf8_to_string;
40use crate::vcard::parameter::parameter_altid::ParameterAltIdData;
41use crate::vcard::parameter::parameter_calscale::ParameterCalScaleData;
42use crate::vcard::parameter::parameter_cc::ParameterCcData;
43use crate::vcard::parameter::parameter_geo::ParameterGeoData;
44use crate::vcard::parameter::parameter_index::ParameterIndexData;
45use crate::vcard::parameter::parameter_label::ParameterLabelData;
46use crate::vcard::parameter::parameter_language::ParameterLanguageData;
47use crate::vcard::parameter::parameter_level::ParameterLevelData;
48use crate::vcard::parameter::parameter_mediatype::ParameterMediaTypeData;
49use crate::vcard::parameter::parameter_pid::ParameterPidData;
50use crate::vcard::parameter::parameter_pref::ParameterPrefData;
51use crate::vcard::parameter::parameter_sortas::ParameterSortAsData;
52use crate::vcard::parameter::parameter_type::ParameterTypeData;
53use crate::vcard::parameter::parameter_tz::ParameterTzData;
54use crate::vcard::parameter::parameter_value::ValueParameterData;
55use crate::vcard::parameter::parameter_xname::XNameParameterData;
56use crate::vcard::value::Value;
57use crate::{parse, HasName, HasValue, VcardError};
58
59pub mod parameter_altid;
60pub mod parameter_calscale;
61pub mod parameter_cc;
62pub mod parameter_geo;
63pub mod parameter_index;
64pub mod parameter_label;
65pub mod parameter_language;
66pub mod parameter_level;
67pub mod parameter_mediatype;
68pub mod parameter_pid;
69pub mod parameter_pref;
70pub mod parameter_sortas;
71pub mod parameter_type;
72pub mod parameter_tz;
73pub mod parameter_value;
74pub mod parameter_xname;
75
76#[derive(Clone, Debug, PartialEq)]
77pub enum Parameter {
78    /// Represents an ALTID parameter, see [RFC 6350 5.4](https://datatracker.ietf.org/doc/html/rfc6350#section-5.4).
79    ParameterAltId(ParameterAltIdData),
80    /// Represents an CALSCALE parameter, see [RFC 6350 5.8](https://datatracker.ietf.org/doc/html/rfc6350#section-5.8).
81    ParameterCalScale(ParameterCalScaleData),
82    /// Represents an CC parameter, see [RFC 8605 3.1](https://datatracker.ietf.org/doc/html/rfc8605#section-3.1).
83    ParameterCc(ParameterCcData),
84    /// Represents an GEO parameter, see [RFC 6350 5.10](https://datatracker.ietf.org/doc/html/rfc6350#section-5.10).
85    ParameterGeo(ParameterGeoData),
86    /// Represents an INDEX parameter, see [RFC 6715 3.1](https://datatracker.ietf.org/doc/html/rfc6715#section-3.1).
87    ParameterIndex(ParameterIndexData),
88    /// Represents an LABEL parameter, see [RFC 6350](https://datatracker.ietf.org/doc/html/rfc6350).
89    ParameterLabel(ParameterLabelData),
90    /// Represents an LANGUAGE parameter, see [RFC 6350 5.1](https://datatracker.ietf.org/doc/html/rfc6350#section-5.1).
91    ParameterLanguage(ParameterLanguageData),
92    /// Represents an LEVEL parameter, see [RFC 6715 3.2](https://datatracker.ietf.org/doc/html/rfc6715#section-3.2).
93    ParameterLevel(ParameterLevelData),
94    /// Represents an MEDIATYPE parameter, see [RFC 6350 5.7](https://datatracker.ietf.org/doc/html/rfc6350#section-5.7).
95    ParameterMediaType(ParameterMediaTypeData),
96    /// Represents an PID parameter, see [RFC 6350 5.5](https://datatracker.ietf.org/doc/html/rfc6350#section-5.5).
97    ParameterPid(ParameterPidData),
98    /// Represents an PREF parameter, see [RFC 6350 5.3](https://datatracker.ietf.org/doc/html/rfc6350#section-5.3).
99    ParameterPref(ParameterPrefData),
100    /// Represents an SORT-AS parameter, see [RFC 6350 5.9](https://datatracker.ietf.org/doc/html/rfc6350#section-5.9).
101    ParameterSortAs(ParameterSortAsData),
102    /// Represents an TYPE parameter, see [RFC 6350 5.6](https://datatracker.ietf.org/doc/html/rfc6350#section-5.6).
103    ParameterType(ParameterTypeData),
104    /// Represents an TZ parameter, see [RFC 6350 5.11](https://datatracker.ietf.org/doc/html/rfc6350#section-5.11).
105    ParameterTz(ParameterTzData),
106    /// Represents an VALUE parameter, see [RFC 6350 5.2](https://datatracker.ietf.org/doc/html/rfc6350#section-5.2).
107    ParameterValue(ValueParameterData),
108    /// Represents an VALUE parameter, see [RFC 6350 3.3](https://datatracker.ietf.org/doc/html/rfc6350#section-3.3).
109    ParameterXName(XNameParameterData),
110}
111
112impl Parameter {
113    pub fn default(name: &str) -> Self {
114        match name.to_uppercase().as_str() {
115            ParameterName::ALTID => Self::ParameterAltId(ParameterAltIdData::default()),
116            ParameterName::CALSCALE => Self::ParameterCalScale(ParameterCalScaleData::default()),
117            ParameterName::CC => Self::ParameterCc(ParameterCcData::default()),
118            ParameterName::GEO => Self::ParameterGeo(ParameterGeoData::default()),
119            ParameterName::INDEX => Self::ParameterIndex(ParameterIndexData::default()),
120            ParameterName::LABEL => Self::ParameterLabel(ParameterLabelData::default()),
121            ParameterName::LANGUAGE => Self::ParameterLanguage(ParameterLanguageData::default()),
122            ParameterName::LEVEL => Self::ParameterLevel(ParameterLevelData::default()),
123            ParameterName::MEDIATYPE => Self::ParameterMediaType(ParameterMediaTypeData::default()),
124            ParameterName::PID => Self::ParameterPid(ParameterPidData::default()),
125            ParameterName::PREF => Self::ParameterPref(ParameterPrefData::default()),
126            ParameterName::SORTAS => Self::ParameterSortAs(ParameterSortAsData::default()),
127            ParameterName::TYPE => Self::ParameterType(ParameterTypeData::default()),
128            ParameterName::TZ => Self::ParameterTz(ParameterTzData::default()),
129            ParameterName::VALUE => Self::ParameterValue(ValueParameterData::default()),
130            _ => Self::ParameterXName(XNameParameterData::default(name)),
131        }
132    }
133}
134
135impl TryFrom<&str> for Parameter {
136    type Error = VcardError;
137    fn try_from(str: &str) -> Result<Self, Self::Error> {
138        let (_, (parameter_name, parameter_value)) = parse::parameter::parameter(str.as_bytes())?;
139        Parameter::try_from((utf8_to_string(parameter_name)?.as_str(), utf8_to_string(parameter_value)?.as_str()))
140    }
141}
142
143impl TryFrom<(&[u8], &[u8])> for Parameter {
144    type Error = VcardError;
145    fn try_from((parameter_name, parameter_value): (&[u8], &[u8])) -> Result<Self, Self::Error> {
146        Parameter::try_from((utf8_to_string(parameter_name)?.as_str(), utf8_to_string(parameter_value)?.as_str()))
147    }
148}
149
150impl TryFrom<(&str, &str)> for Parameter {
151    type Error = VcardError;
152    fn try_from((parameter_name, parameter_value): (&str, &str)) -> Result<Self, Self::Error> {
153        match parameter_name.to_uppercase().as_str() {
154            ParameterName::ALTID => Ok(Self::ParameterAltId(ParameterAltIdData::try_from(parameter_value)?)),
155            ParameterName::CALSCALE => Ok(Self::ParameterCalScale(ParameterCalScaleData::try_from(parameter_value)?)),
156            ParameterName::CC => Ok(Self::ParameterCc(ParameterCcData::try_from(parameter_value)?)),
157            ParameterName::GEO => Ok(Self::ParameterGeo(ParameterGeoData::try_from(parameter_value)?)),
158            ParameterName::INDEX => Ok(Self::ParameterIndex(ParameterIndexData::try_from(parameter_value)?)),
159            ParameterName::LABEL => Ok(Self::ParameterLabel(ParameterLabelData::try_from(parameter_value)?)),
160            ParameterName::LANGUAGE => Ok(Self::ParameterLanguage(ParameterLanguageData::try_from(parameter_value)?)),
161            ParameterName::LEVEL => Ok(Self::ParameterLevel(ParameterLevelData::try_from(parameter_value)?)),
162            ParameterName::MEDIATYPE => Ok(Self::ParameterMediaType(ParameterMediaTypeData::try_from(parameter_value)?)),
163            ParameterName::PID => Ok(Self::ParameterPid(ParameterPidData::try_from(parameter_value)?)),
164            ParameterName::PREF => Ok(Self::ParameterPref(ParameterPrefData::try_from(parameter_value)?)),
165            ParameterName::SORTAS => Ok(Self::ParameterSortAs(ParameterSortAsData::try_from(parameter_value)?)),
166            ParameterName::TYPE => Ok(Self::ParameterType(ParameterTypeData::try_from(parameter_value)?)),
167            ParameterName::TZ => Ok(Self::ParameterTz(ParameterTzData::try_from(parameter_value)?)),
168            ParameterName::VALUE => Ok(Self::ParameterValue(ValueParameterData::try_from(parameter_value)?)),
169            _ => Ok(Self::ParameterXName(XNameParameterData::try_from((parameter_name, parameter_value))?)),
170        }
171    }
172}
173
174impl Display for Parameter {
175    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
176        write!(f, ";{}={}", self.name(), self.get_value())
177    }
178}
179
180impl HasName for Parameter {
181    fn name(&self) -> &str {
182        match self {
183            Parameter::ParameterAltId(parameter) => parameter.name(),
184            Parameter::ParameterCalScale(parameter) => parameter.name(),
185            Parameter::ParameterCc(parameter) => parameter.name(),
186            Parameter::ParameterGeo(parameter) => parameter.name(),
187            Parameter::ParameterIndex(parameter) => parameter.name(),
188            Parameter::ParameterLabel(parameter) => parameter.name(),
189            Parameter::ParameterLanguage(parameter) => parameter.name(),
190            Parameter::ParameterLevel(parameter) => parameter.name(),
191            Parameter::ParameterMediaType(parameter) => parameter.name(),
192            Parameter::ParameterPid(parameter) => parameter.name(),
193            Parameter::ParameterPref(parameter) => parameter.name(),
194            Parameter::ParameterSortAs(parameter) => parameter.name(),
195            Parameter::ParameterType(parameter) => parameter.name(),
196            Parameter::ParameterTz(parameter) => parameter.name(),
197            Parameter::ParameterValue(parameter) => parameter.name(),
198            Parameter::ParameterXName(parameter) => parameter.name(),
199        }
200    }
201}
202
203impl HasValue for Parameter {
204    fn get_value(&self) -> &Value {
205        match self {
206            Parameter::ParameterAltId(parameter) => parameter.get_value(),
207            Parameter::ParameterCalScale(parameter) => parameter.get_value(),
208            Parameter::ParameterCc(parameter) => parameter.get_value(),
209            Parameter::ParameterGeo(parameter) => parameter.get_value(),
210            Parameter::ParameterIndex(parameter) => parameter.get_value(),
211            Parameter::ParameterLabel(parameter) => parameter.get_value(),
212            Parameter::ParameterLanguage(parameter) => parameter.get_value(),
213            Parameter::ParameterLevel(parameter) => parameter.get_value(),
214            Parameter::ParameterMediaType(parameter) => parameter.get_value(),
215            Parameter::ParameterPid(parameter) => parameter.get_value(),
216            Parameter::ParameterPref(parameter) => parameter.get_value(),
217            Parameter::ParameterSortAs(parameter) => parameter.get_value(),
218            Parameter::ParameterType(parameter) => parameter.get_value(),
219            Parameter::ParameterTz(parameter) => parameter.get_value(),
220            Parameter::ParameterValue(parameter) => parameter.get_value(),
221            Parameter::ParameterXName(parameter) => parameter.get_value(),
222        }
223    }
224
225    fn set_value(&mut self, value: Value) -> Result<(), VcardError> {
226        match self {
227            Parameter::ParameterAltId(parameter) => parameter.set_value(value),
228            Parameter::ParameterCalScale(parameter) => parameter.set_value(value),
229            Parameter::ParameterCc(parameter) => parameter.set_value(value),
230            Parameter::ParameterGeo(parameter) => parameter.set_value(value),
231            Parameter::ParameterIndex(parameter) => parameter.set_value(value),
232            Parameter::ParameterLabel(parameter) => parameter.set_value(value),
233            Parameter::ParameterLanguage(parameter) => parameter.set_value(value),
234            Parameter::ParameterLevel(parameter) => parameter.set_value(value),
235            Parameter::ParameterMediaType(parameter) => parameter.set_value(value),
236            Parameter::ParameterPid(parameter) => parameter.set_value(value),
237            Parameter::ParameterPref(parameter) => parameter.set_value(value),
238            Parameter::ParameterSortAs(parameter) => parameter.set_value(value),
239            Parameter::ParameterType(parameter) => parameter.set_value(value),
240            Parameter::ParameterTz(parameter) => parameter.set_value(value),
241            Parameter::ParameterValue(parameter) => parameter.set_value(value),
242            Parameter::ParameterXName(parameter) => parameter.set_value(value),
243        }
244    }
245}
246
247#[cfg(test)]
248mod tests {
249    use crate::vcard::parameter::Parameter;
250
251    #[test]
252    fn parameter_try_from() {
253        assert!(Parameter::try_from(";ALTID=1").is_ok());
254        assert!(Parameter::try_from(";CALSCALE=gregorian").is_ok());
255        assert!(Parameter::try_from(";CC=us").is_ok());
256        assert!(Parameter::try_from(";GEO=\"geo:0.0,-0.0\"").is_ok());
257        assert!(Parameter::try_from(";INDEX=1").is_ok());
258        assert!(Parameter::try_from(";LABEL=WORK").is_ok());
259        assert!(Parameter::try_from(";LANGUAGE=en").is_ok());
260        assert!(Parameter::try_from(";LEVEL=1").is_ok());
261        assert!(Parameter::try_from(";MEDIATYPE=1").is_ok());
262        assert!(Parameter::try_from(";PID=1").is_ok());
263        assert!(Parameter::try_from(";PREF=1").is_ok());
264        assert!(Parameter::try_from(";SORT-AS=1").is_ok());
265        assert!(Parameter::try_from(";TYPE=1").is_ok());
266        assert!(Parameter::try_from(";TZ=1").is_ok());
267        assert!(Parameter::try_from(";VALUE=1").is_ok());
268        assert!(Parameter::try_from(";X-VALUE=1").is_ok());
269    }
270}