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
7//! (the BINARY value, RFC 5545 3.3.1, carried with `ENCODING=BASE64`).
8//!
9//! A property referencing an external URI decodes to
10//! [`IcalUri`](crate::value::uri::IcalUri) instead. The form is told by the
11//! line's `VALUE` / `ENCODING` parameters, and the payload is kept verbatim
12//! (base64 is not decoded to bytes).
13
14use alloc::borrow::Cow;
15#[cfg(feature = "base64")]
16use alloc::vec::Vec;
17
18/// A decoded binary value: an external URI reference, or inline base64 kept as
19/// its raw text.
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub enum IcalBinary<'a> {
22 /// An external URI reference.
23 Uri(Cow<'a, str>),
24 /// Inline base64 data, kept verbatim (not decoded to bytes).
25 Base64(Cow<'a, str>),
26}
27
28#[cfg(feature = "base64")]
29impl IcalBinary<'_> {
30 /// Decode the inline [`Base64`](Self::Base64) payload to raw bytes; `None`
31 /// for a [`Uri`](Self::Uri) reference, which embeds no data. Requires the
32 /// `base64` feature.
33 pub fn decode_base64(&self) -> Option<Result<Vec<u8>, base64::DecodeError>> {
34 use base64::prelude::{BASE64_STANDARD, Engine};
35
36 match self {
37 IcalBinary::Base64(data) => Some(BASE64_STANDARD.decode(data.as_bytes())),
38 IcalBinary::Uri(_) => None,
39 }
40 }
41}
42
43#[cfg(all(test, feature = "base64"))]
44mod tests {
45 use alloc::borrow::Cow;
46
47 use crate::value::binary::IcalBinary;
48
49 #[test]
50 fn decodes_inline_base64_but_not_a_uri() {
51 let inline = IcalBinary::Base64(Cow::Borrowed("Zm9v"));
52 assert_eq!(inline.decode_base64().unwrap().unwrap(), b"foo");
53
54 let reference = IcalBinary::Uri(Cow::Borrowed("http://example.com/p.png"));
55 assert!(reference.decode_base64().is_none());
56 }
57}