ical/parser/vcard/
mod.rs

1//! Parse a VCARD address book.
2//!
3//! Wrap the result of the `PropertyParser` into components.
4//!
5//! Each component contains properties (ie: Property) or sub-components.
6//!
7//! * The `VcardParser` return `VcardContact` objects.
8//!
9//! # Examples
10//!
11//! ```toml
12//! [dependencies.ical]
13//! version = "0.3.*"
14//! default-features = false
15//! features = ["vcard-parser"]
16//! ```
17//!
18//! ```rust
19//! extern crate ical;
20//!
21//! use std::io::BufReader;
22//! use std::fs::File;
23//!
24//! let buf = BufReader::new(File::open("./tests/ressources/vcard_input.vcf")
25//! .unwrap());
26//!
27//! let reader = ical::VcardParser::new(buf);
28//!
29//! for contact in reader {
30//!     println!("{:?}", contact);
31//! }
32//! ```
33
34pub mod component;
35
36// Sys mods
37use crate::parser::ParserError;
38use std::cell::RefCell;
39use std::io::BufRead;
40
41// Internal mods
42use crate::line::LineReader;
43use crate::parser::Component;
44use crate::property::PropertyParser;
45
46/// Reader returning `VcardContact` object from a `BufRead`.
47pub struct VcardParser<B> {
48    line_parser: RefCell<PropertyParser<B>>,
49}
50
51impl<B: BufRead> VcardParser<B> {
52    /// Create a new `VcardParser` from a reader.
53    pub fn new(reader: B) -> VcardParser<B> {
54        let line_reader = LineReader::new(reader);
55        let line_parser = PropertyParser::new(line_reader);
56
57        VcardParser {
58            line_parser: RefCell::new(line_parser),
59        }
60    }
61
62    /// Read the next line and check if it's a valid VCARD start.
63    fn check_header(&mut self) -> Result<Option<()>, ParserError> {
64        let line = match self.line_parser.borrow_mut().next() {
65            Some(val) => val.map_err(|e| ParserError::PropertyError(e))?,
66            None => return Ok(None),
67        };
68
69        if line.name.to_uppercase() != "BEGIN"
70            || line.value.is_none()
71            || line.value.unwrap().to_uppercase() != "VCARD"
72            || line.params != None
73        {
74            return Err(ParserError::MissingHeader.into());
75        }
76
77        Ok(Some(()))
78    }
79}
80
81impl<B: BufRead> Iterator for VcardParser<B> {
82    type Item = Result<component::VcardContact, ParserError>;
83
84    fn next(&mut self) -> Option<Result<component::VcardContact, ParserError>> {
85        match self.check_header() {
86            Ok(res) => {
87                if res == None {
88                    return None;
89                }
90            }
91            Err(err) => return Some(Err(err)),
92        };
93
94        let mut contact = component::VcardContact::new();
95        let result = match contact.parse(&self.line_parser) {
96            Ok(_) => Ok(contact),
97            Err(err) => Err(err),
98        };
99
100        Some(result)
101    }
102}