23 releases

0.7.2 Mar 25, 2025
0.7.1 Dec 12, 2024
0.6.2 Dec 12, 2024
0.5.2 Jun 28, 2024
0.1.4 Nov 9, 2022

#452 in Encoding

Download history 130/week @ 2025-03-19 50/week @ 2025-03-26 27/week @ 2025-04-02 17/week @ 2025-04-09 57/week @ 2025-04-16 71/week @ 2025-04-23 28/week @ 2025-04-30 68/week @ 2025-05-07 11/week @ 2025-05-14 6/week @ 2025-06-11 22/week @ 2025-06-18 61/week @ 2025-06-25 59/week @ 2025-07-02

148 downloads per month
Used in 26 crates (6 directly)

MIT/Apache

160KB
4K SLoC

vCard

Fast and correct vCard parser based on RFC6350; see the API documentation for more information.

For interoperability with older software the parser will accept input with a CHARSET parameter that has a value of UTF-8, any other encoding value for CHARSET will generate an error. However, this parameter is not part of RFC6350 and is therefore not included in the string output for a vCard.

License is MIT or Apache-2.0.


lib.rs:

Fast and correct vCard parser based on RFC6350.

vCards inherently contain private information so this library implements a zeroize feature (which is enabled by default) to securely zero the memory for all the data in a vCard when it is dropped.

Certain external types cannot be zeroize'd due to the restrictions on implementing external traits on external types and are therefore exempt:

  • Uri
  • Time / UtcOffset / OffsetDateTime
  • LanguageTag (feature: language-tags)
  • Mime (feature: mime)

If the mime feature is enabled the MEDIATYPE parameter is parsed to a Mime struct otherwise it is a String.

If the language-tags feature is enabled the LANG property and the LANGUAGE parameter are parsed using the language-tags crate.

Serde support can be enabled with the serde feature.

Examples

Create a new vCard:

use vcard4::VcardBuilder;
let card = VcardBuilder::new("John Doe".to_owned())
    .nickname("Johnny".to_owned())
    .finish();
print!("{}", card);

Decoding and encoding:

use anyhow::Result;
use vcard4::parse;
pub fn main() -> Result<()> {
    let input = r#"BEGIN:VCARD
VERSION:4.0
FN:John Doe
NICKNAME:Johnny
END:VCARD"#;
    let cards = parse(input)?;
    let card = cards.first().unwrap();
    let encoded = card.to_string();
    let decoded = parse(&encoded)?.remove(0);
    assert_eq!(card, &decoded);
    Ok(())
}

Iterative parsing is useful if you only need the first vCard or wish to ignore vCards that have errors (possibly during an import operation):

use anyhow::Result;
use vcard4::iter;

pub fn main() -> Result<()> {
    let input = r#"BEGIN:VCARD
VERSION:4.0
FN:John Doe
END:VCARD

BEGIN:VCARD
VERSION:4.0
FN:Jane Doe
END:VCARD"#;
    let mut it = iter(input, true);
    print!("{}", it.next().unwrap()?);
    print!("{}", it.next().unwrap()?);
    assert!(matches!(it.next(), None));
    Ok(())
}

Implementation

  • The XML property is parsed and propagated but it is not validated as it is optional in the RFC.
  • IANA Tokens are not implemented.
  • The RFC requires a CRLF sequence for line breaks but for easier interoperability between platforms we treat the carriage return as optional.

Dependencies

~5MB
~62K SLoC