Skip to main content

vcard_parser/vcard/property/
mod.rs

1//! The property module represents a single content property, as per [RFC 6350 Section 6](https://datatracker.ietf.org/doc/html/rfc6350#section-6)
2//!
3//! Properties can be created using [`Property::try_from`] or [`Property::default`]. The format should strictly follow RFC guidelines,
4//! e.g. "FN:John Doe\n" for the FN property with "John Doe" as the value. Parsed properties must end with a LF or CRLF ending as per [RFC 6350 Section 3.3](https://datatracker.ietf.org/doc/html/rfc6350#section-3.3).
5//!
6//! Note that content properties exclude BEGIN, VERSION, and END properties.
7//!
8//! See the [parameter](`super::parameter`) and [value](`super::value`) modules for more information on constructing property values.
9//!
10//! # Examples
11//!
12//! ## Creating a new property.
13//! ```
14//! use vcard_parser::vcard::property::Property;
15//!
16//! let mut property = Property::default("N");
17//! ```
18//!
19//! ## Parsing a property.
20//! ```
21//! use vcard_parser::vcard::property::Property;
22//!
23//! let mut property = Property::try_from("NICKNAME:Johnny\n").expect("Unable to parse property.");
24//! ```
25//!
26//! ## Updating a property.
27//! ```
28//! use vcard_parser::traits::HasValue;
29//! use vcard_parser::vcard::property::Property;
30//! use vcard_parser::vcard::value::Value;
31//!
32//! let mut property = Property::try_from("NICKNAME:Johnny\n").expect("Unable to parse property.");
33//! let updated = Value::try_from(("TEXTLIST", "Johnny Be Good")).expect("Unable to parse value.");
34//! property.set_value(updated).expect("Unable to update property.");
35//! assert_eq!(property.get_value().to_string(), "Johnny Be Good");
36//! ```
37
38use std::fmt::{Debug, Display, Formatter};
39
40use crate::constants::{ParameterName, PropertyName};
41use crate::parse::value::utf8_to_string;
42use crate::parse::PropertyData;
43use crate::traits::HasGroup;
44use crate::vcard::parameter::Parameter;
45use crate::vcard::property::property_adr::PropertyAdrData;
46use crate::vcard::property::property_anniversary::PropertyAnniversaryData;
47use crate::vcard::property::property_bday::PropertyBDayData;
48use crate::vcard::property::property_birthplace::PropertyBirthPlaceData;
49use crate::vcard::property::property_caladruri::PropertyCalAdrUriData;
50use crate::vcard::property::property_caluri::PropertyCalUriData;
51use crate::vcard::property::property_categories::PropertyCategoriesData;
52use crate::vcard::property::property_clientpidmap::PropertyClientPidMapData;
53use crate::vcard::property::property_contacturi::PropertyContactUriData;
54use crate::vcard::property::property_deathdate::PropertyDeathDateData;
55use crate::vcard::property::property_deathplace::PropertyDeathPlaceData;
56use crate::vcard::property::property_email::PropertyEmailData;
57use crate::vcard::property::property_expertise::PropertyExpertiseData;
58use crate::vcard::property::property_fburl::PropertyFbUrlData;
59use crate::vcard::property::property_fn::PropertyFnData;
60use crate::vcard::property::property_gender::PropertyGenderData;
61use crate::vcard::property::property_geo::PropertyGeoData;
62use crate::vcard::property::property_hobby::PropertyHobbyData;
63use crate::vcard::property::property_impp::PropertyImppData;
64use crate::vcard::property::property_interest::PropertyInterestData;
65use crate::vcard::property::property_key::PropertyKeyData;
66use crate::vcard::property::property_kind::PropertyKindData;
67use crate::vcard::property::property_lang::PropertyLangData;
68use crate::vcard::property::property_logo::PropertyLogoData;
69use crate::vcard::property::property_member::PropertyMemberData;
70use crate::vcard::property::property_n::PropertyNData;
71use crate::vcard::property::property_nickname::PropertyNickNameData;
72use crate::vcard::property::property_note::PropertyNoteData;
73use crate::vcard::property::property_org::PropertyOrgData;
74use crate::vcard::property::property_orgdirectory::PropertyOrgDirectoryData;
75use crate::vcard::property::property_photo::PropertyPhotoData;
76use crate::vcard::property::property_prodid::PropertyProdIdData;
77use crate::vcard::property::property_related::PropertyRelatedData;
78use crate::vcard::property::property_rev::PropertyRevData;
79use crate::vcard::property::property_role::PropertyRoleData;
80use crate::vcard::property::property_sound::PropertySoundData;
81use crate::vcard::property::property_source::PropertySourceData;
82use crate::vcard::property::property_tel::PropertyTelData;
83use crate::vcard::property::property_title::PropertyTitleData;
84use crate::vcard::property::property_tz::PropertyTzData;
85use crate::vcard::property::property_uid::PropertyUidData;
86use crate::vcard::property::property_url::PropertyUrlData;
87use crate::vcard::property::property_xml::PropertyXmlData;
88use crate::vcard::property::property_xname::PropertyXNameData;
89use crate::vcard::value::Value;
90use crate::vcard::value::Value::ValuePid;
91use crate::{parse, HasCardinality, HasName, HasParameters, HasValue, VcardError};
92
93pub mod property_adr;
94pub mod property_anniversary;
95pub mod property_bday;
96pub mod property_birthplace;
97pub mod property_caladruri;
98pub mod property_caluri;
99pub mod property_categories;
100pub mod property_clientpidmap;
101pub mod property_contacturi;
102pub mod property_deathdate;
103pub mod property_deathplace;
104pub mod property_email;
105pub mod property_expertise;
106pub mod property_fburl;
107pub mod property_fn;
108pub mod property_gender;
109pub mod property_geo;
110pub mod property_hobby;
111pub mod property_impp;
112pub mod property_interest;
113pub mod property_key;
114pub mod property_kind;
115pub mod property_lang;
116pub mod property_logo;
117pub mod property_member;
118pub mod property_n;
119pub mod property_nickname;
120pub mod property_note;
121pub mod property_org;
122pub mod property_orgdirectory;
123pub mod property_photo;
124pub mod property_prodid;
125pub mod property_related;
126pub mod property_rev;
127pub mod property_role;
128pub mod property_sound;
129pub mod property_source;
130pub mod property_tel;
131pub mod property_title;
132pub mod property_tz;
133pub mod property_uid;
134pub mod property_url;
135pub mod property_xml;
136pub mod property_xname;
137
138#[derive(Clone, Debug)]
139pub enum Property {
140    /// Represents an ADR parameter, see [RFC 6350 6.3.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.3.1).
141    PropertyAdr(PropertyAdrData),
142    /// Represents an ANNIVERSARY parameter, see [RFC 6350 6.2.6](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.6).
143    PropertyAnniversary(PropertyAnniversaryData),
144    /// Represents an BDAY parameter, see [RFC 6350 6.2.5](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.5).
145    PropertyBDay(PropertyBDayData),
146    /// Represents an BIRTHPLACE parameter, see [RFC 6474 2.1](https://datatracker.ietf.org/doc/html/rfc6474#section-2.1).
147    PropertyBirthPlace(PropertyBirthPlaceData),
148    /// Represents an CALADRURI parameter, see [RFC 6350 6.9.2](https://datatracker.ietf.org/doc/html/rfc6350#section-6.9.2).
149    PropertyCalAdrUri(PropertyCalAdrUriData),
150    /// Represents an CALURI parameter, see [RFC 6350 6.9.3](https://datatracker.ietf.org/doc/html/rfc6350#section-6.9.3).
151    PropertyCalUri(PropertyCalUriData),
152    /// Represents an CATEGORIES parameter, see [RFC 6350 6.7.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.1).
153    PropertyCategories(PropertyCategoriesData),
154    /// Represents an CLIENTPIDMAP parameter, see [RFC 6350 6.7.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.1).
155    PropertyClientPidMap(PropertyClientPidMapData),
156    /// Represents an CONTACT parameter, see [RFC 8605 2.1](https://datatracker.ietf.org/doc/html/rfc8605#section-2.1).
157    PropertyContactUri(PropertyContactUriData),
158    /// Represents an DEATHDATE parameter, see [RFC 6474 2.3](https://datatracker.ietf.org/doc/html/rfc6474#section-2.3).
159    PropertyDeathDate(PropertyDeathDateData),
160    /// Represents an DEATHPLACE parameter, see [RFC 6474 2.2](https://datatracker.ietf.org/doc/html/rfc6474#section-2.2).
161    PropertyDeathPlace(PropertyDeathPlaceData),
162    /// Represents an EMAIL parameter, see [RFC 6350 6.4.2](https://datatracker.ietf.org/doc/html/rfc6350#section-6.4.2).
163    PropertyEmail(PropertyEmailData),
164    /// Represents an EXPERTISE parameter, see [RFC 6715 2.1](https://datatracker.ietf.org/doc/html/rfc6715#section-2.1).
165    PropertyExpertise(PropertyExpertiseData),
166    /// Represents an FBURL parameter, see [RFC 6350 6.9.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.9.1).
167    PropertyFbUrl(PropertyFbUrlData),
168    /// Represents an FN parameter, see [RFC 6350 6.2.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.1).
169    PropertyFn(PropertyFnData),
170    /// Represents an GENDER parameter, see [RFC 6350 6.2.7](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.7).
171    PropertyGender(PropertyGenderData),
172    /// Represents an GEO parameter, see [RFC 6350 6.5.2](https://datatracker.ietf.org/doc/html/rfc6350#section-6.5.2).
173    PropertyGeo(PropertyGeoData),
174    /// Represents an HOBBY parameter, see [RFC 6715 2.2](https://datatracker.ietf.org/doc/html/rfc6715#section-2.2).
175    PropertyHobby(PropertyHobbyData),
176    /// Represents an IMPP parameter, see [RFC 6350 6.4.3](https://datatracker.ietf.org/doc/html/rfc6350#section-6.4.3).
177    PropertyImpp(PropertyImppData),
178    /// Represents an INTEREST parameter, see [RFC 6715 2.3](https://datatracker.ietf.org/doc/html/rfc6715#section-2.3).
179    PropertyInterest(PropertyInterestData),
180    /// Represents an KEY parameter, see [RFC 6350 6.8.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.8.1).
181    PropertyKey(PropertyKeyData),
182    /// Represents an KIND parameter, see [RFC 6350 6.1.4](https://datatracker.ietf.org/doc/html/rfc6350#section-6.1.4).
183    PropertyKind(PropertyKindData),
184    /// Represents an LANG parameter, see [RFC 6350 6.4.4](https://datatracker.ietf.org/doc/html/rfc6350#section-6.4.4).
185    PropertyLang(PropertyLangData),
186    /// Represents an LOGO parameter, see [RFC 6350 6.6.3](https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.3).
187    PropertyLogo(PropertyLogoData),
188    /// Represents an MEMBER parameter, see [RFC 6350 6.6.5](https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.5).
189    PropertyMember(PropertyMemberData),
190    /// Represents an NICKNAME parameter, see [RFC 6350 6.2.3](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.3).
191    PropertyNickName(PropertyNickNameData),
192    /// Represents an NOTE parameter, see [RFC 6350 6.7.2](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.2).
193    PropertyNote(PropertyNoteData),
194    /// Represents an N parameter, see [RFC 6350 6.2.2](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.2).
195    PropertyN(PropertyNData),
196    /// Represents an ORG-DIRECTORY parameter, see [RFC 6715 2.4](https://datatracker.ietf.org/doc/html/rfc6715#section-2.4).
197    PropertyOrgDirectory(PropertyOrgDirectoryData),
198    /// Represents an ORG parameter, see [RFC 6350 6.6.4](https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.4).
199    PropertyOrg(PropertyOrgData),
200    /// Represents an PHOTO parameter, see [RFC 6350 6.2.4](https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.4).
201    PropertyPhoto(PropertyPhotoData),
202    /// Represents an PRODID parameter, see [RFC 6350 6.7.3](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.3).
203    PropertyProdId(PropertyProdIdData),
204    /// Represents an RELATED parameter, see [RFC 6350 6.6.6](https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.6).
205    PropertyRelated(PropertyRelatedData),
206    /// Represents an REV parameter, see [RFC 6350 6.7.4](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.4).
207    PropertyRev(PropertyRevData),
208    /// Represents an ROLE parameter, see [RFC 6350 6.6.2](https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.2).
209    PropertyRole(PropertyRoleData),
210    /// Represents an SOUND parameter, see [RFC 6350 6.7.5](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.5).
211    PropertySound(PropertySoundData),
212    /// Represents an SOURCE parameter, see [RFC 6350 6.1.3](https://datatracker.ietf.org/doc/html/rfc6350#section-6.1.3).
213    PropertySource(PropertySourceData),
214    /// Represents an TEL parameter, see [RFC 6350 6.4.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.4.1).
215    PropertyTel(PropertyTelData),
216    /// Represents an TITLE parameter, see [RFC 6350 6.6.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.1).
217    PropertyTitle(PropertyTitleData),
218    /// Represents an TZ parameter, see [RFC 6350 6.5.1](https://datatracker.ietf.org/doc/html/rfc6350#section-6.5.1).
219    PropertyTz(PropertyTzData),
220    /// Represents an UID parameter, see [RFC 6350 6.7.6](https://datatracker.ietf.org/doc/html/rfc6350#section-6.5.1).
221    PropertyUid(PropertyUidData),
222    /// Represents an URL parameter, see [RFC 6350 6.7.8](https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.8).
223    PropertyUrl(PropertyUrlData),
224    /// Represents an XML parameter, see [RFC 6350 6.1.5](https://datatracker.ietf.org/doc/html/rfc6350#section-6.1.5).
225    PropertyXml(PropertyXmlData),
226    /// Represents an XNAME parameter, see [RFC 6350 3.3](https://datatracker.ietf.org/doc/html/rfc6350#section-3.3).
227    PropertyXName(PropertyXNameData),
228}
229
230impl Property {
231    /// Create a new property from required information (group, name, parameters, and value).
232    ///
233    /// # Examples
234    /// ```
235    /// use vcard_parser::traits::HasValue;
236    /// use vcard_parser::vcard::property::Property;
237    /// use vcard_parser::vcard::value::Value;
238    /// use vcard_parser::vcard::value::Value::ValueText;
239    /// use vcard_parser::vcard::value::value_text::ValueTextData;
240    ///
241    /// let mut property = Property::default("FN");
242    /// assert_eq!(property.export(), "FN:\n");
243    ///
244    /// property.set_value(Value::from(ValueTextData::from("John Doe"))).expect("Unable to set value.");
245    /// assert_eq!(property.export(), "FN:John Doe\n");
246    /// ```
247    pub fn create((property_group, property_name, property_parameters, property_value): (Option<String>, &str, Vec<Parameter>, &str)) -> Result<Self, VcardError> {
248        match property_name.to_uppercase().as_str() {
249            PropertyName::ADR => Ok(Property::PropertyAdr(PropertyAdrData::try_from((property_group, property_value, property_parameters))?)),
250            PropertyName::ANNIVERSARY => Ok(Property::PropertyAnniversary(PropertyAnniversaryData::try_from((property_group, property_value, property_parameters))?)),
251            PropertyName::BDAY => Ok(Property::PropertyBDay(PropertyBDayData::try_from((property_group, property_value, property_parameters))?)),
252            PropertyName::BIRTHPLACE => Ok(Property::PropertyBirthPlace(PropertyBirthPlaceData::try_from((property_group, property_value, property_parameters))?)),
253            PropertyName::CALADRURI => Ok(Property::PropertyCalAdrUri(PropertyCalAdrUriData::try_from((property_group, property_value, property_parameters))?)),
254            PropertyName::CALURI => Ok(Property::PropertyCalUri(PropertyCalUriData::try_from((property_group, property_value, property_parameters))?)),
255            PropertyName::CATEGORIES => Ok(Property::PropertyCategories(PropertyCategoriesData::try_from((property_group, property_value, property_parameters))?)),
256            PropertyName::CLIENTPIDMAP => Ok(Property::PropertyClientPidMap(PropertyClientPidMapData::try_from((property_group, property_value, property_parameters))?)),
257            PropertyName::CONTACTURI => Ok(Property::PropertyContactUri(PropertyContactUriData::try_from((property_group, property_value, property_parameters))?)),
258            PropertyName::DEATHDATE => Ok(Property::PropertyDeathDate(PropertyDeathDateData::try_from((property_group, property_value, property_parameters))?)),
259            PropertyName::DEATHPLACE => Ok(Property::PropertyDeathPlace(PropertyDeathPlaceData::try_from((property_group, property_value, property_parameters))?)),
260            PropertyName::EMAIL => Ok(Property::PropertyEmail(PropertyEmailData::try_from((property_group, property_value, property_parameters))?)),
261            PropertyName::EXPERTISE => Ok(Property::PropertyExpertise(PropertyExpertiseData::try_from((property_group, property_value, property_parameters))?)),
262            PropertyName::FBURL => Ok(Property::PropertyFbUrl(PropertyFbUrlData::try_from((property_group, property_value, property_parameters))?)),
263            PropertyName::FN => Ok(Property::PropertyFn(PropertyFnData::try_from((property_group, property_value, property_parameters))?)),
264            PropertyName::GENDER => Ok(Property::PropertyGender(PropertyGenderData::try_from((property_group, property_value, property_parameters))?)),
265            PropertyName::GEO => Ok(Property::PropertyGeo(PropertyGeoData::try_from((property_group, property_value, property_parameters))?)),
266            PropertyName::HOBBY => Ok(Property::PropertyHobby(PropertyHobbyData::try_from((property_group, property_value, property_parameters))?)),
267            PropertyName::IMPP => Ok(Property::PropertyImpp(PropertyImppData::try_from((property_group, property_value, property_parameters))?)),
268            PropertyName::INTEREST => Ok(Property::PropertyInterest(PropertyInterestData::try_from((property_group, property_value, property_parameters))?)),
269            PropertyName::KEY => Ok(Property::PropertyKey(PropertyKeyData::try_from((property_group, property_value, property_parameters))?)),
270            PropertyName::KIND => Ok(Property::PropertyKind(PropertyKindData::try_from((property_group, property_value, property_parameters))?)),
271            PropertyName::LANG => Ok(Property::PropertyLang(PropertyLangData::try_from((property_group, property_value, property_parameters))?)),
272            PropertyName::LOGO => Ok(Property::PropertyLogo(PropertyLogoData::try_from((property_group, property_value, property_parameters))?)),
273            PropertyName::MEMBER => Ok(Property::PropertyMember(PropertyMemberData::try_from((property_group, property_value, property_parameters))?)),
274            PropertyName::NICKNAME => Ok(Property::PropertyNickName(PropertyNickNameData::try_from((property_group, property_value, property_parameters))?)),
275            PropertyName::NOTE => Ok(Property::PropertyNote(PropertyNoteData::try_from((property_group, property_value, property_parameters))?)),
276            PropertyName::N => Ok(Property::PropertyN(PropertyNData::try_from((property_group, property_value, property_parameters))?)),
277            PropertyName::ORGDIRECTORY => Ok(Property::PropertyOrgDirectory(PropertyOrgDirectoryData::try_from((property_group, property_value, property_parameters))?)),
278            PropertyName::ORG => Ok(Property::PropertyOrg(PropertyOrgData::try_from((property_group, property_value, property_parameters))?)),
279            PropertyName::PHOTO => Ok(Property::PropertyPhoto(PropertyPhotoData::try_from((property_group, property_value, property_parameters))?)),
280            PropertyName::PRODID => Ok(Property::PropertyProdId(PropertyProdIdData::try_from((property_group, property_value, property_parameters))?)),
281            PropertyName::RELATED => Ok(Property::PropertyRelated(PropertyRelatedData::try_from((property_group, property_value, property_parameters))?)),
282            PropertyName::REV => Ok(Property::PropertyRev(PropertyRevData::try_from((property_group, property_value, property_parameters))?)),
283            PropertyName::ROLE => Ok(Property::PropertyRole(PropertyRoleData::try_from((property_group, property_value, property_parameters))?)),
284            PropertyName::SOUND => Ok(Property::PropertySound(PropertySoundData::try_from((property_group, property_value, property_parameters))?)),
285            PropertyName::SOURCE => Ok(Property::PropertySource(PropertySourceData::try_from((property_group, property_value, property_parameters))?)),
286            PropertyName::TEL => Ok(Property::PropertyTel(PropertyTelData::try_from((property_group, property_value, property_parameters))?)),
287            PropertyName::TITLE => Ok(Property::PropertyTitle(PropertyTitleData::try_from((property_group, property_value, property_parameters))?)),
288            PropertyName::TZ => Ok(Property::PropertyTz(PropertyTzData::try_from((property_group, property_value, property_parameters))?)),
289            PropertyName::UID => Ok(Property::PropertyUid(PropertyUidData::try_from((property_group, property_value, property_parameters))?)),
290            PropertyName::URL => Ok(Property::PropertyUrl(PropertyUrlData::try_from((property_group, property_value, property_parameters))?)),
291            PropertyName::XML => Ok(Property::PropertyXml(PropertyXmlData::try_from((property_group, property_value, property_parameters))?)),
292            _ => Ok(Property::PropertyXName(PropertyXNameData::try_from((property_group, property_name, property_value, property_parameters))?)),
293        }
294    }
295
296    pub fn create_from_data(((group, name), parameters, (value, folds)): PropertyData) -> Result<Self, VcardError> {
297        let property_name = utf8_to_string(name)?;
298
299        let property_group = {
300            if let Some(data) = group {
301                Some(utf8_to_string(data)?)
302            } else {
303                None
304            }
305        };
306
307        let mut property_parameters: Vec<Parameter> = Vec::new();
308        for datum in parameters {
309            property_parameters.push(Parameter::try_from(datum)?)
310        }
311
312        let mut property_value = Vec::from([utf8_to_string(value)?]);
313        if let Some(v) = folds {
314            for u in v {
315                if let Ok(string) = utf8_to_string(u) {
316                    property_value.push(string);
317                }
318            }
319        }
320
321        Self::create((property_group, property_name.as_str(), property_parameters, property_value.join("").as_str()))
322    }
323
324    pub fn create_from_str(str: &str) -> Result<Self, VcardError> {
325        Self::create_from_data(parse::property::property(str.as_bytes())?.1)
326    }
327
328    /// Create a new property with default values.
329    ///
330    /// # Examples
331    /// ```
332    /// use vcard_parser::traits::HasValue;
333    /// use vcard_parser::vcard::property::Property;
334    /// use vcard_parser::vcard::value::Value;
335    /// use vcard_parser::vcard::value::Value::ValueText;
336    /// use vcard_parser::vcard::value::value_text::ValueTextData;
337    ///
338    /// let mut property = Property::default("FN");
339    /// assert_eq!(property.export(), "FN:\n");
340    ///
341    /// property.set_value(Value::from(ValueTextData::from("John Doe"))).expect("Unable to set value.");
342    /// assert_eq!(property.export(), "FN:John Doe\n");
343    /// ```
344    pub fn default(name: &str) -> Self {
345        match name.to_uppercase().as_str() {
346            PropertyName::ADR => Property::PropertyAdr(PropertyAdrData::default()),
347            PropertyName::ANNIVERSARY => Property::PropertyAnniversary(PropertyAnniversaryData::default()),
348            PropertyName::BDAY => Property::PropertyBDay(PropertyBDayData::default()),
349            PropertyName::BIRTHPLACE => Property::PropertyBirthPlace(PropertyBirthPlaceData::default()),
350            PropertyName::CALADRURI => Property::PropertyCalAdrUri(PropertyCalAdrUriData::default()),
351            PropertyName::CALURI => Property::PropertyCalUri(PropertyCalUriData::default()),
352            PropertyName::CATEGORIES => Property::PropertyCategories(PropertyCategoriesData::default()),
353            PropertyName::CLIENTPIDMAP => Property::PropertyClientPidMap(PropertyClientPidMapData::default()),
354            PropertyName::CONTACTURI => Property::PropertyContactUri(PropertyContactUriData::default()),
355            PropertyName::DEATHDATE => Property::PropertyDeathDate(PropertyDeathDateData::default()),
356            PropertyName::DEATHPLACE => Property::PropertyDeathPlace(PropertyDeathPlaceData::default()),
357            PropertyName::EMAIL => Property::PropertyEmail(PropertyEmailData::default()),
358            PropertyName::EXPERTISE => Property::PropertyExpertise(PropertyExpertiseData::default()),
359            PropertyName::FBURL => Property::PropertyFbUrl(PropertyFbUrlData::default()),
360            PropertyName::FN => Property::PropertyFn(PropertyFnData::default()),
361            PropertyName::GENDER => Property::PropertyGender(PropertyGenderData::default()),
362            PropertyName::GEO => Property::PropertyGeo(PropertyGeoData::default()),
363            PropertyName::HOBBY => Property::PropertyHobby(PropertyHobbyData::default()),
364            PropertyName::IMPP => Property::PropertyImpp(PropertyImppData::default()),
365            PropertyName::INTEREST => Property::PropertyInterest(PropertyInterestData::default()),
366            PropertyName::KEY => Property::PropertyKey(PropertyKeyData::default()),
367            PropertyName::KIND => Property::PropertyKind(PropertyKindData::default()),
368            PropertyName::LANG => Property::PropertyLang(PropertyLangData::default()),
369            PropertyName::LOGO => Property::PropertyLogo(PropertyLogoData::default()),
370            PropertyName::MEMBER => Property::PropertyMember(PropertyMemberData::default()),
371            PropertyName::NICKNAME => Property::PropertyNickName(PropertyNickNameData::default()),
372            PropertyName::NOTE => Property::PropertyNote(PropertyNoteData::default()),
373            PropertyName::N => Property::PropertyN(PropertyNData::default()),
374            PropertyName::ORGDIRECTORY => Property::PropertyOrgDirectory(PropertyOrgDirectoryData::default()),
375            PropertyName::ORG => Property::PropertyOrg(PropertyOrgData::default()),
376            PropertyName::PHOTO => Property::PropertyPhoto(PropertyPhotoData::default()),
377            PropertyName::PRODID => Property::PropertyProdId(PropertyProdIdData::default()),
378            PropertyName::RELATED => Property::PropertyRelated(PropertyRelatedData::default()),
379            PropertyName::REV => Property::PropertyRev(PropertyRevData::default()),
380            PropertyName::ROLE => Property::PropertyRole(PropertyRoleData::default()),
381            PropertyName::SOUND => Property::PropertySound(PropertySoundData::default()),
382            PropertyName::SOURCE => Property::PropertySource(PropertySourceData::default()),
383            PropertyName::TEL => Property::PropertyTel(PropertyTelData::default()),
384            PropertyName::TITLE => Property::PropertyTitle(PropertyTitleData::default()),
385            PropertyName::TZ => Property::PropertyTz(PropertyTzData::default()),
386            PropertyName::UID => Property::PropertyUid(PropertyUidData::default()),
387            PropertyName::URL => Property::PropertyUrl(PropertyUrlData::default()),
388            PropertyName::XML => Property::PropertyXml(PropertyXmlData::default()),
389            _ => Property::PropertyXName(PropertyXNameData::default(name)),
390        }
391    }
392
393    /// Export a property without any pid information.
394    ///
395    /// # Examples
396    /// ```
397    /// use vcard_parser::parse::vcard::vcard;
398    /// use vcard_parser::vcard::property::Property;
399    ///
400    /// let mut property = Property::try_from("FN;PID=1:John Doe\n").expect("Unable to parse property.");
401    /// assert_eq!(property.to_string(), "FN;PID=1:John Doe\n");
402    /// assert_eq!(property.export(), "FN:John Doe\n");
403    /// ```
404    pub fn export(&self) -> String {
405        let mut property = self.clone();
406
407        // Remove all pids from property.
408        property.set_parameters(property.get_parameters().into_iter().filter(|p| p.name() != ParameterName::PID).collect());
409
410        property.to_string()
411    }
412}
413
414impl Display for Property {
415    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
416        if let Some(group) = self.group() {
417            write!(f, "{}.", group)?;
418        }
419
420        write!(f, "{}", self.name())?;
421
422        for parameter in self.get_parameters() {
423            write!(f, "{}", parameter)?;
424        }
425
426        write!(f, ":{}", self.get_value())?;
427
428        writeln!(f)?;
429
430        Ok(())
431    }
432}
433
434/// Matches properties based on [RFC 6350 7.1.2](https://datatracker.ietf.org/doc/html/rfc6350#section-7.1.2) and [RFC 6350 7.1.3](https://datatracker.ietf.org/doc/html/rfc6350#section-7.1.3).
435impl PartialEq<Property> for Property {
436    fn eq(&self, other: &Property) -> bool {
437        // Property instances whose name is CLIENTPIDMAP are handled separately
438        // and MUST NOT be matched.  The synchronization MUST ensure that there
439        // is consistency of CLIENTPIDMAPs among matched vCard instances.
440        if self.name() == PropertyName::CLIENTPIDMAP {
441            return false;
442        }
443
444        // Property instances whose name (e.g., EMAIL, TEL, etc.) is not the
445        // same MUST NOT be matched.
446        if self.name() != other.name() {
447            return false;
448        }
449
450        // Property instances belonging to matched vCards, whose name is the
451        // same, and whose maximum cardinality is 1, MUST be matched.
452        if self.is_single() && self.name() == other.name() {
453            return true;
454        }
455
456        // Property instances belonging to matched vCards, whose name is the
457        // same, and whose PID parameters match, MUST be matched. See
458        // Section 7.1.3 for details on PID matching.
459        if self.is_multiple() && self.name() == other.name() {
460            fn _pids_get(property: &Property) -> Option<Vec<(i32, Option<i32>)>> {
461                for parameter in property.get_parameters() {
462                    if parameter.name() == ParameterName::PID {
463                        if let ValuePid(data) = parameter.get_value() {
464                            return Some(data.value.clone());
465                        }
466                    }
467                }
468                None
469            }
470
471            if let (Some(a), Some(b)) = (_pids_get(self), _pids_get(other)) {
472                for (a1, a2) in &a {
473                    for (b1, b2) in &b {
474                        if a1 == b1 && a2 == b2 {
475                            return true;
476                        }
477                    }
478                }
479            }
480        }
481
482        // In all other cases, property instances MAY be matched at the
483        // discretion of the synchronization engine.
484        false
485    }
486}
487
488impl TryFrom<&str> for Property {
489    type Error = VcardError;
490    fn try_from(str: &str) -> Result<Self, Self::Error> {
491        Self::create_from_str(str)
492    }
493}
494
495impl<'a> TryFrom<PropertyData<'a>> for Property {
496    type Error = VcardError;
497    fn try_from(data: PropertyData) -> Result<Self, Self::Error> {
498        Self::create_from_data(data)
499    }
500}
501
502impl TryFrom<(Option<String>, &str, Vec<Parameter>, &str)> for Property {
503    type Error = VcardError;
504    fn try_from(data: (Option<String>, &str, Vec<Parameter>, &str)) -> Result<Self, Self::Error> {
505        Self::create(data)
506    }
507}
508
509impl HasGroup for Property {
510    fn group(&self) -> &Option<String> {
511        match self {
512            Property::PropertyAdr(property) => property.group(),
513            Property::PropertyAnniversary(property) => property.group(),
514            Property::PropertyBDay(property) => property.group(),
515            Property::PropertyBirthPlace(property) => property.group(),
516            Property::PropertyCalAdrUri(property) => property.group(),
517            Property::PropertyCalUri(property) => property.group(),
518            Property::PropertyCategories(property) => property.group(),
519            Property::PropertyClientPidMap(property) => property.group(),
520            Property::PropertyContactUri(property) => property.group(),
521            Property::PropertyDeathDate(property) => property.group(),
522            Property::PropertyDeathPlace(property) => property.group(),
523            Property::PropertyEmail(property) => property.group(),
524            Property::PropertyExpertise(property) => property.group(),
525            Property::PropertyFbUrl(property) => property.group(),
526            Property::PropertyFn(property) => property.group(),
527            Property::PropertyGender(property) => property.group(),
528            Property::PropertyGeo(property) => property.group(),
529            Property::PropertyHobby(property) => property.group(),
530            Property::PropertyImpp(property) => property.group(),
531            Property::PropertyInterest(property) => property.group(),
532            Property::PropertyKey(property) => property.group(),
533            Property::PropertyKind(property) => property.group(),
534            Property::PropertyLang(property) => property.group(),
535            Property::PropertyLogo(property) => property.group(),
536            Property::PropertyMember(property) => property.group(),
537            Property::PropertyNickName(property) => property.group(),
538            Property::PropertyNote(property) => property.group(),
539            Property::PropertyN(property) => property.group(),
540            Property::PropertyOrgDirectory(property) => property.group(),
541            Property::PropertyOrg(property) => property.group(),
542            Property::PropertyPhoto(property) => property.group(),
543            Property::PropertyProdId(property) => property.group(),
544            Property::PropertyRelated(property) => property.group(),
545            Property::PropertyRev(property) => property.group(),
546            Property::PropertyRole(property) => property.group(),
547            Property::PropertySound(property) => property.group(),
548            Property::PropertySource(property) => property.group(),
549            Property::PropertyTel(property) => property.group(),
550            Property::PropertyTitle(property) => property.group(),
551            Property::PropertyTz(property) => property.group(),
552            Property::PropertyUid(property) => property.group(),
553            Property::PropertyUrl(property) => property.group(),
554            Property::PropertyXml(property) => property.group(),
555            Property::PropertyXName(property) => property.group(),
556        }
557    }
558}
559
560impl HasName for Property {
561    fn name(&self) -> &str {
562        match self {
563            Property::PropertyAdr(property) => property.name(),
564            Property::PropertyAnniversary(property) => property.name(),
565            Property::PropertyBDay(property) => property.name(),
566            Property::PropertyBirthPlace(property) => property.name(),
567            Property::PropertyCalAdrUri(property) => property.name(),
568            Property::PropertyCalUri(property) => property.name(),
569            Property::PropertyCategories(property) => property.name(),
570            Property::PropertyClientPidMap(property) => property.name(),
571            Property::PropertyContactUri(property) => property.name(),
572            Property::PropertyDeathDate(property) => property.name(),
573            Property::PropertyDeathPlace(property) => property.name(),
574            Property::PropertyEmail(property) => property.name(),
575            Property::PropertyExpertise(property) => property.name(),
576            Property::PropertyFbUrl(property) => property.name(),
577            Property::PropertyFn(property) => property.name(),
578            Property::PropertyGender(property) => property.name(),
579            Property::PropertyGeo(property) => property.name(),
580            Property::PropertyHobby(property) => property.name(),
581            Property::PropertyImpp(property) => property.name(),
582            Property::PropertyInterest(property) => property.name(),
583            Property::PropertyKey(property) => property.name(),
584            Property::PropertyKind(property) => property.name(),
585            Property::PropertyLang(property) => property.name(),
586            Property::PropertyLogo(property) => property.name(),
587            Property::PropertyMember(property) => property.name(),
588            Property::PropertyNickName(property) => property.name(),
589            Property::PropertyNote(property) => property.name(),
590            Property::PropertyN(property) => property.name(),
591            Property::PropertyOrgDirectory(property) => property.name(),
592            Property::PropertyOrg(property) => property.name(),
593            Property::PropertyPhoto(property) => property.name(),
594            Property::PropertyProdId(property) => property.name(),
595            Property::PropertyRelated(property) => property.name(),
596            Property::PropertyRev(property) => property.name(),
597            Property::PropertyRole(property) => property.name(),
598            Property::PropertySound(property) => property.name(),
599            Property::PropertySource(property) => property.name(),
600            Property::PropertyTel(property) => property.name(),
601            Property::PropertyTitle(property) => property.name(),
602            Property::PropertyTz(property) => property.name(),
603            Property::PropertyUid(property) => property.name(),
604            Property::PropertyUrl(property) => property.name(),
605            Property::PropertyXml(property) => property.name(),
606            Property::PropertyXName(property) => property.name(),
607        }
608    }
609}
610
611impl HasCardinality for Property {
612    fn cardinality(&self) -> &str {
613        match self {
614            Property::PropertyAdr(property) => property.cardinality(),
615            Property::PropertyAnniversary(property) => property.cardinality(),
616            Property::PropertyBDay(property) => property.cardinality(),
617            Property::PropertyBirthPlace(property) => property.cardinality(),
618            Property::PropertyCalAdrUri(property) => property.cardinality(),
619            Property::PropertyCalUri(property) => property.cardinality(),
620            Property::PropertyCategories(property) => property.cardinality(),
621            Property::PropertyClientPidMap(property) => property.cardinality(),
622            Property::PropertyContactUri(property) => property.cardinality(),
623            Property::PropertyDeathDate(property) => property.cardinality(),
624            Property::PropertyDeathPlace(property) => property.cardinality(),
625            Property::PropertyEmail(property) => property.cardinality(),
626            Property::PropertyExpertise(property) => property.cardinality(),
627            Property::PropertyFbUrl(property) => property.cardinality(),
628            Property::PropertyFn(property) => property.cardinality(),
629            Property::PropertyGender(property) => property.cardinality(),
630            Property::PropertyGeo(property) => property.cardinality(),
631            Property::PropertyHobby(property) => property.cardinality(),
632            Property::PropertyImpp(property) => property.cardinality(),
633            Property::PropertyInterest(property) => property.cardinality(),
634            Property::PropertyKey(property) => property.cardinality(),
635            Property::PropertyKind(property) => property.cardinality(),
636            Property::PropertyLang(property) => property.cardinality(),
637            Property::PropertyLogo(property) => property.cardinality(),
638            Property::PropertyMember(property) => property.cardinality(),
639            Property::PropertyNickName(property) => property.cardinality(),
640            Property::PropertyNote(property) => property.cardinality(),
641            Property::PropertyN(property) => property.cardinality(),
642            Property::PropertyOrgDirectory(property) => property.cardinality(),
643            Property::PropertyOrg(property) => property.cardinality(),
644            Property::PropertyPhoto(property) => property.cardinality(),
645            Property::PropertyProdId(property) => property.cardinality(),
646            Property::PropertyRelated(property) => property.cardinality(),
647            Property::PropertyRev(property) => property.cardinality(),
648            Property::PropertyRole(property) => property.cardinality(),
649            Property::PropertySound(property) => property.cardinality(),
650            Property::PropertySource(property) => property.cardinality(),
651            Property::PropertyTel(property) => property.cardinality(),
652            Property::PropertyTitle(property) => property.cardinality(),
653            Property::PropertyTz(property) => property.cardinality(),
654            Property::PropertyUid(property) => property.cardinality(),
655            Property::PropertyUrl(property) => property.cardinality(),
656            Property::PropertyXml(property) => property.cardinality(),
657            Property::PropertyXName(property) => property.cardinality(),
658        }
659    }
660}
661
662impl HasValue for Property {
663    fn get_value(&self) -> &Value {
664        match self {
665            Property::PropertyAdr(property) => property.get_value(),
666            Property::PropertyAnniversary(property) => property.get_value(),
667            Property::PropertyBDay(property) => property.get_value(),
668            Property::PropertyBirthPlace(property) => property.get_value(),
669            Property::PropertyCalAdrUri(property) => property.get_value(),
670            Property::PropertyCalUri(property) => property.get_value(),
671            Property::PropertyCategories(property) => property.get_value(),
672            Property::PropertyClientPidMap(property) => property.get_value(),
673            Property::PropertyContactUri(property) => property.get_value(),
674            Property::PropertyDeathDate(property) => property.get_value(),
675            Property::PropertyDeathPlace(property) => property.get_value(),
676            Property::PropertyEmail(property) => property.get_value(),
677            Property::PropertyExpertise(property) => property.get_value(),
678            Property::PropertyFbUrl(property) => property.get_value(),
679            Property::PropertyFn(property) => property.get_value(),
680            Property::PropertyGender(property) => property.get_value(),
681            Property::PropertyGeo(property) => property.get_value(),
682            Property::PropertyHobby(property) => property.get_value(),
683            Property::PropertyImpp(property) => property.get_value(),
684            Property::PropertyInterest(property) => property.get_value(),
685            Property::PropertyKey(property) => property.get_value(),
686            Property::PropertyKind(property) => property.get_value(),
687            Property::PropertyLang(property) => property.get_value(),
688            Property::PropertyLogo(property) => property.get_value(),
689            Property::PropertyMember(property) => property.get_value(),
690            Property::PropertyNickName(property) => property.get_value(),
691            Property::PropertyNote(property) => property.get_value(),
692            Property::PropertyN(property) => property.get_value(),
693            Property::PropertyOrgDirectory(property) => property.get_value(),
694            Property::PropertyOrg(property) => property.get_value(),
695            Property::PropertyPhoto(property) => property.get_value(),
696            Property::PropertyProdId(property) => property.get_value(),
697            Property::PropertyRelated(property) => property.get_value(),
698            Property::PropertyRev(property) => property.get_value(),
699            Property::PropertyRole(property) => property.get_value(),
700            Property::PropertySound(property) => property.get_value(),
701            Property::PropertySource(property) => property.get_value(),
702            Property::PropertyTel(property) => property.get_value(),
703            Property::PropertyTitle(property) => property.get_value(),
704            Property::PropertyTz(property) => property.get_value(),
705            Property::PropertyUid(property) => property.get_value(),
706            Property::PropertyUrl(property) => property.get_value(),
707            Property::PropertyXml(property) => property.get_value(),
708            Property::PropertyXName(property) => property.get_value(),
709        }
710    }
711
712    fn set_value(&mut self, value: Value) -> Result<(), VcardError> {
713        match self {
714            Property::PropertyAdr(property) => property.set_value(value),
715            Property::PropertyAnniversary(property) => property.set_value(value),
716            Property::PropertyBDay(property) => property.set_value(value),
717            Property::PropertyBirthPlace(property) => property.set_value(value),
718            Property::PropertyCalAdrUri(property) => property.set_value(value),
719            Property::PropertyCalUri(property) => property.set_value(value),
720            Property::PropertyCategories(property) => property.set_value(value),
721            Property::PropertyClientPidMap(property) => property.set_value(value),
722            Property::PropertyContactUri(property) => property.set_value(value),
723            Property::PropertyDeathDate(property) => property.set_value(value),
724            Property::PropertyDeathPlace(property) => property.set_value(value),
725            Property::PropertyEmail(property) => property.set_value(value),
726            Property::PropertyExpertise(property) => property.set_value(value),
727            Property::PropertyFbUrl(property) => property.set_value(value),
728            Property::PropertyFn(property) => property.set_value(value),
729            Property::PropertyGender(property) => property.set_value(value),
730            Property::PropertyGeo(property) => property.set_value(value),
731            Property::PropertyHobby(property) => property.set_value(value),
732            Property::PropertyImpp(property) => property.set_value(value),
733            Property::PropertyInterest(property) => property.set_value(value),
734            Property::PropertyKey(property) => property.set_value(value),
735            Property::PropertyKind(property) => property.set_value(value),
736            Property::PropertyLang(property) => property.set_value(value),
737            Property::PropertyLogo(property) => property.set_value(value),
738            Property::PropertyMember(property) => property.set_value(value),
739            Property::PropertyNickName(property) => property.set_value(value),
740            Property::PropertyNote(property) => property.set_value(value),
741            Property::PropertyN(property) => property.set_value(value),
742            Property::PropertyOrgDirectory(property) => property.set_value(value),
743            Property::PropertyOrg(property) => property.set_value(value),
744            Property::PropertyPhoto(property) => property.set_value(value),
745            Property::PropertyProdId(property) => property.set_value(value),
746            Property::PropertyRelated(property) => property.set_value(value),
747            Property::PropertyRev(property) => property.set_value(value),
748            Property::PropertyRole(property) => property.set_value(value),
749            Property::PropertySound(property) => property.set_value(value),
750            Property::PropertySource(property) => property.set_value(value),
751            Property::PropertyTel(property) => property.set_value(value),
752            Property::PropertyTitle(property) => property.set_value(value),
753            Property::PropertyTz(property) => property.set_value(value),
754            Property::PropertyUid(property) => property.set_value(value),
755            Property::PropertyUrl(property) => property.set_value(value),
756            Property::PropertyXml(property) => property.set_value(value),
757            Property::PropertyXName(property) => property.set_value(value),
758        }
759    }
760}
761
762impl HasParameters for Property {
763    fn allowed_parameters<'a>(&self) -> Vec<&'a str> {
764        match self {
765            Property::PropertyAdr(property) => property.allowed_parameters(),
766            Property::PropertyAnniversary(property) => property.allowed_parameters(),
767            Property::PropertyBDay(property) => property.allowed_parameters(),
768            Property::PropertyBirthPlace(property) => property.allowed_parameters(),
769            Property::PropertyCalAdrUri(property) => property.allowed_parameters(),
770            Property::PropertyCalUri(property) => property.allowed_parameters(),
771            Property::PropertyCategories(property) => property.allowed_parameters(),
772            Property::PropertyClientPidMap(property) => property.allowed_parameters(),
773            Property::PropertyContactUri(property) => property.allowed_parameters(),
774            Property::PropertyDeathDate(property) => property.allowed_parameters(),
775            Property::PropertyDeathPlace(property) => property.allowed_parameters(),
776            Property::PropertyEmail(property) => property.allowed_parameters(),
777            Property::PropertyExpertise(property) => property.allowed_parameters(),
778            Property::PropertyFbUrl(property) => property.allowed_parameters(),
779            Property::PropertyFn(property) => property.allowed_parameters(),
780            Property::PropertyGender(property) => property.allowed_parameters(),
781            Property::PropertyGeo(property) => property.allowed_parameters(),
782            Property::PropertyHobby(property) => property.allowed_parameters(),
783            Property::PropertyImpp(property) => property.allowed_parameters(),
784            Property::PropertyInterest(property) => property.allowed_parameters(),
785            Property::PropertyKey(property) => property.allowed_parameters(),
786            Property::PropertyKind(property) => property.allowed_parameters(),
787            Property::PropertyLang(property) => property.allowed_parameters(),
788            Property::PropertyLogo(property) => property.allowed_parameters(),
789            Property::PropertyMember(property) => property.allowed_parameters(),
790            Property::PropertyNickName(property) => property.allowed_parameters(),
791            Property::PropertyNote(property) => property.allowed_parameters(),
792            Property::PropertyN(property) => property.allowed_parameters(),
793            Property::PropertyOrgDirectory(property) => property.allowed_parameters(),
794            Property::PropertyOrg(property) => property.allowed_parameters(),
795            Property::PropertyPhoto(property) => property.allowed_parameters(),
796            Property::PropertyProdId(property) => property.allowed_parameters(),
797            Property::PropertyRelated(property) => property.allowed_parameters(),
798            Property::PropertyRev(property) => property.allowed_parameters(),
799            Property::PropertyRole(property) => property.allowed_parameters(),
800            Property::PropertySound(property) => property.allowed_parameters(),
801            Property::PropertySource(property) => property.allowed_parameters(),
802            Property::PropertyTel(property) => property.allowed_parameters(),
803            Property::PropertyTitle(property) => property.allowed_parameters(),
804            Property::PropertyTz(property) => property.allowed_parameters(),
805            Property::PropertyUid(property) => property.allowed_parameters(),
806            Property::PropertyUrl(property) => property.allowed_parameters(),
807            Property::PropertyXml(property) => property.allowed_parameters(),
808            Property::PropertyXName(property) => property.allowed_parameters(),
809        }
810    }
811
812    fn get_parameters(&self) -> Vec<Parameter> {
813        match self {
814            Property::PropertyAdr(property) => property.get_parameters(),
815            Property::PropertyAnniversary(property) => property.get_parameters(),
816            Property::PropertyBDay(property) => property.get_parameters(),
817            Property::PropertyBirthPlace(property) => property.get_parameters(),
818            Property::PropertyCalAdrUri(property) => property.get_parameters(),
819            Property::PropertyCalUri(property) => property.get_parameters(),
820            Property::PropertyCategories(property) => property.get_parameters(),
821            Property::PropertyClientPidMap(property) => property.get_parameters(),
822            Property::PropertyContactUri(property) => property.get_parameters(),
823            Property::PropertyDeathDate(property) => property.get_parameters(),
824            Property::PropertyDeathPlace(property) => property.get_parameters(),
825            Property::PropertyEmail(property) => property.get_parameters(),
826            Property::PropertyExpertise(property) => property.get_parameters(),
827            Property::PropertyFbUrl(property) => property.get_parameters(),
828            Property::PropertyFn(property) => property.get_parameters(),
829            Property::PropertyGender(property) => property.get_parameters(),
830            Property::PropertyGeo(property) => property.get_parameters(),
831            Property::PropertyHobby(property) => property.get_parameters(),
832            Property::PropertyImpp(property) => property.get_parameters(),
833            Property::PropertyInterest(property) => property.get_parameters(),
834            Property::PropertyKey(property) => property.get_parameters(),
835            Property::PropertyKind(property) => property.get_parameters(),
836            Property::PropertyLang(property) => property.get_parameters(),
837            Property::PropertyLogo(property) => property.get_parameters(),
838            Property::PropertyMember(property) => property.get_parameters(),
839            Property::PropertyNickName(property) => property.get_parameters(),
840            Property::PropertyNote(property) => property.get_parameters(),
841            Property::PropertyN(property) => property.get_parameters(),
842            Property::PropertyOrgDirectory(property) => property.get_parameters(),
843            Property::PropertyOrg(property) => property.get_parameters(),
844            Property::PropertyPhoto(property) => property.get_parameters(),
845            Property::PropertyProdId(property) => property.get_parameters(),
846            Property::PropertyRelated(property) => property.get_parameters(),
847            Property::PropertyRev(property) => property.get_parameters(),
848            Property::PropertyRole(property) => property.get_parameters(),
849            Property::PropertySound(property) => property.get_parameters(),
850            Property::PropertySource(property) => property.get_parameters(),
851            Property::PropertyTel(property) => property.get_parameters(),
852            Property::PropertyTitle(property) => property.get_parameters(),
853            Property::PropertyTz(property) => property.get_parameters(),
854            Property::PropertyUid(property) => property.get_parameters(),
855            Property::PropertyUrl(property) => property.get_parameters(),
856            Property::PropertyXml(property) => property.get_parameters(),
857            Property::PropertyXName(property) => property.get_parameters(),
858        }
859    }
860
861    fn set_parameters(&mut self, parameters: Vec<Parameter>) {
862        match self {
863            Property::PropertyAdr(property) => property.set_parameters(parameters),
864            Property::PropertyAnniversary(property) => property.set_parameters(parameters),
865            Property::PropertyBDay(property) => property.set_parameters(parameters),
866            Property::PropertyBirthPlace(property) => property.set_parameters(parameters),
867            Property::PropertyCalAdrUri(property) => property.set_parameters(parameters),
868            Property::PropertyCalUri(property) => property.set_parameters(parameters),
869            Property::PropertyCategories(property) => property.set_parameters(parameters),
870            Property::PropertyClientPidMap(property) => property.set_parameters(parameters),
871            Property::PropertyContactUri(property) => property.set_parameters(parameters),
872            Property::PropertyDeathDate(property) => property.set_parameters(parameters),
873            Property::PropertyDeathPlace(property) => property.set_parameters(parameters),
874            Property::PropertyEmail(property) => property.set_parameters(parameters),
875            Property::PropertyExpertise(property) => property.set_parameters(parameters),
876            Property::PropertyFbUrl(property) => property.set_parameters(parameters),
877            Property::PropertyFn(property) => property.set_parameters(parameters),
878            Property::PropertyGender(property) => property.set_parameters(parameters),
879            Property::PropertyGeo(property) => property.set_parameters(parameters),
880            Property::PropertyHobby(property) => property.set_parameters(parameters),
881            Property::PropertyImpp(property) => property.set_parameters(parameters),
882            Property::PropertyInterest(property) => property.set_parameters(parameters),
883            Property::PropertyKey(property) => property.set_parameters(parameters),
884            Property::PropertyKind(property) => property.set_parameters(parameters),
885            Property::PropertyLang(property) => property.set_parameters(parameters),
886            Property::PropertyLogo(property) => property.set_parameters(parameters),
887            Property::PropertyMember(property) => property.set_parameters(parameters),
888            Property::PropertyNickName(property) => property.set_parameters(parameters),
889            Property::PropertyNote(property) => property.set_parameters(parameters),
890            Property::PropertyN(property) => property.set_parameters(parameters),
891            Property::PropertyOrgDirectory(property) => property.set_parameters(parameters),
892            Property::PropertyOrg(property) => property.set_parameters(parameters),
893            Property::PropertyPhoto(property) => property.set_parameters(parameters),
894            Property::PropertyProdId(property) => property.set_parameters(parameters),
895            Property::PropertyRelated(property) => property.set_parameters(parameters),
896            Property::PropertyRev(property) => property.set_parameters(parameters),
897            Property::PropertyRole(property) => property.set_parameters(parameters),
898            Property::PropertySound(property) => property.set_parameters(parameters),
899            Property::PropertySource(property) => property.set_parameters(parameters),
900            Property::PropertyTel(property) => property.set_parameters(parameters),
901            Property::PropertyTitle(property) => property.set_parameters(parameters),
902            Property::PropertyTz(property) => property.set_parameters(parameters),
903            Property::PropertyUid(property) => property.set_parameters(parameters),
904            Property::PropertyUrl(property) => property.set_parameters(parameters),
905            Property::PropertyXml(property) => property.set_parameters(parameters),
906            Property::PropertyXName(property) => property.set_parameters(parameters),
907        }
908    }
909}
910
911#[cfg(test)]
912mod tests {
913    use crate::constants::{PropertyName, TestDataPropertyValues};
914    use crate::vcard::property::property_adr::PropertyAdrData;
915    use crate::vcard::property::property_anniversary::PropertyAnniversaryData;
916    use crate::vcard::property::property_bday::PropertyBDayData;
917    use crate::vcard::property::property_birthplace::PropertyBirthPlaceData;
918    use crate::vcard::property::property_caladruri::PropertyCalAdrUriData;
919    use crate::vcard::property::property_caluri::PropertyCalUriData;
920    use crate::vcard::property::property_categories::PropertyCategoriesData;
921    use crate::vcard::property::property_clientpidmap::PropertyClientPidMapData;
922    use crate::vcard::property::property_contacturi::PropertyContactUriData;
923    use crate::vcard::property::property_deathdate::PropertyDeathDateData;
924    use crate::vcard::property::property_deathplace::PropertyDeathPlaceData;
925    use crate::vcard::property::property_email::PropertyEmailData;
926    use crate::vcard::property::property_expertise::PropertyExpertiseData;
927    use crate::vcard::property::property_fburl::PropertyFbUrlData;
928    use crate::vcard::property::property_fn::PropertyFnData;
929    use crate::vcard::property::property_gender::PropertyGenderData;
930    use crate::vcard::property::property_geo::PropertyGeoData;
931    use crate::vcard::property::property_hobby::PropertyHobbyData;
932    use crate::vcard::property::property_impp::PropertyImppData;
933    use crate::vcard::property::property_interest::PropertyInterestData;
934    use crate::vcard::property::property_key::PropertyKeyData;
935    use crate::vcard::property::property_kind::PropertyKindData;
936    use crate::vcard::property::property_lang::PropertyLangData;
937    use crate::vcard::property::property_logo::PropertyLogoData;
938    use crate::vcard::property::property_member::PropertyMemberData;
939    use crate::vcard::property::property_n::PropertyNData;
940    use crate::vcard::property::property_nickname::PropertyNickNameData;
941    use crate::vcard::property::property_note::PropertyNoteData;
942    use crate::vcard::property::property_org::PropertyOrgData;
943    use crate::vcard::property::property_orgdirectory::PropertyOrgDirectoryData;
944    use crate::vcard::property::property_photo::PropertyPhotoData;
945    use crate::vcard::property::property_prodid::PropertyProdIdData;
946    use crate::vcard::property::property_related::PropertyRelatedData;
947    use crate::vcard::property::property_rev::PropertyRevData;
948    use crate::vcard::property::property_role::PropertyRoleData;
949    use crate::vcard::property::property_sound::PropertySoundData;
950    use crate::vcard::property::property_source::PropertySourceData;
951    use crate::vcard::property::property_tel::PropertyTelData;
952    use crate::vcard::property::property_title::PropertyTitleData;
953    use crate::vcard::property::property_tz::PropertyTzData;
954    use crate::vcard::property::property_uid::PropertyUidData;
955    use crate::vcard::property::property_url::PropertyUrlData;
956    use crate::vcard::property::property_xml::PropertyXmlData;
957    use crate::{HasCardinality, HasName, HasValue, Property, Vcard};
958
959    #[test]
960    pub fn property_cardinality() {
961        assert!(PropertyAnniversaryData::default().is_single());
962        assert!(PropertyBDayData::default().is_single());
963        assert!(PropertyBirthPlaceData::default().is_single());
964        assert!(PropertyDeathDateData::default().is_single());
965        assert!(PropertyDeathPlaceData::default().is_single());
966        assert!(PropertyFnData::default().is_single());
967        assert!(PropertyGenderData::default().is_single());
968        assert!(PropertyKindData::default().is_single());
969        assert!(PropertyNData::default().is_single());
970        assert!(PropertyProdIdData::default().is_single());
971        assert!(PropertyRevData::default().is_single());
972        assert!(PropertyUidData::default().is_single());
973
974        assert!(PropertyAdrData::default().is_multiple());
975        assert!(PropertyCalAdrUriData::default().is_multiple());
976        assert!(PropertyCalUriData::default().is_multiple());
977        assert!(PropertyCategoriesData::default().is_multiple());
978        assert!(PropertyClientPidMapData::default().is_multiple());
979        assert!(PropertyContactUriData::default().is_multiple());
980        assert!(PropertyEmailData::default().is_multiple());
981        assert!(PropertyExpertiseData::default().is_multiple());
982        assert!(PropertyFbUrlData::default().is_multiple());
983        assert!(PropertyGeoData::default().is_multiple());
984        assert!(PropertyHobbyData::default().is_multiple());
985        assert!(PropertyImppData::default().is_multiple());
986        assert!(PropertyInterestData::default().is_multiple());
987        assert!(PropertyKeyData::default().is_multiple());
988        assert!(PropertyLangData::default().is_multiple());
989        assert!(PropertyLogoData::default().is_multiple());
990        assert!(PropertyMemberData::default().is_multiple());
991        assert!(PropertyNickNameData::default().is_multiple());
992        assert!(PropertyNoteData::default().is_multiple());
993        assert!(PropertyOrgDirectoryData::default().is_multiple());
994        assert!(PropertyOrgData::default().is_multiple());
995        assert!(PropertyPhotoData::default().is_multiple());
996        assert!(PropertyRelatedData::default().is_multiple());
997        assert!(PropertyRoleData::default().is_multiple());
998        assert!(PropertySoundData::default().is_multiple());
999        assert!(PropertySourceData::default().is_multiple());
1000        assert!(PropertyTelData::default().is_multiple());
1001        assert!(PropertyTitleData::default().is_multiple());
1002        assert!(PropertyTzData::default().is_multiple());
1003        assert!(PropertyUrlData::default().is_multiple());
1004        assert!(PropertyXmlData::default().is_multiple());
1005    }
1006
1007    #[test]
1008    pub fn property_names() {
1009        assert_eq!(PropertyAdrData::default().name(), PropertyName::ADR);
1010        assert_eq!(PropertyAnniversaryData::default().name(), PropertyName::ANNIVERSARY);
1011        assert_eq!(PropertyBDayData::default().name(), PropertyName::BDAY);
1012        assert_eq!(PropertyBirthPlaceData::default().name(), PropertyName::BIRTHPLACE);
1013        assert_eq!(PropertyCalAdrUriData::default().name(), PropertyName::CALADRURI);
1014        assert_eq!(PropertyCalUriData::default().name(), PropertyName::CALURI);
1015        assert_eq!(PropertyCategoriesData::default().name(), PropertyName::CATEGORIES);
1016        assert_eq!(PropertyClientPidMapData::default().name(), PropertyName::CLIENTPIDMAP);
1017        assert_eq!(PropertyContactUriData::default().name(), PropertyName::CONTACTURI);
1018        assert_eq!(PropertyDeathDateData::default().name(), PropertyName::DEATHDATE);
1019        assert_eq!(PropertyDeathPlaceData::default().name(), PropertyName::DEATHPLACE);
1020        assert_eq!(PropertyEmailData::default().name(), PropertyName::EMAIL);
1021        assert_eq!(PropertyExpertiseData::default().name(), PropertyName::EXPERTISE);
1022        assert_eq!(PropertyFbUrlData::default().name(), PropertyName::FBURL);
1023        assert_eq!(PropertyFnData::default().name(), PropertyName::FN);
1024        assert_eq!(PropertyGenderData::default().name(), PropertyName::GENDER);
1025        assert_eq!(PropertyGeoData::default().name(), PropertyName::GEO);
1026        assert_eq!(PropertyHobbyData::default().name(), PropertyName::HOBBY);
1027        assert_eq!(PropertyImppData::default().name(), PropertyName::IMPP);
1028        assert_eq!(PropertyInterestData::default().name(), PropertyName::INTEREST);
1029        assert_eq!(PropertyKeyData::default().name(), PropertyName::KEY);
1030        assert_eq!(PropertyKindData::default().name(), PropertyName::KIND);
1031        assert_eq!(PropertyLangData::default().name(), PropertyName::LANG);
1032        assert_eq!(PropertyLogoData::default().name(), PropertyName::LOGO);
1033        assert_eq!(PropertyMemberData::default().name(), PropertyName::MEMBER);
1034        assert_eq!(PropertyNickNameData::default().name(), PropertyName::NICKNAME);
1035        assert_eq!(PropertyNoteData::default().name(), PropertyName::NOTE);
1036        assert_eq!(PropertyNData::default().name(), PropertyName::N);
1037        assert_eq!(PropertyOrgDirectoryData::default().name(), PropertyName::ORGDIRECTORY);
1038        assert_eq!(PropertyOrgData::default().name(), PropertyName::ORG);
1039        assert_eq!(PropertyPhotoData::default().name(), PropertyName::PHOTO);
1040        assert_eq!(PropertyProdIdData::default().name(), PropertyName::PRODID);
1041        assert_eq!(PropertyRelatedData::default().name(), PropertyName::RELATED);
1042        assert_eq!(PropertyRevData::default().name(), PropertyName::REV);
1043        assert_eq!(PropertyRoleData::default().name(), PropertyName::ROLE);
1044        assert_eq!(PropertySoundData::default().name(), PropertyName::SOUND);
1045        assert_eq!(PropertySourceData::default().name(), PropertyName::SOURCE);
1046        assert_eq!(PropertyTelData::default().name(), PropertyName::TEL);
1047        assert_eq!(PropertyTitleData::default().name(), PropertyName::TITLE);
1048        assert_eq!(PropertyTzData::default().name(), PropertyName::TZ);
1049        assert_eq!(PropertyUidData::default().name(), PropertyName::UID);
1050        assert_eq!(PropertyUrlData::default().name(), PropertyName::URL);
1051        assert_eq!(PropertyXmlData::default().name(), PropertyName::XML);
1052    }
1053
1054    #[test]
1055    pub fn property_equality() {
1056        let a = Property::try_from("TEL;PID=1.1:555-5555\n").expect("Unable to parse property string.");
1057        let b = Property::try_from("TEL;PID=1.1:555-5556\n").expect("Unable to parse property string.");
1058        let c = Property::try_from("TEL;PID=1.2:555-5555\n").expect("Unable to parse property string.");
1059        let d = Property::try_from("TEL;PID=2.1:555-5557\n").expect("Unable to parse property string.");
1060
1061        assert_eq!(a, b);
1062        assert_eq!(b, a);
1063        assert_ne!(a, c);
1064        assert_ne!(a, d);
1065        assert_ne!(b, c);
1066        assert_ne!(b, d);
1067        assert_ne!(c, d);
1068
1069        assert_ne!(a.get_value(), b.get_value());
1070        assert_eq!(a.get_value(), c.get_value());
1071    }
1072
1073    #[test]
1074    pub fn property_matching() {
1075        pub fn _property_matching(name: &str, value: &str) {
1076            let mut vcard = Vcard::new("John Doe");
1077
1078            let str = format!("{}:{}\n", name, value);
1079
1080            let a = Property::try_from(str.as_str()).unwrap();
1081            let b = Property::try_from(str.as_str()).unwrap();
1082
1083            if a.name() == PropertyName::CLIENTPIDMAP {
1084                // TODO: Figure out CLIENTPIDMAP matching and adding.
1085            } else if a.name() == PropertyName::FN {
1086                vcard.set_property(&a).unwrap();
1087                assert_eq!(vcard.properties.len(), 1);
1088                vcard.set_property(&b).unwrap();
1089                assert_eq!(vcard.properties.len(), 1);
1090            } else if a.is_multiple() && b.is_multiple() {
1091                vcard.set_property(&a).unwrap();
1092                assert_eq!(vcard.get_properties_by_name(name).len(), 1);
1093                vcard.set_property(&b).unwrap();
1094                assert_eq!(vcard.get_properties_by_name(name).len(), 2);
1095            } else if a.is_single() && b.is_single() {
1096                vcard.set_property(&a).unwrap();
1097                assert_eq!(vcard.properties.len(), 2);
1098                vcard.set_property(&b).unwrap();
1099                assert_eq!(vcard.properties.len(), 2);
1100            }
1101        }
1102
1103        _property_matching(PropertyName::ADR, TestDataPropertyValues::ADR);
1104        _property_matching(PropertyName::ANNIVERSARY, TestDataPropertyValues::ANNIVERSARY);
1105        _property_matching(PropertyName::BDAY, TestDataPropertyValues::BDAY);
1106        _property_matching(PropertyName::BIRTHPLACE, TestDataPropertyValues::BIRTHPLACE);
1107        _property_matching(PropertyName::CALADRURI, TestDataPropertyValues::CALADRURI);
1108        _property_matching(PropertyName::CALURI, TestDataPropertyValues::CALURI);
1109        _property_matching(PropertyName::CATEGORIES, TestDataPropertyValues::CATEGORIES);
1110        _property_matching(PropertyName::CLIENTPIDMAP, TestDataPropertyValues::CLIENTPIDMAP);
1111        _property_matching(PropertyName::CONTACTURI, TestDataPropertyValues::CONTACTURI);
1112        _property_matching(PropertyName::DEATHDATE, TestDataPropertyValues::DEATHDATE);
1113        _property_matching(PropertyName::DEATHPLACE, TestDataPropertyValues::DEATHPLACE);
1114        _property_matching(PropertyName::EMAIL, TestDataPropertyValues::EMAIL);
1115        _property_matching(PropertyName::EXPERTISE, TestDataPropertyValues::EXPERTISE);
1116        _property_matching(PropertyName::FBURL, TestDataPropertyValues::FBURL);
1117        _property_matching(PropertyName::FN, TestDataPropertyValues::FN);
1118        _property_matching(PropertyName::GENDER, TestDataPropertyValues::GENDER);
1119        _property_matching(PropertyName::GEO, TestDataPropertyValues::GEO);
1120        _property_matching(PropertyName::HOBBY, TestDataPropertyValues::HOBBY);
1121        _property_matching(PropertyName::IMPP, TestDataPropertyValues::IMPP);
1122        _property_matching(PropertyName::INTEREST, TestDataPropertyValues::INTEREST);
1123        _property_matching(PropertyName::KEY, TestDataPropertyValues::KEY);
1124        _property_matching(PropertyName::KIND, TestDataPropertyValues::KIND);
1125        _property_matching(PropertyName::LANG, TestDataPropertyValues::LANG);
1126        _property_matching(PropertyName::LOGO, TestDataPropertyValues::LOGO);
1127        _property_matching(PropertyName::MEMBER, TestDataPropertyValues::MEMBER);
1128        _property_matching(PropertyName::NICKNAME, TestDataPropertyValues::NICKNAME);
1129        _property_matching(PropertyName::NOTE, TestDataPropertyValues::NOTE);
1130        _property_matching(PropertyName::N, TestDataPropertyValues::N);
1131        _property_matching(PropertyName::ORGDIRECTORY, TestDataPropertyValues::ORGDIRECTORY);
1132        _property_matching(PropertyName::ORG, TestDataPropertyValues::ORG);
1133        _property_matching(PropertyName::PHOTO, TestDataPropertyValues::PHOTO);
1134        _property_matching(PropertyName::PRODID, TestDataPropertyValues::PRODID);
1135        _property_matching(PropertyName::RELATED, TestDataPropertyValues::RELATED);
1136        _property_matching(PropertyName::REV, TestDataPropertyValues::REV);
1137        _property_matching(PropertyName::ROLE, TestDataPropertyValues::ROLE);
1138        _property_matching(PropertyName::SOUND, TestDataPropertyValues::SOUND);
1139        _property_matching(PropertyName::SOURCE, TestDataPropertyValues::SOURCE);
1140        _property_matching(PropertyName::TEL, TestDataPropertyValues::TEL);
1141        _property_matching(PropertyName::TITLE, TestDataPropertyValues::TITLE);
1142        _property_matching(PropertyName::TZ, TestDataPropertyValues::TZ);
1143        _property_matching(PropertyName::UID, TestDataPropertyValues::UID);
1144        _property_matching(PropertyName::URL, TestDataPropertyValues::URL);
1145        _property_matching(PropertyName::XML, TestDataPropertyValues::XML);
1146    }
1147}