use std::fmt::{Display, Formatter};
use crate::constants::ValueName;
use crate::vcard::value::value_boolean::ValueBooleanData;
use crate::vcard::value::value_clientpidmap::ValueClientPidMapData;
use crate::vcard::value::value_date::ValueDateData;
use crate::vcard::value::value_float::ValueFloatData;
use crate::vcard::value::value_integer::ValueIntegerData;
use crate::vcard::value::value_languagetag::ValueLanguageTagData;
use crate::vcard::value::value_listcomponent::ValueListComponentData;
use crate::vcard::value::value_pid::ValuePidData;
use crate::vcard::value::value_text::ValueTextData;
use crate::vcard::value::value_textlist::ValueTextListData;
use crate::vcard::value::value_timestamp::ValueTimestampData;
use crate::vcard::value::value_uri::ValueUriData;
use crate::vcard::value::value_utcoffset::ValueUtcOffsetData;
use crate::vcard::value::Value::{ValueBoolean, ValueClientPidMap, ValueDate, ValueFloat, ValueInteger, ValueLanguageTag, ValueListComponent, ValuePid, ValueText, ValueTextList, ValueTimestamp, ValueUri, ValueUtcOffset};
use crate::VcardError;
pub mod value_boolean;
pub mod value_clientpidmap;
pub mod value_date;
pub mod value_float;
pub mod value_integer;
pub mod value_languagetag;
pub mod value_listcomponent;
pub mod value_pid;
pub mod value_text;
pub mod value_textlist;
pub mod value_timestamp;
pub mod value_uri;
pub mod value_utcoffset;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
ValueBoolean(ValueBooleanData),
ValueClientPidMap(ValueClientPidMapData),
ValueDate(ValueDateData),
ValueFloat(ValueFloatData),
ValueInteger(ValueIntegerData),
ValueLanguageTag(ValueLanguageTagData),
ValueListComponent(ValueListComponentData),
ValuePid(ValuePidData),
ValueText(ValueTextData),
ValueTextList(ValueTextListData),
ValueTimestamp(ValueTimestampData),
ValueUri(ValueUriData),
ValueUtcOffset(ValueUtcOffsetData),
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ValueBoolean(data) => data.fmt(f),
ValueClientPidMap(data) => data.fmt(f),
ValueDate(data) => data.fmt(f),
ValueFloat(data) => data.fmt(f),
ValueInteger(data) => data.fmt(f),
ValueLanguageTag(data) => data.fmt(f),
ValueListComponent(data) => data.fmt(f),
ValuePid(data) => data.fmt(f),
ValueText(data) => data.fmt(f),
ValueTextList(data) => data.fmt(f),
ValueTimestamp(data) => data.fmt(f),
ValueUri(data) => data.fmt(f),
ValueUtcOffset(data) => data.fmt(f),
}
}
}
impl TryFrom<(&str, &str)> for Value {
type Error = VcardError;
fn try_from((name, str): (&str, &str)) -> Result<Self, Self::Error> {
match name.to_uppercase().as_str() {
ValueName::BOOLEAN => Ok(ValueBoolean(ValueBooleanData::try_from(str)?)),
ValueName::CLIENTPIDMAP => Ok(ValueClientPidMap(ValueClientPidMapData::try_from(str)?)),
ValueName::DATE => Ok(ValueDate(ValueDateData::try_from(str)?)),
ValueName::FLOAT => Ok(ValueFloat(ValueFloatData::try_from(str)?)),
ValueName::INTEGER => Ok(ValueInteger(ValueIntegerData::try_from(str)?)),
ValueName::LANGUAGE_TAG => Ok(ValueLanguageTag(ValueLanguageTagData::try_from(str)?)),
ValueName::LISTCOMPONENT => Ok(ValueListComponent(ValueListComponentData::try_from((str, ';', ','))?)),
ValueName::PID => Ok(ValuePid(ValuePidData::try_from(str)?)),
ValueName::TEXT => Ok(ValueText(ValueTextData::from(str))),
ValueName::TEXTLIST => Ok(ValueTextList(ValueTextListData::from((str, ',')))),
ValueName::TIMESTAMP => Ok(ValueTimestamp(ValueTimestampData::try_from(str)?)),
ValueName::URI => Ok(ValueUri(ValueUriData::try_from(str)?)),
ValueName::UTCOFFSET => Ok(ValueUtcOffset(ValueUtcOffsetData::try_from(str)?)),
_ => Err(VcardError::ValueNameUnknown(name.to_string())),
}
}
}
impl From<ValueBooleanData> for Value {
fn from(data: ValueBooleanData) -> Self {
ValueBoolean(data)
}
}
impl From<ValueClientPidMapData> for Value {
fn from(data: ValueClientPidMapData) -> Self {
ValueClientPidMap(data)
}
}
impl From<ValueDateData> for Value {
fn from(data: ValueDateData) -> Self {
ValueDate(data)
}
}
impl From<ValueFloatData> for Value {
fn from(data: ValueFloatData) -> Self {
ValueFloat(data)
}
}
impl From<ValueIntegerData> for Value {
fn from(data: ValueIntegerData) -> Self {
ValueInteger(data)
}
}
impl From<ValueLanguageTagData> for Value {
fn from(data: ValueLanguageTagData) -> Self {
ValueLanguageTag(data)
}
}
impl From<ValueListComponentData> for Value {
fn from(data: ValueListComponentData) -> Self {
ValueListComponent(data)
}
}
impl From<ValuePidData> for Value {
fn from(data: ValuePidData) -> Self {
ValuePid(data)
}
}
impl From<ValueTextData> for Value {
fn from(data: ValueTextData) -> Self {
ValueText(data)
}
}
impl From<ValueTextListData> for Value {
fn from(data: ValueTextListData) -> Self {
ValueTextList(data)
}
}
impl From<ValueTimestampData> for Value {
fn from(data: ValueTimestampData) -> Self {
ValueTimestamp(data)
}
}
impl From<ValueUriData> for Value {
fn from(data: ValueUriData) -> Self {
ValueUri(data)
}
}
impl From<ValueUtcOffsetData> for Value {
fn from(data: ValueUtcOffsetData) -> Self {
ValueUtcOffset(data)
}
}
#[cfg(test)]
mod tests {
use crate::vcard::value::value_listcomponent::ValueListComponentData;
use crate::vcard::value::value_textlist::ValueTextListData;
#[test]
fn util_parse_textlist_value() {
assert_eq!(ValueTextListData::from(("", ';')).to_string(), "");
assert_eq!(ValueTextListData::from(("A", ';')).to_string(), "A");
assert_eq!(ValueTextListData::from((";", ';')).to_string(), ";");
assert_eq!(ValueTextListData::from(("FOO;", ';')).to_string(), "FOO;");
assert_eq!(ValueTextListData::from((";BAR", ';')).to_string(), ";BAR");
assert_eq!(ValueTextListData::from(("FOO;BAR", ';')).to_string(), "FOO;BAR");
assert_eq!(ValueTextListData::from(("FOO;BAR;AGAIN", ';')).to_string(), "FOO;BAR;AGAIN");
assert_eq!(ValueTextListData::from(("FOO\\;TEST;BAR", ';')).to_string(), "FOO\\;TEST;BAR");
assert_eq!(ValueTextListData::from(("FOO\\;TEST;BAR\\;TEST", ';')).to_string(), "FOO\\;TEST;BAR\\;TEST");
}
#[test]
fn util_parse_textlist_compound_value() {
assert_eq!(ValueListComponentData::try_from(("", ';', ',')).unwrap().to_string(), "");
assert_eq!(ValueListComponentData::try_from(("A", ';', ',')).unwrap().to_string(), "A");
assert_eq!(ValueListComponentData::try_from((";", ';', ',')).unwrap().to_string(), ";");
assert_eq!(ValueListComponentData::try_from(("FOO;", ';', ',')).unwrap().to_string(), "FOO;");
assert_eq!(ValueListComponentData::try_from((";BAR", ';', ',')).unwrap().to_string(), ";BAR");
assert_eq!(ValueListComponentData::try_from(("FOO;BAR", ';', ',')).unwrap().to_string(), "FOO;BAR");
assert_eq!(ValueListComponentData::try_from(("FOO;BAR;AGAIN", ';', ',')).unwrap().to_string(), "FOO;BAR;AGAIN");
assert_eq!(ValueListComponentData::try_from((",", ';', ',')).unwrap().to_string(), ",");
assert_eq!(ValueListComponentData::try_from((",;", ';', ',')).unwrap().to_string(), ",;");
assert_eq!(ValueListComponentData::try_from((",;,", ';', ',')).unwrap().to_string(), ",;,");
assert_eq!(ValueListComponentData::try_from((";,", ';', ',')).unwrap().to_string(), ";,");
assert_eq!(ValueListComponentData::try_from(("A,;", ';', ',')).unwrap().to_string(), "A,;");
assert_eq!(ValueListComponentData::try_from((",B;", ';', ',')).unwrap().to_string(), ",B;");
assert_eq!(ValueListComponentData::try_from(("A,B;", ';', ',')).unwrap().to_string(), "A,B;");
assert_eq!(ValueListComponentData::try_from((";C,", ';', ',')).unwrap().to_string(), ";C,");
assert_eq!(ValueListComponentData::try_from((";,D", ';', ',')).unwrap().to_string(), ";,D");
assert_eq!(ValueListComponentData::try_from((";C,D", ';', ',')).unwrap().to_string(), ";C,D");
assert_eq!(ValueListComponentData::try_from(("A,B;C", ';', ',')).unwrap().to_string(), "A,B;C");
assert_eq!(ValueListComponentData::try_from(("A,B;C,D", ';', ',')).unwrap().to_string(), "A,B;C,D");
assert_eq!(ValueListComponentData::try_from(("FOO,BAR;FOO,BAR", ';', ',')).unwrap().to_string(), "FOO,BAR;FOO,BAR");
}
}