use crate::{
common::{tokenizer::Token, CalendarScale, Data, PartialDateTime},
Entry, Parser,
};
pub mod parser;
pub mod utils;
pub mod writer;
#[cfg(feature = "rkyv")]
pub mod rkyv_types;
#[cfg(feature = "rkyv")]
pub mod rkyv_utils;
#[cfg(feature = "rkyv")]
pub mod rkyv_writer;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub struct VCard {
pub entries: Vec<VCardEntry>,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VCardVersion {
V2_0 = 20,
V2_1 = 21,
V3_0 = 30,
#[default]
V4_0 = 40,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub struct VCardEntry {
pub group: Option<String>,
pub name: VCardProperty,
pub params: Vec<VCardParameter>,
pub values: Vec<VCardValue>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(any(test, feature = "serde"), serde(tag = "type", content = "data"))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardProperty {
Begin,
End,
Source, Kind, Xml, Fn, N, Nickname, Photo, Bday, Anniversary, Gender, Adr, Tel, Email, Impp, Lang, Tz, Geo, Title, Role, Logo, Org, Member, Related, Categories, Note, Prodid, Rev, Sound, Uid, Clientpidmap, Url, Version, Key, Fburl, Caladruri, Caluri, Birthplace, Deathplace, Deathdate, Expertise, Hobby, Interest, OrgDirectory, ContactUri, Created, Gramgender, Language, Pronouns, Socialprofile, Jsprop, Other(String),
}
impl TryFrom<&[u8]> for VCardProperty {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
hashify::tiny_map_ignore_case!(value,
"BEGIN" => VCardProperty::Begin,
"END" => VCardProperty::End,
"SOURCE" => VCardProperty::Source,
"KIND" => VCardProperty::Kind,
"XML" => VCardProperty::Xml,
"FN" => VCardProperty::Fn,
"N" => VCardProperty::N,
"NICKNAME" => VCardProperty::Nickname,
"PHOTO" => VCardProperty::Photo,
"BDAY" => VCardProperty::Bday,
"ANNIVERSARY" => VCardProperty::Anniversary,
"GENDER" => VCardProperty::Gender,
"ADR" => VCardProperty::Adr,
"TEL" => VCardProperty::Tel,
"EMAIL" => VCardProperty::Email,
"IMPP" => VCardProperty::Impp,
"LANG" => VCardProperty::Lang,
"TZ" => VCardProperty::Tz,
"GEO" => VCardProperty::Geo,
"TITLE" => VCardProperty::Title,
"ROLE" => VCardProperty::Role,
"LOGO" => VCardProperty::Logo,
"ORG" => VCardProperty::Org,
"MEMBER" => VCardProperty::Member,
"RELATED" => VCardProperty::Related,
"CATEGORIES" => VCardProperty::Categories,
"NOTE" => VCardProperty::Note,
"PRODID" => VCardProperty::Prodid,
"REV" => VCardProperty::Rev,
"SOUND" => VCardProperty::Sound,
"UID" => VCardProperty::Uid,
"CLIENTPIDMAP" => VCardProperty::Clientpidmap,
"URL" => VCardProperty::Url,
"VERSION" => VCardProperty::Version,
"KEY" => VCardProperty::Key,
"FBURL" => VCardProperty::Fburl,
"CALADRURI" => VCardProperty::Caladruri,
"CALURI" => VCardProperty::Caluri,
"BIRTHPLACE" => VCardProperty::Birthplace,
"DEATHPLACE" => VCardProperty::Deathplace,
"DEATHDATE" => VCardProperty::Deathdate,
"EXPERTISE" => VCardProperty::Expertise,
"HOBBY" => VCardProperty::Hobby,
"INTEREST" => VCardProperty::Interest,
"ORG-DIRECTORY" => VCardProperty::OrgDirectory,
"CONTACT-URI" => VCardProperty::ContactUri,
"CREATED" => VCardProperty::Created,
"GRAMGENDER" => VCardProperty::Gramgender,
"LANGUAGE" => VCardProperty::Language,
"PRONOUNS" => VCardProperty::Pronouns,
"SOCIALPROFILE" => VCardProperty::Socialprofile,
"JSPROP" => VCardProperty::Jsprop,
)
.ok_or(())
}
}
impl VCardProperty {
pub fn as_str(&self) -> &str {
match self {
VCardProperty::Source => "SOURCE",
VCardProperty::Kind => "KIND",
VCardProperty::Xml => "XML",
VCardProperty::Fn => "FN",
VCardProperty::N => "N",
VCardProperty::Nickname => "NICKNAME",
VCardProperty::Photo => "PHOTO",
VCardProperty::Bday => "BDAY",
VCardProperty::Anniversary => "ANNIVERSARY",
VCardProperty::Gender => "GENDER",
VCardProperty::Adr => "ADR",
VCardProperty::Tel => "TEL",
VCardProperty::Email => "EMAIL",
VCardProperty::Impp => "IMPP",
VCardProperty::Lang => "LANG",
VCardProperty::Tz => "TZ",
VCardProperty::Geo => "GEO",
VCardProperty::Title => "TITLE",
VCardProperty::Role => "ROLE",
VCardProperty::Logo => "LOGO",
VCardProperty::Org => "ORG",
VCardProperty::Member => "MEMBER",
VCardProperty::Related => "RELATED",
VCardProperty::Categories => "CATEGORIES",
VCardProperty::Note => "NOTE",
VCardProperty::Prodid => "PRODID",
VCardProperty::Rev => "REV",
VCardProperty::Sound => "SOUND",
VCardProperty::Uid => "UID",
VCardProperty::Clientpidmap => "CLIENTPIDMAP",
VCardProperty::Url => "URL",
VCardProperty::Version => "VERSION",
VCardProperty::Key => "KEY",
VCardProperty::Fburl => "FBURL",
VCardProperty::Caladruri => "CALADRURI",
VCardProperty::Caluri => "CALURI",
VCardProperty::Birthplace => "BIRTHPLACE",
VCardProperty::Deathplace => "DEATHPLACE",
VCardProperty::Deathdate => "DEATHDATE",
VCardProperty::Expertise => "EXPERTISE",
VCardProperty::Hobby => "HOBBY",
VCardProperty::Interest => "INTEREST",
VCardProperty::OrgDirectory => "ORG-DIRECTORY",
VCardProperty::ContactUri => "CONTACT-URI",
VCardProperty::Created => "CREATED",
VCardProperty::Gramgender => "GRAMGENDER",
VCardProperty::Language => "LANGUAGE",
VCardProperty::Pronouns => "PRONOUNS",
VCardProperty::Socialprofile => "SOCIALPROFILE",
VCardProperty::Jsprop => "JSPROP",
VCardProperty::Begin => "BEGIN",
VCardProperty::End => "END",
VCardProperty::Other(ref s) => s,
}
}
pub(crate) fn default_types(&self) -> (ValueType, ValueSeparator) {
match self {
VCardProperty::Source => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Kind => (ValueType::Kind, ValueSeparator::None),
VCardProperty::Xml => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Fn => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::N => (
ValueType::Vcard(VCardValueType::Text),
ValueSeparator::Semicolon,
),
VCardProperty::Nickname => (
ValueType::Vcard(VCardValueType::Text),
ValueSeparator::Comma,
),
VCardProperty::Photo => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Bday => (
ValueType::Vcard(VCardValueType::DateAndOrTime),
ValueSeparator::None,
),
VCardProperty::Anniversary => (
ValueType::Vcard(VCardValueType::DateAndOrTime),
ValueSeparator::None,
),
VCardProperty::Gender => (ValueType::Sex, ValueSeparator::Semicolon),
VCardProperty::Adr => (
ValueType::Vcard(VCardValueType::Text),
ValueSeparator::Semicolon,
),
VCardProperty::Tel => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Email => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Impp => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Lang => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Tz => (
ValueType::Vcard(VCardValueType::UtcOffset),
ValueSeparator::None,
),
VCardProperty::Geo => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Title => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Role => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Logo => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Org => (
ValueType::Vcard(VCardValueType::Text),
ValueSeparator::Semicolon,
),
VCardProperty::Member => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Related => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Categories => {
(ValueType::Vcard(VCardValueType::Uri), ValueSeparator::Comma)
}
VCardProperty::Note => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Prodid => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Rev => (
ValueType::Vcard(VCardValueType::Timestamp),
ValueSeparator::None,
),
VCardProperty::Sound => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Uid => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Clientpidmap => (
ValueType::Vcard(VCardValueType::Text),
ValueSeparator::Semicolon,
),
VCardProperty::Url => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Version => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::None)
}
VCardProperty::Key => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Fburl => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Caladruri => {
(ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None)
}
VCardProperty::Caluri => (ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None),
VCardProperty::Birthplace => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::None)
}
VCardProperty::Deathplace => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::None)
}
VCardProperty::Deathdate => (
ValueType::Vcard(VCardValueType::DateAndOrTime),
ValueSeparator::None,
),
VCardProperty::Expertise => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::None)
}
VCardProperty::Hobby => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Interest => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::None)
}
VCardProperty::OrgDirectory => {
(ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None)
}
VCardProperty::ContactUri => {
(ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None)
}
VCardProperty::Created => (
ValueType::Vcard(VCardValueType::Timestamp),
ValueSeparator::None,
),
VCardProperty::Gramgender => (ValueType::GramGender, ValueSeparator::None),
VCardProperty::Language => (
ValueType::Vcard(VCardValueType::LanguageTag),
ValueSeparator::None,
),
VCardProperty::Pronouns => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::None)
}
VCardProperty::Socialprofile => {
(ValueType::Vcard(VCardValueType::Uri), ValueSeparator::None)
}
VCardProperty::Jsprop => (ValueType::Vcard(VCardValueType::Text), ValueSeparator::None),
VCardProperty::Other(_) => (
ValueType::Vcard(VCardValueType::Text),
ValueSeparator::Semicolon,
),
VCardProperty::Begin | VCardProperty::End => {
(ValueType::Vcard(VCardValueType::Text), ValueSeparator::Skip)
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(any(test, feature = "serde"), serde(tag = "type", content = "data"))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardValue {
Text(String),
Integer(i64),
Float(f64),
Boolean(bool),
PartialDateTime(PartialDateTime),
Binary(Data),
Sex(VCardSex),
GramGender(VCardGramGender),
Kind(VCardKind),
}
impl Eq for VCardValue {}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(any(test, feature = "serde"), serde(tag = "type", content = "data"))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardParameter {
Language(String), Value(Vec<VCardValueType>), Pref(u32), Altid(String), Pid(Vec<String>), Type(Vec<VCardType>), Mediatype(String), Calscale(CalendarScale), SortAs(String), Geo(String), Tz(String), Index(u32), Level(VCardLevel), Group(String), Cc(String), Author(String), AuthorName(String), Created(i64), Derived(bool), Label(String), Phonetic(VCardPhonetic), PropId(String), Script(String), ServiceType(String), Username(String), Jsptr(String), Other(Vec<String>),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardParameterName {
Language, Value, Pref, Altid, Pid, Type, Mediatype, Calscale, SortAs, Geo, Tz, Index, Level, Group, Cc, Author, AuthorName, Created, Derived, Label, Phonetic, PropId, Script, ServiceType, Username, Jsptr, Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(any(test, feature = "serde"), serde(tag = "type", content = "data"))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardValueType {
Boolean, Date, DateAndOrTime, DateTime, Float, Integer, LanguageTag, Text, Time, Timestamp, Uri, UtcOffset, Other(String),
}
impl VCardValueType {
pub fn as_str(&self) -> &str {
match self {
VCardValueType::Boolean => "BOOLEAN",
VCardValueType::Date => "DATE",
VCardValueType::DateAndOrTime => "DATE-AND-OR-TIME",
VCardValueType::DateTime => "DATE-TIME",
VCardValueType::Float => "FLOAT",
VCardValueType::Integer => "INTEGER",
VCardValueType::LanguageTag => "LANGUAGE-TAG",
VCardValueType::Text => "TEXT",
VCardValueType::Time => "TIME",
VCardValueType::Timestamp => "TIMESTAMP",
VCardValueType::Uri => "URI",
VCardValueType::UtcOffset => "UTC-OFFSET",
VCardValueType::Other(ref s) => s,
}
}
}
impl AsRef<str> for VCardValueType {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl From<Token<'_>> for VCardValueType {
fn from(token: Token<'_>) -> Self {
hashify::tiny_map_ignore_case!(token.text.as_ref(),
"BOOLEAN" => VCardValueType::Boolean,
"DATE" => VCardValueType::Date,
"DATE-AND-OR-TIME" => VCardValueType::DateAndOrTime,
"DATE-TIME" => VCardValueType::DateTime,
"FLOAT" => VCardValueType::Float,
"INTEGER" => VCardValueType::Integer,
"LANGUAGE-TAG" => VCardValueType::LanguageTag,
"TEXT" => VCardValueType::Text,
"TIME" => VCardValueType::Time,
"TIMESTAMP" => VCardValueType::Timestamp,
"URI" => VCardValueType::Uri,
"UTC-OFFSET" => VCardValueType::UtcOffset,
)
.unwrap_or_else(|| VCardValueType::Other(token.into_string()))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardLevel {
Beginner, Average, Expert, High, Medium, Low, }
impl TryFrom<&[u8]> for VCardLevel {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
hashify::tiny_map_ignore_case!(value,
"beginner" => VCardLevel::Beginner,
"average" => VCardLevel::Average,
"expert" => VCardLevel::Expert,
"high" => VCardLevel::High,
"medium" => VCardLevel::Medium,
"low" => VCardLevel::Low,
)
.ok_or(())
}
}
impl VCardLevel {
pub fn as_str(&self) -> &str {
match self {
VCardLevel::Beginner => "BEGINNER",
VCardLevel::Average => "AVERAGE",
VCardLevel::Expert => "EXPERT",
VCardLevel::High => "HIGH",
VCardLevel::Medium => "MEDIUM",
VCardLevel::Low => "LOW",
}
}
}
impl AsRef<str> for VCardLevel {
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(any(test, feature = "serde"), serde(tag = "type", content = "data"))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardPhonetic {
Ipa, Jyut, Piny, Script, Other(String),
}
impl From<Token<'_>> for VCardPhonetic {
fn from(token: Token<'_>) -> Self {
hashify::tiny_map_ignore_case!(token.text.as_ref(),
"ipa" => VCardPhonetic::Ipa,
"jyut" => VCardPhonetic::Jyut,
"piny" => VCardPhonetic::Piny,
"script" => VCardPhonetic::Script,
)
.unwrap_or_else(|| VCardPhonetic::Other(token.into_string()))
}
}
impl VCardPhonetic {
pub fn as_str(&self) -> &str {
match self {
VCardPhonetic::Ipa => "IPA",
VCardPhonetic::Jyut => "JYUT",
VCardPhonetic::Piny => "PINY",
VCardPhonetic::Script => "SCRIPT",
VCardPhonetic::Other(ref s) => s,
}
}
}
impl AsRef<str> for VCardPhonetic {
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(any(test, feature = "serde"), serde(tag = "type", content = "data"))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardType {
Work, Home, Billing, Delivery, Contact, Acquaintance, Friend, Met, CoWorker, Colleague, CoResident, Neighbor, Child, Parent, Sibling, Spouse, Kin, Muse, Crush, Date, Sweetheart, Me, Agent, Emergency, Text, Voice, Fax, Cell, Video, Pager, Textphone, MainNumber, Other(String),
}
impl TryFrom<&[u8]> for VCardType {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
hashify::tiny_map_ignore_case!(value,
"work" => VCardType::Work,
"home" => VCardType::Home,
"billing" => VCardType::Billing,
"delivery" => VCardType::Delivery,
"contact" => VCardType::Contact,
"acquaintance" => VCardType::Acquaintance,
"friend" => VCardType::Friend,
"met" => VCardType::Met,
"co-worker" => VCardType::CoWorker,
"colleague" => VCardType::Colleague,
"co-resident" => VCardType::CoResident,
"neighbor" => VCardType::Neighbor,
"child" => VCardType::Child,
"parent" => VCardType::Parent,
"sibling" => VCardType::Sibling,
"spouse" => VCardType::Spouse,
"kin" => VCardType::Kin,
"muse" => VCardType::Muse,
"crush" => VCardType::Crush,
"date" => VCardType::Date,
"sweetheart" => VCardType::Sweetheart,
"me" => VCardType::Me,
"agent" => VCardType::Agent,
"emergency" => VCardType::Emergency,
"text" => VCardType::Text,
"voice" => VCardType::Voice,
"fax" => VCardType::Fax,
"cell" => VCardType::Cell,
"video" => VCardType::Video,
"pager" => VCardType::Pager,
"textphone" => VCardType::Textphone,
"main-number" => VCardType::MainNumber,
)
.ok_or(())
}
}
impl VCardType {
pub fn as_str(&self) -> &str {
match self {
VCardType::Work => "WORK",
VCardType::Home => "HOME",
VCardType::Billing => "BILLING",
VCardType::Delivery => "DELIVERY",
VCardType::Contact => "CONTACT",
VCardType::Acquaintance => "ACQUAINTANCE",
VCardType::Friend => "FRIEND",
VCardType::Met => "MET",
VCardType::CoWorker => "CO-WORKER",
VCardType::Colleague => "COLLEAGUE",
VCardType::CoResident => "CO-RESIDENT",
VCardType::Neighbor => "NEIGHBOR",
VCardType::Child => "CHILD",
VCardType::Parent => "PARENT",
VCardType::Sibling => "SIBLING",
VCardType::Spouse => "SPOUSE",
VCardType::Kin => "KIN",
VCardType::Muse => "MUSE",
VCardType::Crush => "CRUSH",
VCardType::Date => "DATE",
VCardType::Sweetheart => "SWEETHEART",
VCardType::Me => "ME",
VCardType::Agent => "AGENT",
VCardType::Emergency => "EMERGENCY",
VCardType::Text => "TEXT",
VCardType::Voice => "VOICE",
VCardType::Fax => "FAX",
VCardType::Cell => "CELL",
VCardType::Video => "VIDEO",
VCardType::Pager => "PAGER",
VCardType::Textphone => "TEXTPHONE",
VCardType::MainNumber => "MAIN-NUMBER",
VCardType::Other(ref s) => s,
}
}
}
impl AsRef<str> for VCardType {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl From<Token<'_>> for VCardType {
fn from(token: Token<'_>) -> Self {
VCardType::try_from(token.text.as_ref())
.unwrap_or_else(|_| VCardType::Other(token.into_string()))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardGramGender {
Animate, Common, Feminine, Inanimate, Masculine, Neuter, }
impl TryFrom<&[u8]> for VCardGramGender {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
hashify::tiny_map_ignore_case!(value,
"animate" => VCardGramGender::Animate,
"common" => VCardGramGender::Common,
"feminine" => VCardGramGender::Feminine,
"inanimate" => VCardGramGender::Inanimate,
"masculine" => VCardGramGender::Masculine,
"neuter" => VCardGramGender::Neuter,
)
.ok_or(())
}
}
impl VCardGramGender {
pub fn as_str(&self) -> &str {
match self {
VCardGramGender::Animate => "ANIMATE",
VCardGramGender::Common => "COMMON",
VCardGramGender::Feminine => "FEMININE",
VCardGramGender::Inanimate => "INANIMATE",
VCardGramGender::Masculine => "MASCULINE",
VCardGramGender::Neuter => "NEUTER",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardSex {
Male,
Female,
Other,
NoneOrNotApplicable,
Unknown,
}
impl TryFrom<&[u8]> for VCardSex {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
hashify::tiny_map_ignore_case!(value,
"M" => VCardSex::Male,
"F" => VCardSex::Female,
"O" => VCardSex::Other,
"N" => VCardSex::NoneOrNotApplicable,
"U" => VCardSex::Unknown,
)
.ok_or(())
}
}
impl VCardSex {
pub fn as_str(&self) -> &str {
match self {
VCardSex::Male => "M",
VCardSex::Female => "F",
VCardSex::Other => "O",
VCardSex::NoneOrNotApplicable => "N",
VCardSex::Unknown => "U",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq), derive(Debug)))]
pub enum VCardKind {
Individual, Group, Org, Location, Application, Device, }
impl TryFrom<&[u8]> for VCardKind {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
hashify::tiny_map_ignore_case!(value,
"individual" => VCardKind::Individual,
"group" => VCardKind::Group,
"org" => VCardKind::Org,
"location" => VCardKind::Location,
"application" => VCardKind::Application,
"device" => VCardKind::Device,
)
.ok_or(())
}
}
impl VCardKind {
pub fn as_str(&self) -> &str {
match self {
VCardKind::Individual => "INDIVIDUAL",
VCardKind::Group => "GROUP",
VCardKind::Org => "ORG",
VCardKind::Location => "LOCATION",
VCardKind::Application => "APPLICATION",
VCardKind::Device => "DEVICE",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ValueSeparator {
None,
Comma,
Semicolon,
Skip,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ValueType {
Vcard(VCardValueType),
Kind,
Sex,
GramGender,
}
impl ValueType {
pub fn unwrap_vcard(self) -> VCardValueType {
match self {
ValueType::Vcard(v) => v,
_ => VCardValueType::Text,
}
}
}
impl VCard {
pub fn parse(value: impl AsRef<str>) -> Result<Self, Entry> {
let mut parser = Parser::new(value.as_ref());
match parser.entry() {
Entry::VCard(vcard) => Ok(vcard),
other => Err(other),
}
}
}