bson/
binary.rs

1//! Contains functionality related to BSON binary values.
2
3mod vector;
4
5use std::fmt::{self, Display};
6
7use crate::{
8    base64,
9    error::{Error, Result},
10    spec::BinarySubtype,
11    RawBinaryRef,
12};
13
14pub use vector::{PackedBitVector, Vector};
15
16/// Represents a BSON binary value.
17#[derive(Debug, Clone, Eq, PartialEq, Hash)]
18pub struct Binary {
19    /// The subtype of the bytes.
20    pub subtype: BinarySubtype,
21
22    /// The binary bytes.
23    pub bytes: Vec<u8>,
24}
25
26impl Display for Binary {
27    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
28        write!(
29            fmt,
30            "Binary({:#x}, {})",
31            u8::from(self.subtype),
32            base64::encode(&self.bytes)
33        )
34    }
35}
36
37impl Binary {
38    /// Creates a [`Binary`] from a base64 string and optional [`BinarySubtype`]. If the
39    /// `subtype` argument is [`None`], the [`Binary`] constructed will default to
40    /// [`BinarySubtype::Generic`].
41    ///
42    /// ```rust
43    /// # use bson::{Binary, error::Result};
44    /// # fn example() -> Result<()> {
45    /// let input = base64::encode("hello");
46    /// let binary = Binary::from_base64(input, None)?;
47    /// println!("{:?}", binary);
48    /// // binary: Binary { subtype: Generic, bytes: [104, 101, 108, 108, 111] }
49    /// # Ok(())
50    /// # }
51    /// ```
52    pub fn from_base64(
53        input: impl AsRef<str>,
54        subtype: impl Into<Option<BinarySubtype>>,
55    ) -> Result<Self> {
56        let bytes = base64::decode(input.as_ref()).map_err(Error::binary)?;
57        let subtype = match subtype.into() {
58            Some(s) => s,
59            None => BinarySubtype::Generic,
60        };
61        Ok(Binary { subtype, bytes })
62    }
63
64    #[cfg(feature = "serde")]
65    pub(crate) fn from_extended_doc(doc: &crate::Document) -> Option<Self> {
66        use std::convert::TryFrom;
67
68        let binary_doc = doc.get_document("$binary").ok()?;
69
70        if let Ok(bytes) = binary_doc.get_str("base64") {
71            let bytes = base64::decode(bytes).ok()?;
72            let subtype = binary_doc.get_str("subType").ok()?;
73            let subtype = hex::decode(subtype).ok()?;
74            if subtype.len() == 1 {
75                Some(Self {
76                    bytes,
77                    subtype: subtype[0].into(),
78                })
79            } else {
80                None
81            }
82        } else {
83            // in non-human-readable mode, RawBinary will serialize as
84            // { "$binary": { "bytes": <bytes>, "subType": <i32> } };
85            let binary = binary_doc.get_binary_generic("bytes").ok()?;
86            let subtype = binary_doc.get_i32("subType").ok()?;
87
88            Some(Self {
89                bytes: binary.clone(),
90                subtype: u8::try_from(subtype).ok()?.into(),
91            })
92        }
93    }
94
95    /// Borrow the contents as a [`RawBinaryRef`].
96    pub fn as_raw_binary(&self) -> RawBinaryRef<'_> {
97        RawBinaryRef {
98            bytes: self.bytes.as_slice(),
99            subtype: self.subtype,
100        }
101    }
102}