Coverage Report

Created: 2025-09-05 06:11

/src/bson-rust/src/raw/document.rs
Line
Count
Source (jump to first uncovered line)
1
use std::{
2
    borrow::Cow,
3
    convert::{TryFrom, TryInto},
4
};
5
6
use crate::{
7
    error::{Error, Result},
8
    raw::CStr,
9
    Bson,
10
    DateTime,
11
    JavaScriptCodeWithScope,
12
    RawBson,
13
    RawJavaScriptCodeWithScope,
14
    Timestamp,
15
    Utf8Lossy,
16
};
17
18
use super::{
19
    i32_from_slice,
20
    iter::Iter,
21
    try_to_str,
22
    Error as RawError,
23
    RawArray,
24
    RawBinaryRef,
25
    RawBsonRef,
26
    RawDocumentBuf,
27
    RawIter,
28
    RawRegexRef,
29
    Result as RawResult,
30
    MIN_BSON_DOCUMENT_SIZE,
31
};
32
use crate::{oid::ObjectId, spec::ElementType, Document};
33
34
/// A slice of a BSON document (akin to [`std::str`]). This can be created from a
35
/// [`RawDocumentBuf`] or any type that contains valid BSON data, including static binary literals,
36
/// [`Vec<u8>`](std::vec::Vec), or arrays.
37
///
38
/// This is an _unsized_ type, meaning that it must always be used behind a pointer like `&`. For an
39
/// owned version of this type, see [`RawDocumentBuf`].
40
///
41
/// Accessing elements within a [`RawDocument`] is similar to element access in [`crate::Document`],
42
/// but because the contents are parsed during iteration instead of at creation time, format errors
43
/// can happen at any time during use.
44
///
45
/// Iterating over a [`RawDocument`] yields either an error or a key-value pair that borrows from
46
/// the original document without making any additional allocations.
47
/// ```
48
/// # use bson::error::Error;
49
/// use bson::raw::RawDocument;
50
///
51
/// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?;
52
/// let mut iter = doc.into_iter();
53
/// let (key, value) = iter.next().unwrap()?;
54
/// assert_eq!(key, "hi");
55
/// assert_eq!(value.as_str(), Some("y'all"));
56
/// assert!(iter.next().is_none());
57
/// # Ok::<(), Error>(())
58
/// ```
59
///
60
/// Individual elements can be accessed using [`RawDocument::get`] or any of
61
/// the type-specific getters, such as [`RawDocument::get_object_id`] or
62
/// [`RawDocument::get_str`]. Note that accessing elements is an O(N) operation, as it
63
/// requires iterating through the document from the beginning to find the requested key.
64
///
65
/// ```
66
/// use bson::raw::RawDocument;
67
///
68
/// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?;
69
/// assert_eq!(doc.get_str("hi")?, "y'all");
70
/// # Ok::<(), Box<dyn std::error::Error>>(())
71
/// ```
72
#[derive(PartialEq)]
73
#[repr(transparent)]
74
pub struct RawDocument {
75
    data: [u8],
76
}
77
78
impl RawDocument {
79
    /// Constructs a new [`RawDocument`], validating _only_ the
80
    /// following invariants:
81
    ///   * `data` is at least five bytes long (the minimum for a valid BSON document)
82
    ///   * the initial four bytes of `data` accurately represent the length of the bytes as
83
    ///     required by the BSON spec.
84
    ///   * the last byte of `data` is a 0
85
    ///
86
    /// Note that the internal structure of the bytes representing the
87
    /// BSON elements is _not_ validated at all by this method. If the
88
    /// bytes do not conform to the BSON spec, then method calls on
89
    /// the [`RawDocument`] will return Errors where appropriate.
90
    ///
91
    /// ```
92
    /// use bson::raw::RawDocument;
93
    ///
94
    /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?;
95
    /// # Ok::<(), bson::error::Error>(())
96
    /// ```
97
896k
    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
98
896k
        let data = data.as_ref();
99
896k
100
896k
        if data.len() < 5 {
101
25.4k
            return Err(Error::malformed_bytes("document too short"));
102
871k
        }
103
104
871k
        let length = i32_from_slice(data)?;
105
106
871k
        if data.len() as i32 != length {
107
34.6k
            return Err(Error::malformed_bytes("document length incorrect"));
108
836k
        }
109
836k
110
836k
        if data[data.len() - 1] != 0 {
111
30.0k
            return Err(Error::malformed_bytes("document not null-terminated"));
112
806k
        }
113
806k
114
806k
        Ok(RawDocument::new_unchecked(data))
115
896k
    }
