bson/raw/
array.rs

1use std::{borrow::Cow, convert::TryFrom};
2
3use serde::{ser::SerializeSeq, Deserialize, Serialize};
4
5use super::{
6    error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
7    serde::OwnedOrBorrowedRawArray,
8    Error,
9    RawBinaryRef,
10    RawBsonRef,
11    RawDocument,
12    RawIter,
13    RawRegexRef,
14    Result,
15};
16use crate::{
17    oid::ObjectId,
18    raw::RAW_ARRAY_NEWTYPE,
19    spec::ElementType,
20    Bson,
21    DateTime,
22    RawArrayBuf,
23    Timestamp,
24};
25
26/// A slice of a BSON document containing a BSON array value (akin to [`std::str`]). This can be
27/// retrieved from a [`RawDocument`] via [`RawDocument::get`].
28///
29/// This is an _unsized_ type, meaning that it must always be used behind a pointer like `&`.
30///
31/// Accessing elements within a [`RawArray`] is similar to element access in [`crate::Document`],
32/// but because the contents are parsed during iteration instead of at creation time, format errors
33/// can happen at any time during use.
34///
35/// Iterating over a [`RawArray`] yields either an error or a value that borrows from the
36/// original document without making any additional allocations.
37///
38/// ```
39/// use bson::{doc, raw::RawDocument};
40///
41/// let doc = doc! {
42///     "x": [1, true, "two", 5.5]
43/// };
44/// let bytes = bson::to_vec(&doc)?;
45///
46/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?;
47/// let rawarray = rawdoc.get_array("x")?;
48///
49/// for v in rawarray {
50///     println!("{:?}", v?);
51/// }
52/// # Ok::<(), Box<dyn std::error::Error>>(())
53/// ```
54///
55/// Individual elements can be accessed using [`RawArray::get`] or any of
56/// the type-specific getters, such as [`RawArray::get_object_id`] or
57/// [`RawArray::get_str`]. Note that accessing elements is an O(N) operation, as it
58/// requires iterating through the array from the beginning to find the requested index.
59///
60/// ```
61/// # use bson::raw::{ValueAccessError};
62/// use bson::{doc, raw::RawDocument};
63///
64/// let doc = doc! {
65///     "x": [1, true, "two", 5.5]
66/// };
67/// let bytes = bson::to_vec(&doc)?;
68///
69/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?;
70/// let rawarray = rawdoc.get_array("x")?;
71///
72/// assert_eq!(rawarray.get_bool(1)?, true);
73/// # Ok::<(), Box<dyn std::error::Error>>(())
74/// ```
75#[derive(PartialEq)]
76#[repr(transparent)]
77pub struct RawArray {
78    pub(crate) doc: RawDocument,
79}
80
81impl RawArray {
82    pub(crate) fn from_doc(doc: &RawDocument) -> &RawArray {
83        // SAFETY:
84        //
85        // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is
86        // null, dangling, or misaligned. We know the pointer is not null or dangling due to the
87        // fact that it's created by a safe reference. Converting &RawDocument to *const
88        // RawDocument will be properly aligned due to them being references to the same type,
89        // and converting *const RawDocument to *const RawArray is aligned due to the fact that
90        // the only field in a RawArray is a RawDocument, meaning the structs are represented
91        // identically at the byte level.
92        unsafe { &*(doc as *const RawDocument as *const RawArray) }
93    }
94
95    pub(crate) fn as_doc(&self) -> &RawDocument {
96        &self.doc
97    }
98
99    /// Convert this borrowed [`RawArray`] into an owned [`RawArrayBuf`].
100    ///
101    /// This involves a traversal of the array to count the values.
102    pub fn to_raw_array_buf(&self) -> RawArrayBuf {
103        RawArrayBuf::from_raw_document_buf(self.doc.to_raw_document_buf())
104    }
105
106    /// Gets a reference to the value at the given index.
107    pub fn get(&self, index: usize) -> Result<Option<RawBsonRef<'_>>> {
108        self.into_iter().nth(index).transpose()
109    }
110
111    fn get_with<'a, T>(
112        &'a self,
113        index: usize,
114        expected_type: ElementType,
115        f: impl FnOnce(RawBsonRef<'a>) -> Option<T>,
116    ) -> ValueAccessResult<T> {
117        let bson = self
118            .get(index)
119            .map_err(|e| ValueAccessError {
120                key: index.to_string(),
121                kind: ValueAccessErrorKind::InvalidBson(e),
122            })?
123            .ok_or(ValueAccessError {
124                key: index.to_string(),
125                kind: ValueAccessErrorKind::NotPresent,
126            })?;
127        match f(bson) {
128            Some(t) => Ok(t),
129            None => Err(ValueAccessError {
130                key: index.to_string(),
131                kind: ValueAccessErrorKind::UnexpectedType {
132                    expected: expected_type,
133                    actual: bson.element_type(),
134                },
135            }),
136        }
137    }
138
139    /// Gets the BSON double at the given index or returns an error if the value at that index isn't
140    /// a double.
141    pub fn get_f64(&self, index: usize) -> ValueAccessResult<f64> {
142        self.get_with(index, ElementType::Double, RawBsonRef::as_f64)
143    }
144
145    /// Gets a reference to the string at the given index or returns an error if the
146    /// value at that index isn't a string.
147    pub fn get_str(&self, index: usize) -> ValueAccessResult<&str> {
148        self.get_with(index, ElementType::String, RawBsonRef::as_str)
149    }
150
151    /// Gets a reference to the document at the given index or returns an error if the
152    /// value at that index isn't a document.
153    pub fn get_document(&self, index: usize) -> ValueAccessResult<&RawDocument> {
154        self.get_with(
155            index,
156            ElementType::EmbeddedDocument,
157            RawBsonRef::as_document,
158        )
159    }
160
161    /// Gets a reference to the array at the given index or returns an error if the
162    /// value at that index isn't a array.
163    pub fn get_array(&self, index: usize) -> ValueAccessResult<&RawArray> {
164        self.get_with(index, ElementType::Array, RawBsonRef::as_array)
165    }
166
167    /// Gets a reference to the BSON binary value at the given index or returns an error if the
168    /// value at that index isn't a binary.
169    pub fn get_binary(&self, index: usize) -> ValueAccessResult<RawBinaryRef<'_>> {
170        self.get_with(index, ElementType::Binary, RawBsonRef::as_binary)
171    }
172
173    /// Gets the ObjectId at the given index or returns an error if the value at that index isn't an
174    /// ObjectId.
175    pub fn get_object_id(&self, index: usize) -> ValueAccessResult<ObjectId> {
176        self.get_with(index, ElementType::ObjectId, RawBsonRef::as_object_id)
177    }
178
179    /// Gets the boolean at the given index or returns an error if the value at that index isn't a
180    /// boolean.
181    pub fn get_bool(&self, index: usize) -> ValueAccessResult<bool> {
182        self.get_with(index, ElementType::Boolean, RawBsonRef::as_bool)
183    }
184
185    /// Gets the DateTime at the given index or returns an error if the value at that index isn't a
186    /// DateTime.
187    pub fn get_datetime(&self, index: usize) -> ValueAccessResult<DateTime> {
188        self.get_with(index, ElementType::DateTime, RawBsonRef::as_datetime)
189    }
190
191    /// Gets a reference to the BSON regex at the given index or returns an error if the
192    /// value at that index isn't a regex.
193    pub fn get_regex(&self, index: usize) -> ValueAccessResult<RawRegexRef<'_>> {
194        self.get_with(index, ElementType::RegularExpression, RawBsonRef::as_regex)
195    }
196
197    /// Gets a reference to the BSON timestamp at the given index or returns an error if the
198    /// value at that index isn't a timestamp.
199    pub fn get_timestamp(&self, index: usize) -> ValueAccessResult<Timestamp> {
200        self.get_with(index, ElementType::Timestamp, RawBsonRef::as_timestamp)
201    }
202
203    /// Gets the BSON int32 at the given index or returns an error if the value at that index isn't
204    /// a 32-bit integer.
205    pub fn get_i32(&self, index: usize) -> ValueAccessResult<i32> {
206        self.get_with(index, ElementType::Int32, RawBsonRef::as_i32)
207    }
208
209    /// Gets BSON int64 at the given index or returns an error if the value at that index isn't a
210    /// 64-bit integer.
211    pub fn get_i64(&self, index: usize) -> ValueAccessResult<i64> {
212        self.get_with(index, ElementType::Int64, RawBsonRef::as_i64)
213    }
214
215    /// Gets a reference to the raw bytes of the [`RawArray`].
216    pub fn as_bytes(&self) -> &[u8] {
217        self.doc.as_bytes()
218    }
219
220    /// Whether this array contains any elements or not.
221    pub fn is_empty(&self) -> bool {
222        self.doc.is_empty()
223    }
224}
225
226impl std::fmt::Debug for RawArray {
227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228        f.debug_struct("RawArray")
229            .field("data", &hex::encode(self.doc.as_bytes()))
230            .finish()
231    }
232}
233
234impl TryFrom<&RawArray> for Vec<Bson> {
235    type Error = Error;
236
237    fn try_from(arr: &RawArray) -> Result<Vec<Bson>> {
238        arr.into_iter()
239            .map(|result| {
240                let rawbson = result?;
241                Bson::try_from(rawbson)
242            })
243            .collect()
244    }
245}
246
247impl ToOwned for RawArray {
248    type Owned = RawArrayBuf;
249
250    fn to_owned(&self) -> Self::Owned {
251        self.to_raw_array_buf()
252    }
253}
254
255impl<'a> From<&'a RawArray> for Cow<'a, RawArray> {
256    fn from(rdr: &'a RawArray) -> Self {
257        Cow::Borrowed(rdr)
258    }
259}
260
261impl<'a> IntoIterator for &'a RawArray {
262    type IntoIter = RawArrayIter<'a>;
263    type Item = Result<RawBsonRef<'a>>;
264
265    fn into_iter(self) -> RawArrayIter<'a> {
266        RawArrayIter {
267            inner: RawIter::new(&self.doc),
268        }
269    }
270}
271
272/// An iterator over borrowed raw BSON array values.
273pub struct RawArrayIter<'a> {
274    inner: RawIter<'a>,
275}
276
277impl<'a> Iterator for RawArrayIter<'a> {
278    type Item = Result<RawBsonRef<'a>>;
279
280    fn next(&mut self) -> Option<Result<RawBsonRef<'a>>> {
281        match self.inner.next() {
282            Some(Ok(elem)) => match elem.value() {
283                Ok(value) => Some(Ok(value)),
284                Err(e) => Some(Err(e)),
285            },
286            Some(Err(e)) => Some(Err(e)),
287            None => None,
288        }
289    }
290}
291
292impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray {
293    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
294    where
295        D: serde::Deserializer<'de>,
296    {
297        match OwnedOrBorrowedRawArray::deserialize(deserializer)? {
298            OwnedOrBorrowedRawArray::Borrowed(b) => Ok(b),
299            o => Err(serde::de::Error::custom(format!(
300                "expected borrowed raw array, instead got owned {:?}",
301                o
302            ))),
303        }
304    }
305}
306
307impl Serialize for &RawArray {
308    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
309    where
310        S: serde::Serializer,
311    {
312        struct SeqSerializer<'a>(&'a RawArray);
313
314        impl Serialize for SeqSerializer<'_> {
315            fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
316            where
317                S: serde::Serializer,
318            {
319                if serializer.is_human_readable() {
320                    let mut seq = serializer.serialize_seq(None)?;
321                    for v in self.0 {
322                        let v = v.map_err(serde::ser::Error::custom)?;
323                        seq.serialize_element(&v)?;
324                    }
325                    seq.end()
326                } else {
327                    serializer.serialize_bytes(self.0.as_bytes())
328                }
329            }
330        }
331
332        serializer.serialize_newtype_struct(RAW_ARRAY_NEWTYPE, &SeqSerializer(self))
333    }
334}