Skip to main content

ical/value/
binary.rs

1//! # Binary value
2//!
3//! The decoded binary value kind.
4//!
5//! Backs the binary-bearing properties (`ATTACH`, `IMAGE`, `STRUCTURED-DATA`)
6//! where the value is inline base64 rather than an external URI reference (the
7//! BINARY value, RFC 5545 3.3.1, carried with `ENCODING=BASE64`); a property
8//! referencing an external URI decodes to
9//! [`IcalUri`](crate::value::uri::IcalUri) instead. The form is told by the
10//! line's `VALUE` / `ENCODING` parameters, and the payload is kept verbatim
11//! (base64 is not 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 IcalBinary<'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 IcalBinary<'_> {
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            IcalBinary::Base64(data) => Some(BASE64_STANDARD.decode(data.as_bytes())),
35            IcalBinary::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::IcalBinary;
45
46    #[test]
47    fn decodes_inline_base64_but_not_a_uri() {
48        let inline = IcalBinary::Base64(Cow::Borrowed("Zm9v"));
49        assert_eq!(inline.decode_base64().unwrap().unwrap(), b"foo");
50
51        let reference = IcalBinary::Uri(Cow::Borrowed("http://example.com/p.png"));
52        assert!(reference.decode_base64().is_none());
53    }
54}