<bson::raw::document::RawDocument>::from_bytes::<&[u8]>
Line
Count
Source
97
7.62k
    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
98
7.62k
        let data = data.as_ref();
99
7.62k
100
7.62k
        if data.len() < 5 {
101
8
            return Err(Error::malformed_bytes("document too short"));
102
7.61k
        }
103
104
7.61k
        let length = i32_from_slice(data)?;
105
106
7.61k
        if data.len() as i32 != length {
107
53
            return Err(Error::malformed_bytes("document length incorrect"));
108
7.56k
        }
109
7.56k
110
7.56k
        if data[data.len() - 1] != 0 {
111
8
            return Err(Error::malformed_bytes("document not null-terminated"));
112
7.55k
        }
113
7.55k
114
7.55k
        Ok(RawDocument::new_unchecked(data))
115
7.62k
    }
<bson::raw::document::RawDocument>::from_bytes::<[u8]>
Line
Count
Source
97
889k
    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
98
889k
        let data = data.as_ref();
99
889k
100
889k
        if data.len() < 5 {
101
25.4k
            return Err(Error::malformed_bytes("document too short"));
102
863k
        }
103
104
863k
        let length = i32_from_slice(data)?;
105
106
863k
        if data.len() as i32 != length {
107
34.6k
            return Err(Error::malformed_bytes("document length incorrect"));
108
829k
        }
109
829k
110
829k
        if data[data.len() - 1] != 0 {
111
30.0k
            return Err(Error::malformed_bytes("document not null-terminated"));
112
799k
        }
113
799k
114
799k
        Ok(RawDocument::new_unchecked(data))
115
889k
    }
116
117
    /// Creates a new [`RawDocument`] referencing the provided data slice.
118
1.12M
    pub(crate) fn new_unchecked<D: AsRef<[u8]> + ?Sized>(data: &D) -> &RawDocument {
119
1.12M
        // SAFETY:
120
1.12M
        //
121
1.12M
        // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is
122
1.12M
        // null, dangling, or misaligned. We know the pointer is not null or dangling due to the
123
1.12M
        // fact that it's created by a safe reference. Converting &[u8] to *const [u8] will be
124
1.12M
        // properly aligned due to them being references to the same type, and converting *const
125
1.12M
        // [u8] to *const RawDocument is aligned due to the fact that the only field in a
126
1.12M
        // RawDocument is a [u8] and it is #[repr(transparent), meaning the structs are represented
127
1.12M
        // identically at the byte level.
128
1.12M
        unsafe { &*(data.as_ref() as *const [u8] as *const RawDocument) }
129
1.12M
    }
<bson::raw::document::RawDocument>::new_unchecked::<alloc::vec::Vec<u8>>
Line
Count
Source
118
315k
    pub(crate) fn new_unchecked<D: AsRef<[u8]> + ?Sized>(data: &D) -> &RawDocument {
119
315k
        // SAFETY:
120
315k
        //
121
315k
        // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is
122
315k
        // null, dangling, or misaligned. We know the pointer is not null or dangling due to the
123
315k
        // fact that it's created by a safe reference. Converting &[u8] to *const [u8] will be
124
315k
        // properly aligned due to them being references to the same type, and converting *const
125
315k
        // [u8] to *const RawDocument is aligned due to the fact that the only field in a
126
315k
        // RawDocument is a [u8] and it is #[repr(transparent), meaning the structs are represented
127
315k
        // identically at the byte level.
128
315k
        unsafe { &*(data.as_ref() as *const [u8] as *const RawDocument) }
129
315k
    }
