use crate::{
param::VcardParamKind,
prop::VcardPropKind,
tree::{
cst::VcardCst,
error::VcardParseError,
line::VcardLine,
prop::{cardinality::VcardPropCardinality, lens::VcardPropLens, spec::VcardPropSpec},
value::cursor::VcardValueCursor,
},
value::text::VcardText,
version::VcardVersion,
};
pub struct AGENT;
impl VcardCst<'_> {
pub fn agent(&self) -> Option<Result<VcardCst<'static>, VcardParseError>> {
let text = self.prop::<AGENT>()?;
let bytes = text.0.into_owned().into_bytes();
let (first, _rest) = VcardLine::take(&bytes).ok()?;
if !first.name.get().eq_ignore_ascii_case("BEGIN") {
return None;
}
Some(VcardCst::parse(&bytes).map(VcardCst::into_static))
}
}
impl VcardPropLens for AGENT {
type Target<'v> = VcardText<'v>;
type Cursor<'c, 'a>
= VcardValueCursor<'c, 'a>
where
'a: 'c;
fn cursor<'c, 'a>(line: &'c mut VcardLine<'a>) -> VcardValueCursor<'c, 'a> {
VcardValueCursor { line }
}
}
impl VcardPropSpec for AGENT {
const KIND: VcardPropKind = VcardPropKind::Agent;
fn allowed_versions() -> &'static [VcardVersion] {
&[VcardVersion::V2_1, VcardVersion::V3_0]
}
fn cardinality(_version: VcardVersion) -> VcardPropCardinality {
VcardPropCardinality::AtMostOne
}
fn allowed_params(_version: VcardVersion) -> &'static [VcardParamKind] {
&[
VcardParamKind::Type,
VcardParamKind::Language,
VcardParamKind::Encoding,
VcardParamKind::Charset,
VcardParamKind::Value,
]
}
}
#[cfg(test)]
mod tests {
use crate::tree::{cst::VcardCst, prop::r#fn::FN};
#[test]
fn parses_the_embedded_agent_card() {
let card = VcardCst::parse(concat!(
"BEGIN:VCARD\r\n",
"VERSION:3.0\r\n",
"FN:Boss\r\n",
"AGENT:BEGIN:VCARD\\nVERSION:3.0\\nFN:Susan Thomas\\nEND:VCARD\\n\r\n",
"END:VCARD\r\n",
))
.unwrap();
let agent = card.agent().expect("an AGENT property").expect("parses");
assert_eq!(agent.prop::<FN>().unwrap().0, "Susan Thomas");
}
#[test]
fn returns_none_when_agent_is_a_uri_reference() {
let card = VcardCst::parse(concat!(
"BEGIN:VCARD\r\n",
"VERSION:3.0\r\n",
"AGENT;VALUE=uri:CID:JQPUBLIC.part3.960129T083020.xyzMail@example.com\r\n",
"END:VCARD\r\n",
))
.unwrap();
assert!(card.agent().is_none());
}
}