Coverage Report

Created: 2025-12-14 06:39

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