vcard/value/binary.rs
1//! # Binary value
2//!
3//! The decoded binary value kind.
4//!
5//! Backs the binary-bearing properties (`PHOTO`, `LOGO`, `SOUND`, `KEY`) in
6//! vCard 2.1 and 3.0, where the value is either an external URI reference or
7//! inline base64 (the URI/binary value, RFC 6350 6.9). vCard 4.0 carries these
8//! as `data:` URIs instead, decoded to
9//! [`VcardUri`](crate::value::uri::VcardUri). The form is told by the line's
10//! `VALUE` / `ENCODING` parameters; the payload is kept verbatim (base64 is not
11//! decoded to bytes).
12
13use alloc::borrow::Cow;
14
15/// A decoded binary value: an external URI reference, or inline base64 kept as
16/// its raw text.
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub enum VcardBinary<'a> {
19 /// An external URI reference.
20 Uri(Cow<'a, str>),
21 /// Inline base64 data, kept verbatim (not decoded to bytes).
22 Base64(Cow<'a, str>),
23}
24
25#[cfg(feature = "base64")]
26impl VcardBinary<'_> {
27 /// Decode the inline [`Base64`](Self::Base64) payload to raw bytes; `None`
28 /// for a [`Uri`](Self::Uri) reference, which embeds no data. Requires the
29 /// `base64` feature.
30 pub fn decode_base64(&self) -> Option<Result<alloc::vec::Vec<u8>, base64::DecodeError>> {
31 use base64::prelude::{BASE64_STANDARD, Engine};
32
33 match self {
34 VcardBinary::Base64(data) => Some(BASE64_STANDARD.decode(data.as_bytes())),
35 VcardBinary::Uri(_) => None,
36 }
37 }
38}
39
40#[cfg(all(test, feature = "base64"))]
41mod tests {
42 use alloc::borrow::Cow;
43
44 use crate::value::binary::VcardBinary;
45
46 #[test]
47 fn decodes_inline_base64_but_not_a_uri() {
48 let inline = VcardBinary::Base64(Cow::Borrowed("Zm9v"));
49 assert_eq!(inline.decode_base64().unwrap().unwrap(), b"foo");
50
51 let reference = VcardBinary::Uri(Cow::Borrowed("http://example.com/p.png"));
52 assert!(reference.decode_base64().is_none());
53 }
54}