<bson::raw::document::RawDocument>::new_unchecked::<[u8]>
Line
Count
Source
118
806k
    pub(crate) fn new_unchecked<D: AsRef<[u8]> + ?Sized>(data: &D) -> &RawDocument {
119
806k
        // SAFETY:
120
806k
        //
121
806k
        // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is
122
806k
        // null, dangling, or misaligned. We know the pointer is not null or dangling due to the
123
806k
        // fact that it's created by a safe reference. Converting &[u8] to *const [u8] will be
124
806k
        // properly aligned due to them being references to the same type, and converting *const
125
806k
        // [u8] to *const RawDocument is aligned due to the fact that the only field in a
126
806k
        // RawDocument is a [u8] and it is #[repr(transparent), meaning the structs are represented
127
806k
        // identically at the byte level.
128
806k
        unsafe { &*(data.as_ref() as *const [u8] as *const RawDocument) }
129
806k
    }
130
131
    /// Gets a reference to the value corresponding to the given key by iterating until the key is
132
    /// found.
133
    ///
134
    /// ```
135
    /// # use bson::error::Error;
136
    /// use bson::{rawdoc, oid::ObjectId};
137
    ///
138
    /// let doc = rawdoc! {
139
    ///     "_id": ObjectId::new(),
140
    ///     "f64": 2.5,
141
    /// };
142
    ///
143
    /// let element = doc.get("f64")?.expect("finding key f64");
144
    /// assert_eq!(element.as_f64(), Some(2.5));
145
    /// assert!(doc.get("unknown")?.is_none());
146
    /// # Ok::<(), Error>(())
147
    /// ```
148
0
    pub fn get(&self, key: impl AsRef<str>) -> RawResult<Option<RawBsonRef<'_>>> {
149
0
        for elem in RawIter::new(self) {
150
0
            let elem = elem?;
151
0
            if key.as_ref() == elem.key().as_str() {
152
0
                return Ok(Some(elem.try_into()?));
153
0
            }
154
        }
155
0
        Ok(None)
156
0
    }
157
158
    /// Gets an iterator over the elements in the [`RawDocument`] that yields
159
    /// `Result<(&str, RawBson<'_>)>`.
160
154k
    pub fn iter(&self) -> Iter<'_> {
161
154k
        Iter::new(self)
162
154k
    }
163
164
    /// Gets an iterator over the elements in the [`RawDocument`],
165
    /// which yields `Result<RawElement<'_>>` values. These hold a
166
    /// reference to the underlying document but do not explicitly
167
    /// resolve the values.
168
    ///
169
    /// This iterator, which underpins the implementation of the
170
    /// default iterator, produces `RawElement` objects that hold a
171
    /// view onto the document but do not parse out or construct
172
    /// values until the `.value()` or `.try_into()` methods are
173
    /// called.
174
150k
    pub fn iter_elements(&self) -> RawIter<'_> {
175
150k
        RawIter::new(self)
176
150k
    }
177
178
0
    fn get_with<'a, T>(
179
0
        &'a self,
180
0
        key: impl AsRef<str>,
181
0
        expected_type: ElementType,
182
0
        f: impl FnOnce(RawBsonRef<'a>) -> Option<T>,
183
0
    ) -> Result<T> {
184
0
        let key = key.as_ref();
185
186
0
        let bson = self
187
0
            .get(key)
188
0
            .map_err(|e| Error::value_access_invalid_bson(format!("{:?}", e)))?
189
0
            .ok_or_else(Error::value_access_not_present)
190
0
            .map_err(|e| e.with_key(key))?;
191
0
        match f(bson) {
192
0
            Some(t) => Ok(t),
193
0
            None => Err(
194
0
                Error::value_access_unexpected_type(bson.element_type(), expected_type)
195
0
                    .with_key(key),
196
0
            ),
197
        }
198
0
    }
199
200
    /// Gets a reference to the BSON double value corresponding to a given key or returns an error
201
    /// if the key corresponds to a value which isn't a double.
202
    ///
203
    /// ```
204
    /// # use bson::error::Error;
205
    /// use bson::rawdoc;
206
    ///
