vcard_parser 0.2.3

Parses and validates vCard data according to RFC 6350 specification.
Documentation
use std::fmt::{Display, Formatter};

use crate::VcardError;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ValuePidData {
    pub value: Vec<(i32, Option<i32>)>,
}

impl From<Vec<(i32, Option<i32>)>> for ValuePidData {
    fn from(value: Vec<(i32, Option<i32>)>) -> Self {
        Self { value }
    }
}

impl TryFrom<&str> for ValuePidData {
    type Error = VcardError;
    fn try_from(str: &str) -> Result<Self, Self::Error> {
        let mut value = Vec::new();

        for datum in str.split(';').map(|s| s.to_string()).collect::<Vec<String>>() {
            if let Some((a, b)) = datum.split_once('.') {
                if let (Ok(id), Ok(cid)) = (a.parse::<i32>(), b.parse::<i32>()) {
                    value.push((id, Some(cid)))
                }
            } else if let Ok(id) = datum.parse::<i32>() {
                value.push((id, None))
            }
        }

        if !value.is_empty() {
            return Ok(Self { value });
        }

        Err(VcardError::ValueMalformed(str.to_string()))
    }
}

impl Display for ValuePidData {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            self.value
                .iter()
                .map(|(id, cid_option)| {
                    if let Some(cid) = cid_option {
                        format!("{}.{}", id, cid)
                    } else {
                        format!("{}", id)
                    }
                })
                .collect::<Vec<String>>()
                .join(",")
        )
    }
}