bson/raw/
bson.rs

1use std::convert::{TryFrom, TryInto};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    oid::{self, ObjectId},
7    raw::RAW_BSON_NEWTYPE,
8    spec::ElementType,
9    Binary,
10    Bson,
11    DbPointer,
12    Decimal128,
13    RawArray,
14    RawArrayBuf,
15    RawBinaryRef,
16    RawBsonRef,
17    RawDbPointerRef,
18    RawDocument,
19    RawDocumentBuf,
20    RawJavaScriptCodeWithScopeRef,
21    RawRegexRef,
22    Regex,
23    Timestamp,
24};
25
26use super::{
27    serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson},
28    Error,
29    Result,
30};
31
32/// A BSON value backed by owned raw BSON bytes.
33#[derive(Debug, Clone, PartialEq)]
34pub enum RawBson {
35    /// 64-bit binary floating point
36    Double(f64),
37    /// UTF-8 string
38    String(String),
39    /// Array
40    Array(RawArrayBuf),
41    /// Embedded document
42    Document(RawDocumentBuf),
43    /// Boolean value
44    Boolean(bool),
45    /// Null value
46    Null,
47    /// Regular expression
48    RegularExpression(Regex),
49    /// JavaScript code
50    JavaScriptCode(String),
51    /// JavaScript code w/ scope
52    JavaScriptCodeWithScope(RawJavaScriptCodeWithScope),
53    /// 32-bit signed integer
54    Int32(i32),
55    /// 64-bit signed integer
56    Int64(i64),
57    /// Timestamp
58    Timestamp(Timestamp),
59    /// Binary data
60    Binary(Binary),
61    /// [ObjectId](http://dochub.mongodb.org/core/objectids)
62    ObjectId(oid::ObjectId),
63    /// UTC datetime
64    DateTime(crate::DateTime),
65    /// Symbol (Deprecated)
66    Symbol(String),
67    /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst)
68    Decimal128(Decimal128),
69    /// Undefined value (Deprecated)
70    Undefined,
71    /// Max key
72    MaxKey,
73    /// Min key
74    MinKey,
75    /// DBPointer (Deprecated)
76    DbPointer(DbPointer),
77}
78
79impl RawBson {
80    /// Get the [`ElementType`] of this value.
81    pub fn element_type(&self) -> ElementType {
82        match *self {
83            RawBson::Double(..) => ElementType::Double,
84            RawBson::String(..) => ElementType::String,
85            RawBson::Array(..) => ElementType::Array,
86            RawBson::Document(..) => ElementType::EmbeddedDocument,
87            RawBson::Boolean(..) => ElementType::Boolean,
88            RawBson::Null => ElementType::Null,
89            RawBson::RegularExpression(..) => ElementType::RegularExpression,
90            RawBson::JavaScriptCode(..) => ElementType::JavaScriptCode,
91            RawBson::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope,
92            RawBson::Int32(..) => ElementType::Int32,
93            RawBson::Int64(..) => ElementType::Int64,
94            RawBson::Timestamp(..) => ElementType::Timestamp,
95            RawBson::Binary(..) => ElementType::Binary,
96            RawBson::ObjectId(..) => ElementType::ObjectId,
97            RawBson::DateTime(..) => ElementType::DateTime,
98            RawBson::Symbol(..) => ElementType::Symbol,
99            RawBson::Decimal128(..) => ElementType::Decimal128,
100            RawBson::Undefined => ElementType::Undefined,
101            RawBson::MaxKey => ElementType::MaxKey,
102            RawBson::MinKey => ElementType::MinKey,
103            RawBson::DbPointer(..) => ElementType::DbPointer,
104        }
105    }
106
107    /// Gets the wrapped `f64` value or returns [`None`] if the value isn't a BSON
108    /// double.
109    pub fn as_f64(&self) -> Option<f64> {
110        match self {
111            RawBson::Double(d) => Some(*d),
112            _ => None,
113        }
114    }
115
116    /// Gets a reference to the [`String`] that's wrapped or returns [`None`] if the wrapped value
117    /// isn't a BSON String.
118    pub fn as_str(&self) -> Option<&'_ str> {
119        match self {
120            RawBson::String(s) => Some(s),
121            _ => None,
122        }
123    }
124
125    /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns [`None`] if the wrapped
126    /// value isn't a BSON array.
127    pub fn as_array(&self) -> Option<&'_ RawArray> {
128        match self {
129            RawBson::Array(v) => Some(v),
130            _ => None,
131        }
132    }
133
134    /// Gets a mutable reference to the [`RawArrayBuf`] that's wrapped or returns [`None`] if the
135    /// wrapped value isn't a BSON array.
136    pub fn as_array_mut(&mut self) -> Option<&mut RawArrayBuf> {
137        match self {
138            RawBson::Array(ref mut v) => Some(v),
139            _ => None,
140        }
141    }
142
143    /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns [`None`] if the wrapped
144    /// value isn't a BSON document.
145    pub fn as_document(&self) -> Option<&'_ RawDocument> {
146        match self {
147            RawBson::Document(v) => Some(v),
148            _ => None,
149        }
150    }
151
152    /// Gets a mutable reference to the [`RawDocumentBuf`] that's wrapped or returns [`None`] if the
153    /// wrapped value isn't a BSON document.
154    pub fn as_document_mut(&mut self) -> Option<&mut RawDocumentBuf> {
155        match self {
156            RawBson::Document(ref mut v) => Some(v),
157            _ => None,
158        }
159    }
160
161    /// Gets the wrapped `bool` value or returns [`None`] if the wrapped value isn't a BSON
162    /// boolean.
163    pub fn as_bool(&self) -> Option<bool> {
164        match self {
165            RawBson::Boolean(v) => Some(*v),
166            _ => None,
167        }
168    }
169
170    /// Gets the wrapped `i32` value or returns [`None`] if the wrapped value isn't a BSON
171    /// Int32.
172    pub fn as_i32(&self) -> Option<i32> {
173        match self {
174            RawBson::Int32(v) => Some(*v),
175            _ => None,
176        }
177    }
178
179    /// Gets the wrapped `i64` value or returns [`None`] if the wrapped value isn't a BSON
180    /// Int64.
181    pub fn as_i64(&self) -> Option<i64> {
182        match self {
183            RawBson::Int64(v) => Some(*v),
184            _ => None,
185        }
186    }
187
188    /// Gets the wrapped [`crate::oid::ObjectId`] value or returns [`None`] if the wrapped value
189    /// isn't a BSON ObjectID.
190    pub fn as_object_id(&self) -> Option<oid::ObjectId> {
191        match self {
192            RawBson::ObjectId(v) => Some(*v),
193            _ => None,
194        }
195    }
196
197    /// Gets a reference to the [`Binary`] that's wrapped or returns [`None`] if the wrapped value
198    /// isn't a BSON binary.
199    pub fn as_binary(&self) -> Option<RawBinaryRef<'_>> {
200        match self {
201            RawBson::Binary(v) => Some(RawBinaryRef {
202                bytes: v.bytes.as_slice(),
203                subtype: v.subtype,
204            }),
205            _ => None,
206        }
207    }
208
209    /// Gets a reference to the [`Regex`] that's wrapped or returns [`None`] if the wrapped value
210    /// isn't a BSON regular expression.
211    pub fn as_regex(&self) -> Option<RawRegexRef<'_>> {
212        match self {
213            RawBson::RegularExpression(v) => Some(RawRegexRef {
214                pattern: v.pattern.as_str(),
215                options: v.options.as_str(),
216            }),
217            _ => None,
218        }
219    }
220
221    /// Gets the wrapped [`crate::DateTime`] value or returns [`None`] if the wrapped value isn't a
222    /// BSON datetime.
223    pub fn as_datetime(&self) -> Option<crate::DateTime> {
224        match self {
225            RawBson::DateTime(v) => Some(*v),
226            _ => None,
227        }
228    }
229
230    /// Gets a reference to the symbol that's wrapped or returns [`None`] if the wrapped value isn't
231    /// a BSON Symbol.
232    pub fn as_symbol(&self) -> Option<&'_ str> {
233        match self {
234            RawBson::Symbol(v) => Some(v),
235            _ => None,
236        }
237    }
238
239    /// Gets the wrapped [`crate::Timestamp`] value or returns [`None`] if the wrapped value isn't a
240    /// BSON datetime.
241    pub fn as_timestamp(&self) -> Option<Timestamp> {
242        match self {
243            RawBson::Timestamp(timestamp) => Some(*timestamp),
244            _ => None,
245        }
246    }
247
248    /// Returns `Some(())` if this value is null, otherwise returns [`None`].
249    pub fn as_null(&self) -> Option<()> {
250        match self {
251            RawBson::Null => Some(()),
252            _ => None,
253        }
254    }
255
256    /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns [`None`] if the
257    /// wrapped value isn't a BSON DbPointer.
258    pub fn as_db_pointer(&self) -> Option<RawDbPointerRef<'_>> {
259        match self {
260            RawBson::DbPointer(d) => Some(RawDbPointerRef {
261                namespace: d.namespace.as_str(),
262                id: d.id,
263            }),
264            _ => None,
265        }
266    }
267
268    /// Gets a reference to the code that's wrapped or returns [`None`] if the wrapped value isn't a
269    /// BSON JavaScript code.
270    pub fn as_javascript(&self) -> Option<&'_ str> {
271        match self {
272            RawBson::JavaScriptCode(s) => Some(s),
273            _ => None,
274        }
275    }
276
277    /// Gets a reference to the [`RawJavaScriptCodeWithScope`] that's wrapped or returns [`None`]
278    /// if the wrapped value isn't a BSON JavaScript code with scope value.
279    pub fn as_javascript_with_scope(&self) -> Option<RawJavaScriptCodeWithScopeRef<'_>> {
280        match self {
281            RawBson::JavaScriptCodeWithScope(s) => Some(RawJavaScriptCodeWithScopeRef {
282                code: s.code.as_str(),
283                scope: &s.scope,
284            }),
285            _ => None,
286        }
287    }
288
289    /// Gets a [`RawBsonRef`] value referencing this owned raw BSON value.
290    pub fn as_raw_bson_ref(&self) -> RawBsonRef<'_> {
291        match self {
292            RawBson::Double(d) => RawBsonRef::Double(*d),
293            RawBson::String(s) => RawBsonRef::String(s.as_str()),
294            RawBson::Array(a) => RawBsonRef::Array(a),
295            RawBson::Document(d) => RawBsonRef::Document(d),
296            RawBson::Boolean(b) => RawBsonRef::Boolean(*b),
297            RawBson::Null => RawBsonRef::Null,
298            RawBson::RegularExpression(re) => RawBsonRef::RegularExpression(RawRegexRef {
299                options: re.options.as_str(),
300                pattern: re.pattern.as_str(),
301            }),
302            RawBson::JavaScriptCode(c) => RawBsonRef::JavaScriptCode(c.as_str()),
303            RawBson::JavaScriptCodeWithScope(code_w_scope) => {
304                RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef {
305                    code: code_w_scope.code.as_str(),
306                    scope: code_w_scope.scope.as_ref(),
307                })
308            }
309            RawBson::Int32(i) => RawBsonRef::Int32(*i),
310            RawBson::Int64(i) => RawBsonRef::Int64(*i),
311            RawBson::Timestamp(ts) => RawBsonRef::Timestamp(*ts),
312            RawBson::Binary(b) => RawBsonRef::Binary(RawBinaryRef {
313                bytes: b.bytes.as_slice(),
314                subtype: b.subtype,
315            }),
316            RawBson::ObjectId(oid) => RawBsonRef::ObjectId(*oid),
317            RawBson::DateTime(dt) => RawBsonRef::DateTime(*dt),
318            RawBson::Symbol(s) => RawBsonRef::Symbol(s.as_str()),
319            RawBson::Decimal128(d) => RawBsonRef::Decimal128(*d),
320            RawBson::Undefined => RawBsonRef::Undefined,
321            RawBson::MaxKey => RawBsonRef::MaxKey,
322            RawBson::MinKey => RawBsonRef::MinKey,
323            RawBson::DbPointer(dbp) => RawBsonRef::DbPointer(RawDbPointerRef {
324                namespace: dbp.namespace.as_str(),
325                id: dbp.id,
326            }),
327        }
328    }
329}
330
331impl From<i32> for RawBson {
332    fn from(i: i32) -> Self {
333        RawBson::Int32(i)
334    }
335}
336
337impl From<i64> for RawBson {
338    fn from(i: i64) -> Self {
339        RawBson::Int64(i)
340    }
341}
342
343impl From<String> for RawBson {
344    fn from(s: String) -> Self {
345        RawBson::String(s)
346    }
347}
348
349impl From<&str> for RawBson {
350    fn from(s: &str) -> Self {
351        RawBson::String(s.to_owned())
352    }
353}
354
355impl From<f64> for RawBson {
356    fn from(f: f64) -> Self {
357        RawBson::Double(f)
358    }
359}
360
361impl From<bool> for RawBson {
362    fn from(b: bool) -> Self {
363        RawBson::Boolean(b)
364    }
365}
366
367impl From<RawDocumentBuf> for RawBson {
368    fn from(d: RawDocumentBuf) -> Self {
369        RawBson::Document(d)
370    }
371}
372
373impl From<RawArrayBuf> for RawBson {
374    fn from(a: RawArrayBuf) -> Self {
375        RawBson::Array(a)
376    }
377}
378
379impl From<crate::DateTime> for RawBson {
380    fn from(dt: crate::DateTime) -> Self {
381        RawBson::DateTime(dt)
382    }
383}
384
385impl From<Timestamp> for RawBson {
386    fn from(ts: Timestamp) -> Self {
387        RawBson::Timestamp(ts)
388    }
389}
390
391impl From<ObjectId> for RawBson {
392    fn from(oid: ObjectId) -> Self {
393        RawBson::ObjectId(oid)
394    }
395}
396
397impl From<Decimal128> for RawBson {
398    fn from(d: Decimal128) -> Self {
399        RawBson::Decimal128(d)
400    }
401}
402
403impl From<RawJavaScriptCodeWithScope> for RawBson {
404    fn from(code_w_scope: RawJavaScriptCodeWithScope) -> Self {
405        RawBson::JavaScriptCodeWithScope(code_w_scope)
406    }
407}
408
409impl From<Binary> for RawBson {
410    fn from(b: Binary) -> Self {
411        RawBson::Binary(b)
412    }
413}
414
415impl From<Regex> for RawBson {
416    fn from(re: Regex) -> Self {
417        RawBson::RegularExpression(re)
418    }
419}
420
421impl From<DbPointer> for RawBson {
422    fn from(d: DbPointer) -> Self {
423        RawBson::DbPointer(d)
424    }
425}
426
427impl<'de> Deserialize<'de> for RawBson {
428    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
429    where
430        D: serde::Deserializer<'de>,
431    {
432        match deserializer
433            .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)?
434        {
435            OwnedOrBorrowedRawBson::Owned(o) => Ok(o),
436            OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_raw_bson()),
437        }
438    }
439}
440
441impl Serialize for RawBson {
442    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
443    where
444        S: serde::Serializer,
445    {
446        self.as_raw_bson_ref().serialize(serializer)
447    }
448}
449
450impl TryFrom<RawBson> for Bson {
451    type Error = Error;
452
453    fn try_from(rawbson: RawBson) -> Result<Bson> {
454        Ok(match rawbson {
455            RawBson::Double(d) => Bson::Double(d),
456            RawBson::String(s) => Bson::String(s),
457            RawBson::Document(rawdoc) => Bson::Document(rawdoc.as_ref().try_into()?),
458            RawBson::Array(rawarray) => Bson::Array(rawarray.as_ref().try_into()?),
459            RawBson::Binary(rawbson) => Bson::Binary(rawbson),
460            RawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson),
461            RawBson::Boolean(rawbson) => Bson::Boolean(rawbson),
462            RawBson::DateTime(rawbson) => Bson::DateTime(rawbson),
463            RawBson::Null => Bson::Null,
464            RawBson::RegularExpression(rawregex) => Bson::RegularExpression(rawregex),
465            RawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson),
466            RawBson::Int32(rawbson) => Bson::Int32(rawbson),
467            RawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson),
468            RawBson::Int64(rawbson) => Bson::Int64(rawbson),
469            RawBson::Undefined => Bson::Undefined,
470            RawBson::DbPointer(rawbson) => Bson::DbPointer(rawbson),
471            RawBson::Symbol(rawbson) => Bson::Symbol(rawbson),
472            RawBson::JavaScriptCodeWithScope(rawbson) => {
473                Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope {
474                    code: rawbson.code,
475                    scope: rawbson.scope.try_into()?,
476                })
477            }
478            RawBson::Decimal128(rawbson) => Bson::Decimal128(rawbson),
479            RawBson::MaxKey => Bson::MaxKey,
480            RawBson::MinKey => Bson::MinKey,
481        })
482    }
483}
484
485impl TryFrom<Bson> for RawBson {
486    type Error = Error;
487
488    fn try_from(bson: Bson) -> Result<RawBson> {
489        Ok(match bson {
490            Bson::Double(d) => RawBson::Double(d),
491            Bson::String(s) => RawBson::String(s),
492            Bson::Document(doc) => RawBson::Document((&doc).try_into()?),
493            Bson::Array(arr) => RawBson::Array(
494                arr.into_iter()
495                    .map(|b| -> Result<RawBson> { b.try_into() })
496                    .collect::<Result<RawArrayBuf>>()?,
497            ),
498            Bson::Binary(bin) => RawBson::Binary(bin),
499            Bson::ObjectId(id) => RawBson::ObjectId(id),
500            Bson::Boolean(b) => RawBson::Boolean(b),
501            Bson::DateTime(dt) => RawBson::DateTime(dt),
502            Bson::Null => RawBson::Null,
503            Bson::RegularExpression(regex) => RawBson::RegularExpression(regex),
504            Bson::JavaScriptCode(s) => RawBson::JavaScriptCode(s),
505            Bson::Int32(i) => RawBson::Int32(i),
506            Bson::Timestamp(ts) => RawBson::Timestamp(ts),
507            Bson::Int64(i) => RawBson::Int64(i),
508            Bson::Undefined => RawBson::Undefined,
509            Bson::DbPointer(p) => RawBson::DbPointer(p),
510            Bson::Symbol(s) => RawBson::Symbol(s),
511            Bson::JavaScriptCodeWithScope(jcws) => {
512                RawBson::JavaScriptCodeWithScope(crate::RawJavaScriptCodeWithScope {
513                    code: jcws.code,
514                    scope: (&jcws.scope).try_into()?,
515                })
516            }
517            Bson::Decimal128(d) => RawBson::Decimal128(d),
518            Bson::MaxKey => RawBson::MaxKey,
519            Bson::MinKey => RawBson::MinKey,
520        })
521    }
522}
523
524/// A BSON "code with scope" value backed by owned raw BSON.
525#[derive(Debug, Clone, PartialEq)]
526pub struct RawJavaScriptCodeWithScope {
527    /// The code value.
528    pub code: String,
529
530    /// The scope document.
531    pub scope: RawDocumentBuf,
532}
533
534impl<'de> Deserialize<'de> for RawJavaScriptCodeWithScope {
535    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
536    where
537        D: serde::Deserializer<'de>,
538    {
539        match RawBson::deserialize(deserializer)? {
540            RawBson::JavaScriptCodeWithScope(b) => Ok(b),
541            c => Err(serde::de::Error::custom(format!(
542                "expected CodeWithScope, but got {:?} instead",
543                c
544            ))),
545        }
546    }
547}
548
549impl Serialize for RawJavaScriptCodeWithScope {
550    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
551    where
552        S: serde::Serializer,
553    {
554        let raw = RawJavaScriptCodeWithScopeRef {
555            code: self.code.as_str(),
556            scope: self.scope.as_ref(),
557        };
558
559        raw.serialize(serializer)
560    }
561}