207
    /// let doc = rawdoc! {
208
    ///     "bool": true,
209
    ///     "f64": 2.5,
210
    /// };
211
    ///
212
    /// assert_eq!(doc.get_f64("f64")?, 2.5);
213
    /// assert!(doc.get_f64("bool").is_err());
214
    /// assert!(doc.get_f64("unknown").is_err());
215
    /// # Ok::<(), Box<dyn std::error::Error>>(())
216
    /// ```
217
0
    pub fn get_f64(&self, key: impl AsRef<str>) -> Result<f64> {
218
0
        self.get_with(key, ElementType::Double, RawBsonRef::as_f64)
219
0
    }
220
221
    /// Gets a reference to the string value corresponding to a given key or returns an error if the
222
    /// key corresponds to a value which isn't a string.
223
    ///
224
    /// ```
225
    /// use bson::rawdoc;
226
    ///
227
    /// let doc = rawdoc! {
228
    ///     "string": "hello",
229
    ///     "bool": true,
230
    /// };
231
    ///
232
    /// assert_eq!(doc.get_str("string")?, "hello");
233
    /// assert!(doc.get_str("bool").is_err());
234
    /// assert!(doc.get_str("unknown").is_err());
235
    /// # Ok::<(), Box<dyn std::error::Error>>(())
236
    /// ```
237
0
    pub fn get_str(&self, key: impl AsRef<str>) -> Result<&'_ str> {
238
0
        self.get_with(key, ElementType::String, RawBsonRef::as_str)
239
0
    }
240
241
    /// Gets a reference to the document value corresponding to a given key or returns an error if
242
    /// the key corresponds to a value which isn't a document.
243
    ///
244
    /// ```
245
    /// # use bson::error::Error;
246
    /// use bson::rawdoc;
247
    ///
248
    /// let doc = rawdoc! {
249
    ///     "doc": { "key": "value"},
250
    ///     "bool": true,
251
    /// };
252
    ///
253
    /// assert_eq!(doc.get_document("doc")?.get_str("key")?, "value");
254
    /// assert!(doc.get_document("bool").is_err());
255
    /// assert!(doc.get_document("unknown").is_err());
256
    /// # Ok::<(), Box<dyn std::error::Error>>(())
257
    /// ```
258
0
    pub fn get_document(&self, key: impl AsRef<str>) -> Result<&'_ RawDocument> {
259
0
        self.get_with(key, ElementType::EmbeddedDocument, RawBsonRef::as_document)
260
0
    }
261
262
    /// Gets a reference to the array value corresponding to a given key or returns an error if
263
    /// the key corresponds to a value which isn't an array.
264
    ///
265
    /// ```
266
    /// use bson::rawdoc;
267
    ///
268
    /// let doc = rawdoc! {
269
    ///     "array": [true, 3],
270
    ///     "bool": true,
271
    /// };
272
    ///
273
    /// let mut arr_iter = doc.get_array("array")?.into_iter();
274
    /// let _: bool = arr_iter.next().unwrap()?.as_bool().unwrap();
275
    /// let _: i32 = arr_iter.next().unwrap()?.as_i32().unwrap();
276
    ///
277
    /// assert!(arr_iter.next().is_none());
278
    /// assert!(doc.get_array("bool").is_err());
279
    /// assert!(doc.get_array("unknown").is_err());
280
    /// # Ok::<(), Box<dyn std::error::Error>>(())
281
    /// ```
282
0
    pub fn get_array(&self, key: impl AsRef<str>) -> Result<&'_ RawArray> {
283
0
        self.get_with(key, ElementType::Array, RawBsonRef::as_array)
284
0
    }
285
286
    /// Gets a reference to the BSON binary value corresponding to a given key or returns an error
287
    /// if the key corresponds to a value which isn't a binary value.
288
    ///
289
    /// ```
290
    /// use bson::{
291
    ///     rawdoc,
292
    ///     spec::BinarySubtype,
293
    ///     Binary,
294
    /// };
295
    ///
296
    /// let doc = rawdoc! {
297
    ///     "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1, 2, 3] },
298
    ///     "bool": true,
299
    /// };
300
    ///
301
    /// assert_eq!(&doc.get_binary("binary")?.bytes, &[1, 2, 3]);
302
    /// assert!(doc.get_binary("bool").is_err());
303
    /// assert!(doc.get_binary("unknown").is_err());
304
    /// # Ok::<(), Box<dyn std::error::Error>>(())
305
    /// ```
306
0
    pub fn get_binary(&self, key: impl AsRef<str>) -> Result<RawBinaryRef<'_>> {
307
0
        self.get_with(key, ElementType::Binary, RawBsonRef::as_binary)
308
0
    }
309
310
    /// Gets a reference to the ObjectId value corresponding to a given key or returns an error if
311
    /// the key corresponds to a value which isn't an ObjectId.
312
    ///
313
    /// ```
314
    /// # use bson::error::Error;
315
    /// use bson::{rawdoc, oid::ObjectId};
316
    ///
317
    /// let doc = rawdoc! {
318
    ///     "_id": ObjectId::new(),
319
    ///     "bool": true,
320
    /// };
321
    ///
322
    /// let oid = doc.get_object_id("_id")?;
323
    /// assert!(doc.get_object_id("bool").is_err());
324
    /// assert!(doc.get_object_id("unknown").is_err());
325
    /// # Ok::<(), Box<dyn std::error::Error>>(())
326
    /// ```
327
0
    pub fn get_object_id(&self, key: impl AsRef<str>) -> Result<ObjectId> {
328
0
        self.get_with(key, ElementType::ObjectId, RawBsonRef::as_object_id)
329
0
    }
330
331
    /// Gets a reference to the boolean value corresponding to a given key or returns an error if
332
    /// the key corresponds to a value which isn't a boolean.
333
    ///
334
    /// ```
335
    /// # use bson::error::Error;
336
    /// use bson::{rawdoc, oid::ObjectId};
337
    ///
338
    /// let doc = rawdoc! {
339
    ///     "_id": ObjectId::new(),
340
    ///     "bool": true,
341
    /// };
342
    ///
343
    /// assert!(doc.get_bool("bool")?);
344
    /// assert!(doc.get_bool("_id").is_err());
345
    /// assert!(doc.get_bool("unknown").is_err());
346
    /// # Ok::<(), Box<dyn std::error::Error>>(())
347
    /// ```
348
0
    pub fn get_bool(&self, key: impl AsRef<str>) -> Result<bool> {
349
0
        self.get_with(key, ElementType::Boolean, RawBsonRef::as_bool)
350
0
    }
351
352
    /// Gets a reference to the BSON DateTime value corresponding to a given key or returns an
353
    /// error if the key corresponds to a value which isn't a DateTime.
354
    ///
355
    /// ```
356
    /// # use bson::error::Error;
357
    /// use bson::{rawdoc, DateTime};
358
    ///
359
    /// let dt = DateTime::now();
360
    /// let doc = rawdoc! {
361
    ///     "created_at": dt,
362
    ///     "bool": true,
363
    /// };
364
    ///
365
    /// assert_eq!(doc.get_datetime("created_at")?, dt);
366
    /// assert!(doc.get_datetime("bool").is_err());
367
    /// assert!(doc.get_datetime("unknown").is_err());
368
    /// # Ok::<(), Box<dyn std::error::Error>>(())
369
    /// ```
370
0
    pub fn get_datetime(&self, key: impl AsRef<str>) -> Result<DateTime> {
371
0
        self.get_with(key, ElementType::DateTime, RawBsonRef::as_datetime)
372
0
    }
373
374
    /// Gets a reference to the BSON regex value corresponding to a given key or returns an error if
375
    /// the key corresponds to a value which isn't a regex.
376
    ///
377
    /// ```
378
    /// use bson::{rawdoc, Regex, raw::cstr};
379
    ///
380
    /// let doc = rawdoc! {
381
    ///     "regex": Regex {
382
    ///         pattern: cstr!(r"end\s*$").into(),
383
    ///         options: cstr!("i").into(),
384
    ///     },
385
    ///     "bool": true,
386
    /// };
387
    ///
388
    /// assert_eq!(doc.get_regex("regex")?.pattern, cstr!(r"end\s*$"));
389
    /// assert_eq!(doc.get_regex("regex")?.options, cstr!("i"));
390
    /// assert!(doc.get_regex("bool").is_err());
391
    /// assert!(doc.get_regex("unknown").is_err());
392
    /// # Ok::<(), Box<dyn std::error::Error>>(())
393
    /// ```
394
0
    pub fn get_regex(&self, key: impl AsRef<str>) -> Result<RawRegexRef<'_>> {
395
0
        self.get_with(key, ElementType::RegularExpression, RawBsonRef::as_regex)
396
0
    }
397
398
    /// Gets a reference to the BSON timestamp value corresponding to a given key or returns an
399
    /// error if the key corresponds to a value which isn't a timestamp.
400
    ///
401
    /// ```
402
    /// # use bson::error::Error;
403
    /// use bson::{rawdoc, Timestamp};
404
    ///
405
    /// let doc = rawdoc! {
406
    ///     "bool": true,
407
    ///     "ts": Timestamp { time: 649876543, increment: 9 },
408
    /// };
409
    ///
410
    /// let timestamp = doc.get_timestamp("ts")?;
411
    ///
412
    /// assert_eq!(timestamp.time, 649876543);
413
    /// assert_eq!(timestamp.increment, 9);
414
    /// assert!(doc.get_timestamp("bool").is_err());
415
    /// assert!(doc.get_timestamp("unknown").is_err());
416
    /// # Ok::<(), Box<dyn std::error::Error>>(())
417
    /// ```
418
0
    pub fn get_timestamp(&self, key: impl AsRef<str>) -> Result<Timestamp> {
419
0
        self.get_with(key, ElementType::Timestamp, RawBsonRef::as_timestamp)
420
0
    }
421
422
    /// Gets a reference to the BSON int32 value corresponding to a given key or returns an error if
423
    /// the key corresponds to a value which isn't a 32-bit integer.
424
    ///
425
    /// ```
426
    /// # use bson::error::Error;
427
    /// use bson::rawdoc;
428
    ///
429
    /// let doc = rawdoc! {
430
    ///     "bool": true,
431
    ///     "i32": 1_000_000,
432
    /// };
433
    ///
434
    /// assert_eq!(doc.get_i32("i32")?, 1_000_000);
435
    /// assert!(doc.get_i32("bool").is_err());
436
    /// assert!(doc.get_i32("unknown").is_err());
437
    /// # Ok::<(), Box<dyn std::error::Error>>(())
438
    /// ```
439
0
    pub fn get_i32(&self, key: impl AsRef<str>) -> Result<i32> {
440
0
        self.get_with(key, ElementType::Int32, RawBsonRef::as_i32)
441
0
    }
442
443
    /// Gets a reference to the BSON int64 value corresponding to a given key or returns an error if
444
    /// the key corresponds to a value which isn't a 64-bit integer.
445
    ///
446
    /// ```
447
    /// # use bson::error::Error;
448
    /// use bson::rawdoc;
449
    ///
450
    /// let doc = rawdoc! {
451
    ///     "bool": true,
452
    ///     "i64": 9223372036854775807_i64,
453
    /// };
454
    ///
455
    /// assert_eq!(doc.get_i64("i64")?, 9223372036854775807);
456
    /// assert!(doc.get_i64("bool").is_err());
457
    /// assert!(doc.get_i64("unknown").is_err());
458
    /// # Ok::<(), Box<dyn std::error::Error>>(())
459
    /// ```
460
0
    pub fn get_i64(&self, key: impl AsRef<str>) -> Result<i64> {
461
0
        self.get_with(key, ElementType::Int64, RawBsonRef::as_i64)
462
0
    }
463
464
    /// Return a reference to the contained data as a `&[u8]`
465
    ///
466
    /// ```
467
    /// # use bson::error::Error;
468
    /// use bson::rawdoc;
469
    /// let docbuf = rawdoc! {};
470
    /// assert_eq!(docbuf.as_bytes(), b"\x05\x00\x00\x00\x00");
471
    /// # Ok::<(), Error>(())
472
    /// ```
473
59.7M
    pub fn as_bytes(&self) -> &[u8] {
474
59.7M
        &self.data
475
59.7M
    }
476
477
    /// Returns whether this document contains any elements or not.
478
0
    pub fn is_empty(&self) -> bool {
479
0
        self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize
480
0
    }
481
482
13.3M
    pub(crate) fn cstring_bytes_at(&self, start_at: usize) -> RawResult<&[u8]> {
483
13.3M
        let buf = &self.as_bytes()[start_at..];
484
13.3M
485
495M
        let mut splits = buf.splitn(2, |x| *x == 0);
486
13.3M
        let value = splits
487
13.3M
            .next()
488
13.3M
            .ok_or_else(|| RawError::malformed_bytes("no value"))?;
489
13.3M
        if splits.next().is_some() {
490
13.3M
            Ok(value)
491
        } else {
492
246
            Err(RawError::malformed_bytes("expected null terminator"))
493
        }
494
13.3M
    }
495
496
12.9M
    pub(crate) fn read_cstring_at(&self, start_at: usize) -> RawResult<&CStr> {
497
12.9M
        let bytes = self.cstring_bytes_at(start_at)?;
498
12.9M
        let s = try_to_str(bytes)?;
499
12.9M
        s.try_into()
500
12.9M
    }
501
}
502
503
#[cfg(feature = "serde")]
504
impl<'de: 'a, 'a> serde::Deserialize<'de> for &'a RawDocument {
505
0
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
506
0
    where
507
0
        D: serde::Deserializer<'de>,
508
0
    {
509
        use super::serde::OwnedOrBorrowedRawDocument;
510
0
        match OwnedOrBorrowedRawDocument::deserialize(deserializer)? {
511
0
            OwnedOrBorrowedRawDocument::Borrowed(b) => Ok(b),
512
0
            OwnedOrBorrowedRawDocument::Owned(d) => Err(serde::de::Error::custom(format!(
513
0
                "expected borrowed raw document, instead got owned {:?}",
514
0
                d
515
0
            ))),
516
        }
517
0
    }
518
}
519
520
#[cfg(feature = "serde")]
521
impl serde::Serialize for &RawDocument {
522
0
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
523
0
    where
524
0
        S: serde::Serializer,
525
0
    {
526
        struct KvpSerializer<'a>(&'a RawDocument);
527
528
        impl serde::Serialize for KvpSerializer<'_> {
529
0
            fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
530
0
            where
531
0
                S: serde::Serializer,
532
0
            {
533
                use serde::ser::SerializeMap as _;
534
0
                if serializer.is_human_readable() {
535
0
                    let mut map = serializer.serialize_map(None)?;
536
0
                    for kvp in self.0 {
537
0
                        let (k, v) = kvp.map_err(serde::ser::Error::custom)?;
538
0
                        map.serialize_entry(k.as_str(), &v)?;
539
                    }
540
0
                    map.end()
541
                } else {
542
0
                    serializer.serialize_bytes(self.0.as_bytes())
543
                }
544
0
            }
545
        }
546
0
        serializer.serialize_newtype_struct(super::RAW_DOCUMENT_NEWTYPE, &KvpSerializer(self))
547
0
    }
548
}
549
550
impl std::fmt::Debug for RawDocument {
551
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
552
0
        f.debug_struct("RawDocument")
553
0
            .field("data", &hex::encode(&self.data))
554
0
            .finish()
555
0
    }
556
}
557
558
impl AsRef<RawDocument> for RawDocument {
559
0
    fn as_ref(&self) -> &RawDocument {
560
0
        self
561
0
    }
562
}
563
564
impl ToOwned for RawDocument {
565
    type Owned = RawDocumentBuf;
566
567
222k
    fn to_owned(&self) -> Self::Owned {
568
222k
        // unwrap is ok here because we already verified the bytes in
569
222k
        // `RawDocument::from_bytes`
570
222k
        RawDocumentBuf::from_bytes(self.data.to_owned()).unwrap()
571
222k
    }
572
}
573
574
impl<'a> From<&'a RawDocument> for Cow<'a, RawDocument> {
575
    fn from(rdr: &'a RawDocument) -> Self {
576
        Cow::Borrowed(rdr)
577
    }
578
}
579
580
impl TryFrom<&RawDocument> for Document {
581
    type Error = RawError;
582
583
152k
    fn try_from(rawdoc: &RawDocument) -> RawResult<Document> {
584
152k
        rawdoc
585
152k
            .into_iter()
586
2.48M
            .map(|res| res.and_then(|(k, v)| Ok((k.as_str().to_owned(), v.try_into()?))))
587
152k
            .collect()
588
152k
    }
589
}
590
591
impl TryFrom<&RawDocument> for Utf8Lossy<Document> {
592
    type Error = RawError;
593
594
    fn try_from(rawdoc: &RawDocument) -> RawResult<Utf8Lossy<Document>> {
595
        let mut out = Document::new();
596
        for elem in rawdoc.iter_elements() {
597
            let elem = elem?;
598
            let value = deep_utf8_lossy(elem.value_utf8_lossy()?)?;
599
            out.insert(elem.key().as_str(), value);
600
        }
601
        Ok(Utf8Lossy(out))
602
    }
603
}
604
605
0
fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
606
0
    match src {
607
0
        RawBson::Array(arr) => {
608
0
            let mut tmp = vec![];
609
0
            for elem in arr.iter_elements() {
610
0
                tmp.push(deep_utf8_lossy(elem?.value_utf8_lossy()?)?);
611
            }
612
0
            Ok(Bson::Array(tmp))
613
        }
614
0
        RawBson::Document(doc) => {
615
0
            let mut tmp = doc! {};
616
0
            for elem in doc.iter_elements() {
617
0
                let elem = elem?;
618
0
                tmp.insert(
619
0
                    elem.key().as_str(),
620
0
                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
621
                );
622
            }
623
0
            Ok(Bson::Document(tmp))
624
        }
625
0
        RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code, scope }) => {
626
0
            let mut tmp = doc! {};
627
0
            for elem in scope.iter_elements() {
628
0
                let elem = elem?;
629
0
                tmp.insert(
630
0
                    elem.key().as_str(),
631
0
                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
632
                );
633
            }
634
0
            Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
635
0
                code,
636
0
                scope: tmp,
637
0
            }))
638
        }
639
0
        v => v.try_into(),
640
    }
641
0
}
642
643
impl TryFrom<RawDocumentBuf> for Document {
644
    type Error = crate::error::Error;
645
646
20.7k
    fn try_from(raw: RawDocumentBuf) -> Result<Document> {
647
20.7k
        Document::try_from(raw.as_ref())
648
20.7k
    }
649
}
650
651
impl TryFrom<RawDocumentBuf> for Utf8Lossy<Document> {
652
    type Error = crate::error::Error;
653
654
    fn try_from(raw: RawDocumentBuf) -> Result<Utf8Lossy<Document>> {
655
        Utf8Lossy::<Document>::try_from(raw.as_ref())
656
    }
657
}
658
659
impl TryFrom<&RawDocumentBuf> for Document {
660
    type Error = crate::error::Error;
661
662
0
    fn try_from(raw: &RawDocumentBuf) -> Result<Document> {
663
0
        Document::try_from(raw.as_ref())
664
0
    }
665
}
666
667
impl TryFrom<&RawDocumentBuf> for Utf8Lossy<Document> {
668
    type Error = crate::error::Error;
669
670
    fn try_from(raw: &RawDocumentBuf) -> Result<Utf8Lossy<Document>> {
671
        Utf8Lossy::<Document>::try_from(raw.as_ref())
672
    }
673
}
674
675
impl<'a> IntoIterator for &'a RawDocument {
676
    type IntoIter = Iter<'a>;
677
    type Item = RawResult<(&'a CStr, RawBsonRef<'a>)>;
678
679
154k
    fn into_iter(self) -> Iter<'a> {
680
154k
        self.iter()
681
154k
    }
682
}