From d7466520fc1e2d1c5cc52bd4eda5f7a8156bccc0 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Mon, 15 Nov 2021 15:45:30 -0500 Subject: [PATCH 01/21] wip append --- src/macros.rs | 177 ++++++++++++++++++++++++++++++++++++++++ src/raw/document_buf.rs | 47 ++++++++++- src/raw/test/mod.rs | 23 +++--- src/ser/mod.rs | 2 +- 4 files changed, 234 insertions(+), 15 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index b69ca155..f14e17fc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -212,3 +212,180 @@ macro_rules! doc { object }}; } + +#[macro_export] +macro_rules! rawbson { + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an array [...]. Produces a vec![...] + // of the elements. + // + // Must be invoked as: bson!(@array [] $($tt)*) + ////////////////////////////////////////////////////////////////////////// + + // Finished with trailing comma. + (@array [$($elems:expr,)*]) => { + vec![$($elems,)*] + }; + + // Finished without trailing comma. + (@array [$($elems:expr),*]) => { + vec![$($elems),*] + }; + + // Next element is `null`. + (@array [$($elems:expr,)*] null $($rest:tt)*) => { + $crate::rawbson!(@array [$($elems,)* $crate::rawbson!(null)] $($rest)*) + }; + + // Next element is an array. + (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { + $crate::rawbson!(@array [$($elems,)* $crate::rawbson!([$($array)*])] $($rest)*) + }; + + // Next element is a map. + (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { + $crate::rawbson!(@array [$($elems,)* $crate::rawbson!({$($map)*})] $($rest)*) + }; + + // Next element is an expression followed by comma. + (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { + $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($next),] $($rest)*) + }; + + // Last element is an expression with no trailing comma. + (@array [$($elems:expr,)*] $last:expr) => { + $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($last)]) + }; + + // Comma after the most recent element. + (@array [$($elems:expr),*] , $($rest:tt)*) => { + $crate::rawbson!(@array [$($elems,)*] $($rest)*) + }; + + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an object {...}. Each entry is + // inserted into the given map variable. + // + // Must be invoked as: bson!(@object $map () ($($tt)*) ($($tt)*)) + // + // We require two copies of the input tokens so that we can match on one + // copy and trigger errors on the other copy. + ////////////////////////////////////////////////////////////////////////// + + // Finished. + (@object $object:ident () () ()) => {}; + + // Insert the current entry followed by trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { + $object.append(($($key)+), $value); + $crate::rawbson!(@object $object () ($($rest)*) ($($rest)*)); + }; + + // Insert the last entry without trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr)) => { + $object.append(($($key)+), $value); + }; + + // // Next value is `null`. + // (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { + // $crate::bson!(@object $object [$($key)+] ($crate::bson!(null)) $($rest)*); + // }; + + // Next value is an array. + (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { + $crate::bson!(@object $object [$($key)+] ($crate::bson!([$($array)*])) $($rest)*); + }; + + // Next value is a map. + (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { + $crate::bson!(@object $object [$($key)+] ($crate::bson!({$($map)*})) $($rest)*); + }; + + // Next value is an expression followed by comma. + (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { + $crate::bson!(@object $object [$($key)+] ($crate::bson!($value)) , $($rest)*); + }; + + // Last value is an expression with no trailing comma. + (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { + $crate::bson!(@object $object [$($key)+] ($crate::bson!($value))); + }; + + // Missing value for last entry. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { + // "unexpected end of macro invocation" + $crate::bson!(); + }; + + // Missing key-value separator and value for last entry. + // Trigger a reasonable error message. + (@object $object:ident ($($key:tt)+) () $copy:tt) => { + // "unexpected end of macro invocation" + $crate::bson!(); + }; + + // Misplaced key-value separator. Trigger a reasonable error message. + (@object $object:ident () (: $($rest:tt)*) ($kv_separator:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `:`". + unimplemented!($kv_separator); + }; + + // Found a comma inside a key. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `,`". + unimplemented!($comma); + }; + + // Key is fully parenthesized. This avoids clippy double_parens false + // positives because the parenthesization may be necessary here. + (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { + $crate::bson!(@object $object ($key) (: $($rest)*) (: $($rest)*)); + }; + + // Munch a token into the current key. + (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { + $crate::bson!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); + }; + + ////////////////////////////////////////////////////////////////////////// + // The main implementation. + // + // Must be invoked as: bson!($($bson)+) + ////////////////////////////////////////////////////////////////////////// + + (null) => { + $crate::Bson::Null + }; + + ([]) => { + $crate::Bson::Array(vec![]) + }; + + ([ $($tt:tt)+ ]) => { + $crate::Bson::Array($crate::bson!(@array [] $($tt)+)) + }; + + ({}) => { + $crate::RawBson::Document($crate::rawdoc!{}) + }; + + ({$($tt:tt)+}) => { + $crate::RawBson::Document($crate::rawdoc!{$($tt)+}) + }; + + // Any Into type. + // Must be below every other rule. + ($other:expr) => { + $crate::RawBson::from($other) + }; +} + +#[macro_export] +macro_rules! rawdoc { + () => {{ $crate::RawDocumentBuf::empty() }}; + ( $($tt:tt)+ ) => {{ + let mut object = $crate::RawDocumentBuf::empty(); + $crate::rawbson!(@object object () ($($tt)+) ($($tt)+)); + object + }}; +} diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index f1c216d3..83e7c003 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -1,12 +1,13 @@ use std::{ borrow::{Borrow, Cow}, - convert::TryFrom, + convert::{TryFrom, TryInto}, + ffi::CString, ops::Deref, }; use serde::{Deserialize, Serialize}; -use crate::Document; +use crate::{de::MIN_BSON_DOCUMENT_SIZE, spec::ElementType, Document}; use super::{Error, ErrorKind, Iter, RawBson, RawDocument, Result}; @@ -52,6 +53,12 @@ pub struct RawDocumentBuf { } impl RawDocumentBuf { + pub fn empty() -> RawDocumentBuf { + let mut data: Vec = MIN_BSON_DOCUMENT_SIZE.to_le_bytes().to_vec(); + data.push(0); + Self { data } + } + /// Constructs a new [`RawDocumentBuf`], validating _only_ the /// following invariants: /// * `data` is at least five bytes long (the minimum for a valid BSON document) @@ -139,6 +146,42 @@ impl RawDocumentBuf { pub fn into_vec(self) -> Vec { self.data } + + pub fn append_document_buf(&mut self, key: impl AsRef, value: RawDocumentBuf) { + self.append(key, RawBson::Document(&value)) + } + + pub fn append<'a>(&mut self, key: impl AsRef, value: RawBson<'a>) { + let original_len = self.data.len(); + let key_bytes = key.as_ref().as_bytes(); + let key = CString::new(key_bytes).unwrap(); + self.data.extend(key.to_bytes_with_nul()); + match value { + RawBson::Int32(i) => { + self.data.extend(i.to_le_bytes()); + }, + RawBson::String(s) => { + self.data.extend(((s.as_bytes().len() + 1) as i32).to_le_bytes()); + self.data.extend(s.as_bytes()); + self.data.push(0); + }, + RawBson::Document(d) => { + self.data.extend(d.as_bytes()); + } + _ => todo!(), + } + // update element type + self.data[original_len - 1] = value.element_type() as u8; + // append trailing null byte + self.data.push(0); + // update length + self.data + .splice(0..4, (self.data.len() as i32).to_le_bytes()); + } + + pub fn to_document(&self) -> Result { + self.as_ref().try_into() + } } impl<'de> Deserialize<'de> for RawDocumentBuf { diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index e20a1bb4..96e7b22f 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -1,18 +1,7 @@ mod props; use super::*; -use crate::{ - doc, - oid::ObjectId, - raw::error::ValueAccessErrorKind, - spec::BinarySubtype, - Binary, - Bson, - DateTime, - JavaScriptCodeWithScope, - Regex, - Timestamp, -}; +use crate::{Binary, Bson, DateTime, Document, JavaScriptCodeWithScope, Regex, Timestamp, doc, oid::ObjectId, raw::error::ValueAccessErrorKind, spec::BinarySubtype}; use chrono::{TimeZone, Utc}; fn to_bytes(doc: &crate::Document) -> Vec { @@ -479,6 +468,16 @@ fn into_bson_conversion() { ); } +#[test] +fn append() { + let mut buf = RawDocumentBuf::empty(); + buf.append("dog", RawBson::Int32(4)); + buf.append("cat", RawBson::Int32(1)); + + let doc = buf.to_document().unwrap(); + println!("{:#?}", doc); +} + use props::arbitrary_bson; use proptest::prelude::*; use std::convert::TryInto; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index e133d952..5341c38f 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -47,7 +47,7 @@ fn write_string(writer: &mut W, s: &str) -> Result<()> { Ok(()) } -fn write_cstring(writer: &mut W, s: &str) -> Result<()> { +pub(crate) fn write_cstring(writer: &mut W, s: &str) -> Result<()> { if s.contains('\0') { return Err(Error::InvalidCString(s.into())); } From bcf3b9c652ffca42054303c3654ce4996a635180 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Mon, 15 Nov 2021 19:42:25 -0500 Subject: [PATCH 02/21] finish implementaiton, start adding tests --- src/bson.rs | 28 ++- src/lib.rs | 2 +- src/macros.rs | 352 ++++++++++++++++---------------- src/raw/array_buf.rs | 47 +++++ src/raw/bson.rs | 124 ++++++++++- src/raw/document.rs | 5 + src/raw/document_buf.rs | 96 ++++++++- src/raw/mod.rs | 2 + src/raw/test/append.rs | 341 +++++++++++++++++++++++++++++++ src/raw/test/mod.rs | 15 +- src/ser/mod.rs | 1 + src/ser/raw/value_serializer.rs | 9 +- 12 files changed, 823 insertions(+), 199 deletions(-) create mode 100644 src/raw/array_buf.rs create mode 100644 src/raw/test/append.rs diff --git a/src/bson.rs b/src/bson.rs index 11ee714c..f70390e7 100644 --- a/src/bson.rs +++ b/src/bson.rs @@ -34,6 +34,7 @@ use crate::{ oid::{self, ObjectId}, spec::{BinarySubtype, ElementType}, Decimal128, + RawBinary, }; /// Possible BSON value types. @@ -338,6 +339,12 @@ impl From for Bson { } } +impl From for Bson { + fn from(d: Decimal128) -> Self { + Bson::Decimal128(d) + } +} + impl From> for Bson where T: Into, @@ -732,10 +739,7 @@ impl Bson { if let Ok(regex) = doc.get_document("$regularExpression") { if let Ok(pattern) = regex.get_str("pattern") { if let Ok(options) = regex.get_str("options") { - return Bson::RegularExpression(Regex::new( - pattern.into(), - options.into(), - )); + return Bson::RegularExpression(Regex::new(pattern, options)); } } } @@ -1014,11 +1018,14 @@ pub struct Regex { } impl Regex { - pub(crate) fn new(pattern: String, options: String) -> Self { - let mut chars: Vec<_> = options.chars().collect(); + pub(crate) fn new(pattern: impl AsRef, options: impl AsRef) -> Self { + let mut chars: Vec<_> = options.as_ref().chars().collect(); chars.sort_unstable(); let options: String = chars.into_iter().collect(); - Self { pattern, options } + Self { + pattern: pattern.as_ref().to_string(), + options, + } } } @@ -1090,6 +1097,13 @@ impl Binary { }) } } + + pub(crate) fn as_raw_binary(&self) -> RawBinary<'_> { + RawBinary { + bytes: self.bytes.as_slice(), + subtype: self.subtype, + } + } } /// Represents a DBPointer. (Deprecated) diff --git a/src/lib.rs b/src/lib.rs index 164b4456..7d9d23d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,7 +277,7 @@ pub use self::{ }, decimal128::Decimal128, raw::{ - RawArray, RawBinary, RawBson, RawDbPointer, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, + RawArray, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, }, ser::{ diff --git a/src/macros.rs b/src/macros.rs index f14e17fc..d6355591 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -213,179 +213,179 @@ macro_rules! doc { }}; } -#[macro_export] -macro_rules! rawbson { - ////////////////////////////////////////////////////////////////////////// - // TT muncher for parsing the inside of an array [...]. Produces a vec![...] - // of the elements. - // - // Must be invoked as: bson!(@array [] $($tt)*) - ////////////////////////////////////////////////////////////////////////// - - // Finished with trailing comma. - (@array [$($elems:expr,)*]) => { - vec![$($elems,)*] - }; - - // Finished without trailing comma. - (@array [$($elems:expr),*]) => { - vec![$($elems),*] - }; - - // Next element is `null`. - (@array [$($elems:expr,)*] null $($rest:tt)*) => { - $crate::rawbson!(@array [$($elems,)* $crate::rawbson!(null)] $($rest)*) - }; - - // Next element is an array. - (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { - $crate::rawbson!(@array [$($elems,)* $crate::rawbson!([$($array)*])] $($rest)*) - }; - - // Next element is a map. - (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { - $crate::rawbson!(@array [$($elems,)* $crate::rawbson!({$($map)*})] $($rest)*) - }; - - // Next element is an expression followed by comma. - (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { - $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($next),] $($rest)*) - }; - - // Last element is an expression with no trailing comma. - (@array [$($elems:expr,)*] $last:expr) => { - $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($last)]) - }; - - // Comma after the most recent element. - (@array [$($elems:expr),*] , $($rest:tt)*) => { - $crate::rawbson!(@array [$($elems,)*] $($rest)*) - }; - - ////////////////////////////////////////////////////////////////////////// - // TT muncher for parsing the inside of an object {...}. Each entry is - // inserted into the given map variable. - // - // Must be invoked as: bson!(@object $map () ($($tt)*) ($($tt)*)) - // - // We require two copies of the input tokens so that we can match on one - // copy and trigger errors on the other copy. - ////////////////////////////////////////////////////////////////////////// - - // Finished. - (@object $object:ident () () ()) => {}; - - // Insert the current entry followed by trailing comma. - (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { - $object.append(($($key)+), $value); - $crate::rawbson!(@object $object () ($($rest)*) ($($rest)*)); - }; - - // Insert the last entry without trailing comma. - (@object $object:ident [$($key:tt)+] ($value:expr)) => { - $object.append(($($key)+), $value); - }; - - // // Next value is `null`. - // (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { - // $crate::bson!(@object $object [$($key)+] ($crate::bson!(null)) $($rest)*); - // }; - - // Next value is an array. - (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { - $crate::bson!(@object $object [$($key)+] ($crate::bson!([$($array)*])) $($rest)*); - }; - - // Next value is a map. - (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { - $crate::bson!(@object $object [$($key)+] ($crate::bson!({$($map)*})) $($rest)*); - }; - - // Next value is an expression followed by comma. - (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { - $crate::bson!(@object $object [$($key)+] ($crate::bson!($value)) , $($rest)*); - }; - - // Last value is an expression with no trailing comma. - (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { - $crate::bson!(@object $object [$($key)+] ($crate::bson!($value))); - }; - - // Missing value for last entry. Trigger a reasonable error message. - (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { - // "unexpected end of macro invocation" - $crate::bson!(); - }; - - // Missing key-value separator and value for last entry. - // Trigger a reasonable error message. - (@object $object:ident ($($key:tt)+) () $copy:tt) => { - // "unexpected end of macro invocation" - $crate::bson!(); - }; - - // Misplaced key-value separator. Trigger a reasonable error message. - (@object $object:ident () (: $($rest:tt)*) ($kv_separator:tt $($copy:tt)*)) => { - // Takes no arguments so "no rules expected the token `:`". - unimplemented!($kv_separator); - }; - - // Found a comma inside a key. Trigger a reasonable error message. - (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { - // Takes no arguments so "no rules expected the token `,`". - unimplemented!($comma); - }; - - // Key is fully parenthesized. This avoids clippy double_parens false - // positives because the parenthesization may be necessary here. - (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { - $crate::bson!(@object $object ($key) (: $($rest)*) (: $($rest)*)); - }; - - // Munch a token into the current key. - (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { - $crate::bson!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); - }; - - ////////////////////////////////////////////////////////////////////////// - // The main implementation. - // - // Must be invoked as: bson!($($bson)+) - ////////////////////////////////////////////////////////////////////////// - - (null) => { - $crate::Bson::Null - }; - - ([]) => { - $crate::Bson::Array(vec![]) - }; - - ([ $($tt:tt)+ ]) => { - $crate::Bson::Array($crate::bson!(@array [] $($tt)+)) - }; - - ({}) => { - $crate::RawBson::Document($crate::rawdoc!{}) - }; - - ({$($tt:tt)+}) => { - $crate::RawBson::Document($crate::rawdoc!{$($tt)+}) - }; - - // Any Into type. - // Must be below every other rule. - ($other:expr) => { - $crate::RawBson::from($other) - }; -} - -#[macro_export] -macro_rules! rawdoc { - () => {{ $crate::RawDocumentBuf::empty() }}; - ( $($tt:tt)+ ) => {{ - let mut object = $crate::RawDocumentBuf::empty(); - $crate::rawbson!(@object object () ($($tt)+) ($($tt)+)); - object - }}; -} +// #[macro_export] +// macro_rules! rawbson { +// ////////////////////////////////////////////////////////////////////////// +// // TT muncher for parsing the inside of an array [...]. Produces a vec![...] +// // of the elements. +// // +// // Must be invoked as: bson!(@array [] $($tt)*) +// ////////////////////////////////////////////////////////////////////////// + +// // Finished with trailing comma. +// (@array [$($elems:expr,)*]) => { +// vec![$($elems,)*] +// }; + +// // Finished without trailing comma. +// (@array [$($elems:expr),*]) => { +// vec![$($elems),*] +// }; + +// // Next element is `null`. +// (@array [$($elems:expr,)*] null $($rest:tt)*) => { +// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!(null)] $($rest)*) +// }; + +// // Next element is an array. +// (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { +// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!([$($array)*])] $($rest)*) +// }; + +// // Next element is a map. +// (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { +// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!({$($map)*})] $($rest)*) +// }; + +// // Next element is an expression followed by comma. +// (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { +// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($next),] $($rest)*) +// }; + +// // Last element is an expression with no trailing comma. +// (@array [$($elems:expr,)*] $last:expr) => { +// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($last)]) +// }; + +// // Comma after the most recent element. +// (@array [$($elems:expr),*] , $($rest:tt)*) => { +// $crate::rawbson!(@array [$($elems,)*] $($rest)*) +// }; + +// ////////////////////////////////////////////////////////////////////////// +// // TT muncher for parsing the inside of an object {...}. Each entry is +// // inserted into the given map variable. +// // +// // Must be invoked as: bson!(@object $map () ($($tt)*) ($($tt)*)) +// // +// // We require two copies of the input tokens so that we can match on one +// // copy and trigger errors on the other copy. +// ////////////////////////////////////////////////////////////////////////// + +// // Finished. +// (@object $object:ident () () ()) => {}; + +// // Insert the current entry followed by trailing comma. +// (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { +// $object.append(($($key)+), $value); +// $crate::rawbson!(@object $object () ($($rest)*) ($($rest)*)); +// }; + +// // Insert the last entry without trailing comma. +// (@object $object:ident [$($key:tt)+] ($value:expr)) => { +// $object.append(($($key)+), $value); +// }; + +// // // Next value is `null`. +// // (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { +// // $crate::bson!(@object $object [$($key)+] ($crate::bson!(null)) $($rest)*); +// // }; + +// // Next value is an array. +// (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { +// $crate::bson!(@object $object [$($key)+] ($crate::bson!([$($array)*])) $($rest)*); +// }; + +// // Next value is a map. +// (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { +// $crate::bson!(@object $object [$($key)+] ($crate::bson!({$($map)*})) $($rest)*); +// }; + +// // Next value is an expression followed by comma. +// (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { +// $crate::bson!(@object $object [$($key)+] ($crate::bson!($value)) , $($rest)*); +// }; + +// // Last value is an expression with no trailing comma. +// (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { +// $crate::bson!(@object $object [$($key)+] ($crate::bson!($value))); +// }; + +// // Missing value for last entry. Trigger a reasonable error message. +// (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { +// // "unexpected end of macro invocation" +// $crate::bson!(); +// }; + +// // Missing key-value separator and value for last entry. +// // Trigger a reasonable error message. +// (@object $object:ident ($($key:tt)+) () $copy:tt) => { +// // "unexpected end of macro invocation" +// $crate::bson!(); +// }; + +// // Misplaced key-value separator. Trigger a reasonable error message. +// (@object $object:ident () (: $($rest:tt)*) ($kv_separator:tt $($copy:tt)*)) => { +// // Takes no arguments so "no rules expected the token `:`". +// unimplemented!($kv_separator); +// }; + +// // Found a comma inside a key. Trigger a reasonable error message. +// (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { +// // Takes no arguments so "no rules expected the token `,`". +// unimplemented!($comma); +// }; + +// // Key is fully parenthesized. This avoids clippy double_parens false +// // positives because the parenthesization may be necessary here. +// (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { +// $crate::bson!(@object $object ($key) (: $($rest)*) (: $($rest)*)); +// }; + +// // Munch a token into the current key. +// (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { +// $crate::bson!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); +// }; + +// ////////////////////////////////////////////////////////////////////////// +// // The main implementation. +// // +// // Must be invoked as: bson!($($bson)+) +// ////////////////////////////////////////////////////////////////////////// + +// (null) => { +// $crate::Bson::Null +// }; + +// ([]) => { +// $crate::Bson::Array(vec![]) +// }; + +// ([ $($tt:tt)+ ]) => { +// $crate::Bson::Array($crate::bson!(@array [] $($tt)+)) +// }; + +// ({}) => { +// $crate::RawBson::Document($crate::rawdoc!{}) +// }; + +// ({$($tt:tt)+}) => { +// $crate::RawBson::Document($crate::rawdoc!{$($tt)+}) +// }; + +// // Any Into type. +// // Must be below every other rule. +// ($other:expr) => { +// $crate::RawBson::from($other) +// }; +// } + +// #[macro_export] +// macro_rules! rawdoc { +// () => {{ $crate::RawDocumentBuf::empty() }}; +// ( $($tt:tt)+ ) => {{ +// let mut object = $crate::RawDocumentBuf::empty(); +// $crate::rawbson!(@object object () ($($tt)+) ($($tt)+)); +// object +// }}; +// } diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs new file mode 100644 index 00000000..2bb735db --- /dev/null +++ b/src/raw/array_buf.rs @@ -0,0 +1,47 @@ +use std::borrow::Borrow; + +use crate::{RawArray, RawBson, RawDocumentBuf}; + +#[derive(Clone)] +pub struct RawArrayBuf { + inner: RawDocumentBuf, + len: usize, +} + +impl RawArrayBuf { + pub fn new() -> RawArrayBuf { + Self { + inner: RawDocumentBuf::empty(), + len: 0, + } + } + + pub fn append<'a>(&mut self, value: impl Into>) { + self.inner.append(self.len.to_string(), value); + self.len += 1; + } + + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_bytes() + } +} + +impl std::ops::Deref for RawArrayBuf { + type Target = RawArray; + + fn deref(&self) -> &Self::Target { + RawArray::from_doc(&self.inner) + } +} + +impl AsRef for RawArrayBuf { + fn as_ref(&self) -> &RawArray { + RawArray::from_doc(&self.inner) + } +} + +impl Borrow for RawArrayBuf { + fn borrow(&self) -> &RawArray { + self.as_ref() + } +} diff --git a/src/raw/bson.rs b/src/raw/bson.rs index 3402c11b..b3dfd234 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -1,4 +1,7 @@ -use std::convert::{TryFrom, TryInto}; +use std::{ + convert::{TryFrom, TryInto}, + iter::FromIterator, +}; use serde::{de::Visitor, ser::SerializeStruct, Deserialize, Serialize}; use serde_bytes::{ByteBuf, Bytes}; @@ -10,10 +13,14 @@ use crate::{ oid::{self, ObjectId}, raw::{RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::{BinarySubtype, ElementType}, + Binary, Bson, DateTime, DbPointer, Decimal128, + JavaScriptCodeWithScope, + RawArrayBuf, + RawDocumentBuf, Timestamp, }; @@ -607,6 +614,84 @@ impl<'a> TryFrom> for Bson { } } +impl<'a> From for RawBson<'a> { + fn from(i: i32) -> Self { + RawBson::Int32(i) + } +} + +impl<'a> From for RawBson<'a> { + fn from(i: i64) -> Self { + RawBson::Int64(i) + } +} + +impl<'a> From<&'a str> for RawBson<'a> { + fn from(s: &'a str) -> Self { + RawBson::String(s) + } +} + +impl<'a> From for RawBson<'a> { + fn from(f: f64) -> Self { + RawBson::Double(f) + } +} + +impl<'a> From for RawBson<'a> { + fn from(b: bool) -> Self { + RawBson::Boolean(b) + } +} + +impl<'a> From<&'a RawDocumentBuf> for RawBson<'a> { + fn from(d: &'a RawDocumentBuf) -> Self { + RawBson::Document(d.as_ref()) + } +} + +impl<'a> From<&'a RawDocument> for RawBson<'a> { + fn from(d: &'a RawDocument) -> Self { + RawBson::Document(d) + } +} + +impl<'a> From<&'a RawArray> for RawBson<'a> { + fn from(a: &'a RawArray) -> Self { + RawBson::Array(a) + } +} + +impl<'a> From<&'a RawArrayBuf> for RawBson<'a> { + fn from(a: &'a RawArrayBuf) -> Self { + RawBson::Array(a) + } +} + +impl<'a> From for RawBson<'a> { + fn from(dt: crate::DateTime) -> Self { + RawBson::DateTime(dt) + } +} + +impl<'a> From for RawBson<'a> { + fn from(ts: Timestamp) -> Self { + RawBson::Timestamp(ts) + } +} + +impl<'a> From for RawBson<'a> { + fn from(oid: ObjectId) -> Self { + RawBson::ObjectId(oid) + } +} + +impl<'a> From for RawBson<'a> { + fn from(d: Decimal128) -> Self { + RawBson::Decimal128(d) + } +} + /// A BSON binary value referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawBinary<'a> { @@ -617,6 +702,15 @@ pub struct RawBinary<'a> { pub bytes: &'a [u8], } +impl<'a> RawBinary<'a> { + pub(crate) fn len(&self) -> i32 { + match self.subtype { + BinarySubtype::BinaryOld => self.bytes.len() as i32 + 4, + _ => self.bytes.len() as i32, + } + } +} + impl<'de: 'a, 'a> Deserialize<'de> for RawBinary<'a> { fn deserialize(deserializer: D) -> std::result::Result where @@ -667,6 +761,18 @@ impl<'a> Serialize for RawBinary<'a> { } } +impl<'a> From> for RawBson<'a> { + fn from(b: RawBinary<'a>) -> Self { + RawBson::Binary(b) + } +} + +impl<'a> From<&'a Binary> for RawBson<'a> { + fn from(bin: &'a Binary) -> Self { + bin.as_raw_binary().into() + } +} + /// A BSON regex referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawRegex<'a> { @@ -722,6 +828,12 @@ impl<'a> Serialize for RawRegex<'a> { } } +impl<'a> From> for RawBson<'a> { + fn from(re: RawRegex<'a>) -> Self { + RawBson::RegularExpression(re) + } +} + /// A BSON "code with scope" value referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawJavaScriptCodeWithScope<'a> { @@ -740,6 +852,10 @@ impl<'a> RawJavaScriptCodeWithScope<'a> { pub fn scope(self) -> &'a RawDocument { self.scope } + + pub(crate) fn len(self) -> i32 { + 4 + 4 + self.code.len() as i32 + 1 + self.scope.len() as i32 + } } impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScope<'a> { @@ -769,6 +885,12 @@ impl<'a> Serialize for RawJavaScriptCodeWithScope<'a> { } } +impl<'a> From> for RawBson<'a> { + fn from(code_w_scope: RawJavaScriptCodeWithScope<'a>) -> Self { + RawBson::JavaScriptCodeWithScope(code_w_scope) + } +} + /// A BSON DB pointer value referencing raw bytes stored elesewhere. #[derive(Debug, Clone, Copy, PartialEq)] pub struct RawDbPointer<'a> { diff --git a/src/raw/document.rs b/src/raw/document.rs index 34c1ef45..5bbcee80 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -487,6 +487,11 @@ impl RawDocument { pub fn as_bytes(&self) -> &[u8] { &self.data } + + /// The number of bytes in this document. + pub fn len(&self) -> usize { + self.data.len() + } } impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 83e7c003..422e291a 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -7,7 +7,11 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{de::MIN_BSON_DOCUMENT_SIZE, spec::ElementType, Document}; +use crate::{ + de::MIN_BSON_DOCUMENT_SIZE, + spec::{BinarySubtype, ElementType}, + Document, +}; use super::{Error, ErrorKind, Iter, RawBson, RawDocument, Result}; @@ -151,24 +155,94 @@ impl RawDocumentBuf { self.append(key, RawBson::Document(&value)) } - pub fn append<'a>(&mut self, key: impl AsRef, value: RawBson<'a>) { + pub fn append<'a>(&mut self, key: impl AsRef, value: impl Into>) { + fn append_str(doc: &mut RawDocumentBuf, value: &str) { + doc.data + .extend(((value.as_bytes().len() + 1) as i32).to_le_bytes()); + doc.data.extend(value.as_bytes()); + doc.data.push(0); + } + + fn append_cstr(doc: &mut RawDocumentBuf, value: &str) { + if value.contains('\0') { + panic!("cstr includes interior null byte: {}", value) + } + doc.data.extend(value.as_bytes()); + doc.data.push(0); + } + let original_len = self.data.len(); - let key_bytes = key.as_ref().as_bytes(); - let key = CString::new(key_bytes).unwrap(); - self.data.extend(key.to_bytes_with_nul()); + + // write the key for the next value to the end + // the element type will replace the previous null byte terminator of the document + append_cstr(self, key.as_ref()); + + let value = value.into(); + match value { RawBson::Int32(i) => { self.data.extend(i.to_le_bytes()); - }, + } RawBson::String(s) => { - self.data.extend(((s.as_bytes().len() + 1) as i32).to_le_bytes()); - self.data.extend(s.as_bytes()); - self.data.push(0); - }, + append_str(self, s); + } RawBson::Document(d) => { self.data.extend(d.as_bytes()); } - _ => todo!(), + RawBson::Array(a) => { + self.data.extend(a.as_bytes()); + } + RawBson::Binary(b) => { + self.data.extend(b.len().to_le_bytes()); + self.data.push(b.subtype.into()); + if let BinarySubtype::BinaryOld = b.subtype { + self.data.extend((b.len() - 4).to_le_bytes()) + } + self.data.extend(b.bytes); + } + RawBson::Boolean(b) => { + let byte = if b { 1 } else { 0 }; + self.data.push(byte); + } + RawBson::DateTime(dt) => { + self.data.extend(dt.timestamp_millis().to_le_bytes()); + } + RawBson::DbPointer(dbp) => { + append_str(self, dbp.namespace); + self.data.extend(dbp.id.bytes()); + } + RawBson::Decimal128(d) => { + self.data.extend(d.bytes()); + } + RawBson::Double(d) => { + self.data.extend(d.to_le_bytes()); + } + RawBson::Int64(i) => { + self.data.extend(i.to_le_bytes()); + } + RawBson::RegularExpression(re) => { + append_cstr(self, re.pattern); + append_cstr(self, re.options); + } + RawBson::JavaScriptCode(js) => { + append_str(self, js); + } + RawBson::JavaScriptCodeWithScope(code_w_scope) => { + let len = code_w_scope.len(); + self.data.extend(len.to_le_bytes()); + append_str(self, code_w_scope.code); + self.data.extend(code_w_scope.scope.as_bytes()); + } + RawBson::Timestamp(ts) => { + self.data.extend(ts.to_le_i64().to_le_bytes()); + } + RawBson::ObjectId(oid) => { + self.data.extend(oid.bytes()); + } + RawBson::Symbol(s) => { + append_str(self, s); + } + RawBson::Null | RawBson::Undefined | RawBson::MinKey | RawBson::MaxKey => {} } // update element type self.data[original_len - 1] = value.element_type() as u8; diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 89c16ea1..a0aeb47a 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -113,6 +113,7 @@ //! ``` mod array; +mod array_buf; mod bson; mod document; mod document_buf; @@ -127,6 +128,7 @@ use crate::de::MIN_BSON_STRING_SIZE; pub use self::{ array::{RawArray, RawArrayIter}, + array_buf::RawArrayBuf, bson::{RawBinary, RawBson, RawDbPointer, RawJavaScriptCodeWithScope, RawRegex}, document::RawDocument, document_buf::RawDocumentBuf, diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs new file mode 100644 index 00000000..b9a329be --- /dev/null +++ b/src/raw/test/append.rs @@ -0,0 +1,341 @@ +use crate::{ + oid::ObjectId, + spec::BinarySubtype, + tests::LOCK, + Binary, + Bson, + DateTime, + DbPointer, + Decimal128, + Document, + JavaScriptCodeWithScope, + RawArrayBuf, + RawBinary, + RawBson, + RawDbPointer, + RawDocument, + RawDocumentBuf, + RawJavaScriptCodeWithScope, + RawRegex, + Regex, + Timestamp, +}; + +use pretty_assertions::assert_eq; + +fn append_test(expected: Document, append: impl FnOnce(&mut RawDocumentBuf)) { + let bytes = crate::to_vec(&expected).unwrap(); + let mut buf = RawDocumentBuf::empty(); + append(&mut buf); + assert_eq!(buf.as_bytes(), bytes); +} + +#[test] +fn i32() { + let expected = doc! { + "a": -1_i32, + "b": 123_i32, + "c": 0_i32 + }; + append_test(expected, |doc| { + doc.append("a", -1_i32); + doc.append("b", 123_i32); + doc.append("c", 0_i32); + }); +} + +#[test] +fn i64() { + let expected = doc! { + "a": -1_i64, + "b": 123_i64, + "c": 0_i64 + }; + append_test(expected, |doc| { + doc.append("a", -1_i64); + doc.append("b", 123_i64); + doc.append("c", 0_i64); + }); +} + +#[test] +fn str() { + let expected = doc! { + "first": "the quick", + "second": "brown fox", + "third": "jumped over", + "last": "the lazy sheep dog", + }; + append_test(expected, |doc| { + doc.append("first", "the quick"); + doc.append("second", "brown fox"); + doc.append("third", "jumped over"); + doc.append("last", "the lazy sheep dog"); + }); +} + +#[test] +fn double() { + let expected = doc! { + "positive": 12.5, + "0": 0.0, + "negative": -123.24, + "nan": f64::NAN, + "inf": f64::INFINITY, + }; + append_test(expected, |doc| { + doc.append("positive", 12.5); + doc.append("0", 0.0); + doc.append("negative", -123.24); + doc.append("nan", f64::NAN); + doc.append("inf", f64::INFINITY); + }); +} + +#[test] +fn boolean() { + let expected = doc! { + "true": true, + "false": false, + }; + append_test(expected, |doc| { + doc.append("true", true); + doc.append("false", false); + }); +} + +#[test] +fn null() { + let expected = doc! { + "null": null, + }; + append_test(expected, |doc| { + doc.append("null", RawBson::Null); + }); +} + +#[test] +fn document() { + let expected = doc! { + "empty": {}, + "subdoc": { + "a": 1_i32, + "b": true, + } + }; + append_test(expected, |doc| { + doc.append("empty", &RawDocumentBuf::empty()); + let mut buf = RawDocumentBuf::empty(); + buf.append("a", 1_i32); + buf.append("b", true); + doc.append("subdoc", &buf); + }); +} + +#[test] +fn array() { + let expected = doc! { + "empty": [], + "array": [ + true, + "string", + { "a": "subdoc" }, + 123_i32 + ] + }; + append_test(expected, |doc| { + doc.append("empty", &RawArrayBuf::new()); + let mut buf = RawArrayBuf::new(); + buf.append(true); + buf.append("string"); + let mut subdoc = RawDocumentBuf::empty(); + subdoc.append("a", "subdoc"); + buf.append(&subdoc); + buf.append(123_i32); + doc.append("array", &buf); + }); +} + +#[test] +fn oid() { + let _guard = LOCK.run_concurrently(); + + let oid = ObjectId::new(); + let expected = doc! { + "oid": oid, + }; + append_test(expected, |doc| doc.append("oid", oid)); +} + +#[test] +fn datetime() { + let dt = DateTime::now(); + let old = DateTime::from_millis(-1); + + let expected = doc! { + "now": dt, + "old": old + }; + + append_test(expected, |doc| { + doc.append("now", dt); + doc.append("old", old); + }); +} + +#[test] +fn timestamp() { + let ts = Timestamp { + time: 123, + increment: 2, + }; + + let expected = doc! { + "ts": ts, + }; + + append_test(expected, |doc| { + doc.append("ts", ts); + }); +} + +#[test] +fn binary() { + let bytes = vec![1, 2, 3, 4]; + + let bin = Binary { + bytes: bytes.clone(), + subtype: BinarySubtype::Generic, + }; + + let old = Binary { + bytes: bytes.clone(), + subtype: BinarySubtype::BinaryOld, + }; + + let expected = doc! { + "generic": bin.clone(), + "binary_old": old.clone(), + }; + + append_test(expected, |doc| { + doc.append("generic", &bin); + doc.append("binary_old", &old); + }); +} + +#[test] +fn min_max_key() { + let expected = doc! { + "min": Bson::MinKey, + "max": Bson::MaxKey + }; + + append_test(expected, |doc| { + doc.append("min", RawBson::MinKey); + doc.append("max", RawBson::MaxKey); + }); +} + +#[test] +fn undefined() { + let expected = doc! { + "undefined": Bson::Undefined, + }; + + append_test(expected, |doc| { + doc.append("undefined", RawBson::Undefined); + }); +} + +#[test] +fn regex() { + let expected = doc! { + "regex": Regex::new("some pattern", "abc"), + }; + + append_test(expected, |doc| { + doc.append( + "regex", + RawRegex { + pattern: "some pattern", + options: "abc", + }, + ) + }); +} + +#[test] +fn code() { + let code_w_scope = JavaScriptCodeWithScope { + code: "some code".to_string(), + scope: doc! { "a": 1_i32, "b": true }, + }; + + let expected = doc! { + "code": Bson::JavaScriptCode("some code".to_string()), + "code_w_scope": code_w_scope, + }; + + append_test(expected, |doc| { + doc.append("code", RawBson::JavaScriptCode("some code")); + + let mut scope = RawDocumentBuf::empty(); + scope.append("a", 1_i32); + scope.append("b", true); + doc.append( + "code_w_scope", + RawJavaScriptCodeWithScope { + code: "some code", + scope: &scope, + }, + ); + }); +} + +#[test] +fn symbol() { + let expected = doc! { + "symbol": Bson::Symbol("symbol".to_string()) + }; + + append_test(expected, |doc| { + doc.append("symbol", RawBson::Symbol("symbol")); + }); +} + +#[test] +fn dbpointer() { + let _guard = LOCK.run_concurrently(); + + let id = ObjectId::new(); + + let expected = doc! { + "symbol": Bson::DbPointer(DbPointer { + namespace: "ns".to_string(), + id + }) + }; + + append_test(expected, |doc| { + doc.append( + "symbol", + RawBson::DbPointer(RawDbPointer { + namespace: "ns", + id, + }), + ); + }); +} + +#[test] +fn decimal128() { + let decimal = Decimal128 { bytes: [1; 16] }; + let expected = doc! { + "decimal": decimal + }; + + append_test(expected, |doc| { + doc.append("decimal", decimal); + }); +} diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index 96e7b22f..f5919ea0 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -1,7 +1,20 @@ +mod append; mod props; use super::*; -use crate::{Binary, Bson, DateTime, Document, JavaScriptCodeWithScope, Regex, Timestamp, doc, oid::ObjectId, raw::error::ValueAccessErrorKind, spec::BinarySubtype}; +use crate::{ + doc, + oid::ObjectId, + raw::error::ValueAccessErrorKind, + spec::BinarySubtype, + Binary, + Bson, + DateTime, + Document, + JavaScriptCodeWithScope, + Regex, + Timestamp, +}; use chrono::{TimeZone, Utc}; fn to_bytes(doc: &crate::Document) -> Vec { diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 5341c38f..12b8bbb7 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -37,6 +37,7 @@ use crate::{ de::MAX_BSON_SIZE, spec::BinarySubtype, Binary, + RawJavaScriptCodeWithScope, }; use ::serde::{ser::Error as SerdeError, Serialize}; diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs index 49880a85..d5c7bca7 100644 --- a/src/ser/raw/value_serializer.rs +++ b/src/ser/raw/value_serializer.rs @@ -10,6 +10,8 @@ use crate::{ raw::RAW_DOCUMENT_NEWTYPE, ser::{write_binary, write_cstring, write_i32, write_i64, write_string, Error, Result}, spec::{BinarySubtype, ElementType}, + RawDocument, + RawJavaScriptCodeWithScope, }; use super::{document_serializer::DocumentSerializer, Serializer}; @@ -306,8 +308,11 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> { Ok(()) } SerializationStep::CodeWithScopeScope { ref code, raw } if raw => { - let len = 4 + 4 + code.len() as i32 + 1 + v.len() as i32; - write_i32(&mut self.root_serializer.bytes, len)?; + let raw = RawJavaScriptCodeWithScope { + code, + scope: RawDocument::new(v).map_err(Error::custom)?, + }; + write_i32(&mut self.root_serializer.bytes, raw.len())?; write_string(&mut self.root_serializer.bytes, code)?; self.root_serializer.bytes.write_all(v)?; self.state = SerializationStep::Done; From 021f1f84372176fc95b97d6bb98806f1b715c444 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Tue, 16 Nov 2021 15:58:35 -0500 Subject: [PATCH 03/21] wip array buf stuff --- src/raw/array_buf.rs | 12 +++++++- src/raw/document_buf.rs | 17 +++++++---- src/raw/test/append.rs | 63 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index 2bb735db..19fd4b50 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -1,4 +1,4 @@ -use std::borrow::Borrow; +use std::{borrow::Borrow, iter::FromIterator}; use crate::{RawArray, RawBson, RawDocumentBuf}; @@ -45,3 +45,13 @@ impl Borrow for RawArrayBuf { self.as_ref() } } + +impl<'a, T: Into>> FromIterator for RawArrayBuf { + fn from_iter>(iter: I) -> Self { + let mut array_buf = RawArrayBuf::new(); + for item in iter { + array_buf.append(item); + } + array_buf + } +} diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 422e291a..61729ffd 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -1,9 +1,4 @@ -use std::{ - borrow::{Borrow, Cow}, - convert::{TryFrom, TryInto}, - ffi::CString, - ops::Deref, -}; +use std::{borrow::{Borrow, Cow}, convert::{TryFrom, TryInto}, ffi::CString, iter::FromIterator, ops::Deref}; use serde::{Deserialize, Serialize}; @@ -335,3 +330,13 @@ impl Borrow for RawDocumentBuf { &*self } } + +impl<'a, 'b, T: Into>> FromIterator<(&'a str, T)> for RawDocumentBuf { + fn from_iter>(iter: I) -> Self { + let mut buf = RawDocumentBuf::empty(); + for (k, v) in iter { + buf.append(k, v); + } + buf + } +} diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs index b9a329be..ee4f415d 100644 --- a/src/raw/test/append.rs +++ b/src/raw/test/append.rs @@ -1,3 +1,5 @@ +use std::iter::FromIterator; + use crate::{ oid::ObjectId, spec::BinarySubtype, @@ -339,3 +341,64 @@ fn decimal128() { doc.append("decimal", decimal); }); } + +#[test] +fn general() { + let dt = DateTime::now(); + let expected = doc! { + "a": true, + "second key": 123.4, + "third": 15_i64, + "32": -100101_i32, + "subdoc": { + "a": "subkey", + "another": { "subdoc": dt } + }, + "array": [1_i64, true, { "doc": 23_i64 }, ["another", "array"]], + }; + + append_test(expected, |doc| { + doc.append("a", true); + doc.append("second key", 123.4); + doc.append("third", 15_i64); + doc.append("32", -100101_i32); + + let mut subdoc = RawDocumentBuf::empty(); + subdoc.append("a", "subkey"); + + let mut subsubdoc = RawDocumentBuf::empty(); + subsubdoc.append("subdoc", dt); + subdoc.append("another", &subsubdoc); + doc.append("subdoc", &subdoc); + + let mut array = RawArrayBuf::new(); + array.append(1_i64); + array.append(true); + + let mut array_subdoc = RawDocumentBuf::empty(); + array_subdoc.append("doc", 23_i64); + array.append(&array_subdoc); + + let mut sub_array = RawArrayBuf::new(); + sub_array.append("another"); + sub_array.append("array"); + array.append(&sub_array); + + doc.append("array", &array); + }); +} + +#[test] +fn from_iter() { + let mut doc = RawDocumentBuf::empty(); + doc.append("ok", false); + doc.append("other", "hello"); + + let ab = RawArrayBuf::from_iter(vec![ + RawBson::Boolean(true), + RawBson::Document(&RawDocumentBuf::from_iter(vec![ + ("ok", RawBson::Boolean(false)), + ("other", RawBson::String("hello")) + ])) + ]); +} From b2783d07fca010bb056c060dc922a722c37c9d52 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Tue, 16 Nov 2021 16:51:40 -0500 Subject: [PATCH 04/21] wip wip --- src/raw/array.rs | 27 ++++++++++++------ src/raw/array_buf.rs | 48 +++++++++++++++++++++++++++++-- src/raw/bson.rs | 6 ++++ src/raw/document_buf.rs | 2 +- src/raw/test/append.rs | 63 +++++++++++++++++++++-------------------- 5 files changed, 105 insertions(+), 41 deletions(-) diff --git a/src/raw/array.rs b/src/raw/array.rs index 665c5632..188be715 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -12,14 +12,7 @@ use super::{ RawRegex, Result, }; -use crate::{ - oid::ObjectId, - raw::{RawBsonVisitor, RAW_ARRAY_NEWTYPE}, - spec::{BinarySubtype, ElementType}, - Bson, - DateTime, - Timestamp, -}; +use crate::{Bson, DateTime, RawArrayBuf, Timestamp, oid::ObjectId, raw::{RawBsonVisitor, RAW_ARRAY_NEWTYPE}, spec::{BinarySubtype, ElementType}}; /// A slice of a BSON document containing a BSON array value (akin to [`std::str`]). This can be /// retrieved from a [`RawDocument`] via [`RawDocument::get`]. @@ -90,6 +83,10 @@ impl RawArray { unsafe { &*(doc as *const RawDocument as *const RawArray) } } + pub fn to_raw_array_buf(&self) -> RawArrayBuf { + RawArrayBuf::from + } + /// Gets a reference to the value at the given index. pub fn get(&self, index: usize) -> Result>> { self.into_iter().nth(index).transpose() @@ -222,6 +219,20 @@ impl TryFrom<&RawArray> for Vec { } } +impl ToOwned for RawArray { + type Owned = RawArrayBuf; + + fn to_owned(&self) -> Self::Owned { + self.into_iter().collect() + } +} + +impl<'a> From<&'a RawDocument> for Cow<'a, RawDocument> { + fn from(rdr: &'a RawDocument) -> Self { + Cow::Borrowed(rdr) + } +} + impl<'a> IntoIterator for &'a RawArray { type IntoIter = RawArrayIter<'a>; type Item = Result>; diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index 19fd4b50..1436bb5b 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -1,6 +1,12 @@ -use std::{borrow::Borrow, iter::FromIterator}; +use std::{ + borrow::{Borrow, Cow}, + fmt::Debug, + iter::FromIterator, +}; -use crate::{RawArray, RawBson, RawDocumentBuf}; +use crate::{raw::Result, RawArray, RawBson, RawDocumentBuf}; + +use super::RawArrayIter; #[derive(Clone)] pub struct RawArrayBuf { @@ -9,6 +15,7 @@ pub struct RawArrayBuf { } impl RawArrayBuf { + /// Construct a new, empty `RawArrayBuf`. pub fn new() -> RawArrayBuf { Self { inner: RawDocumentBuf::empty(), @@ -16,6 +23,13 @@ impl RawArrayBuf { } } + pub fn from_vec(bytes: Vec) -> Result { + let doc = RawDocumentBuf::new(bytes)?; + let len = doc.iter().count(); + + Ok(Self { inner: doc, len }) + } + pub fn append<'a>(&mut self, value: impl Into>) { self.inner.append(self.len.to_string(), value); self.len += 1; @@ -26,6 +40,15 @@ impl RawArrayBuf { } } +impl Debug for RawArrayBuf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RawArrayBuf") + .field("data", &hex::encode(self.as_bytes())) + .field("len", &self.len) + .finish() + } +} + impl std::ops::Deref for RawArrayBuf { type Target = RawArray; @@ -46,6 +69,27 @@ impl Borrow for RawArrayBuf { } } +impl<'a> IntoIterator for &'a RawArrayBuf { + type IntoIter = RawArrayIter<'a>; + type Item = super::Result>; + + fn into_iter(self) -> RawArrayIter<'a> { + self.deref().into_iter() + } +} + +impl<'a> From for Cow<'a, RawArray> { + fn from(rd: RawArrayBuf) -> Self { + Cow::Owned(rd) + } +} + +impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> { + fn from(rd: &'a RawArrayBuf) -> Self { + Cow::Borrowed(rd.as_ref()) + } +} + impl<'a, T: Into>> FromIterator for RawArrayBuf { fn from_iter>(iter: I) -> Self { let mut array_buf = RawArrayBuf::new(); diff --git a/src/raw/bson.rs b/src/raw/bson.rs index b3dfd234..be5cb89e 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -692,6 +692,12 @@ impl<'a> From for RawBson<'a> { } } +impl<'a, 'b> From<&'a RawBson<'b>> for RawBson<'b> { + fn from(b: &'a RawBson<'b>) -> Self { + *b + } +} + /// A BSON binary value referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawBinary<'a> { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 61729ffd..432ec7f3 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -331,7 +331,7 @@ impl Borrow for RawDocumentBuf { } } -impl<'a, 'b, T: Into>> FromIterator<(&'a str, T)> for RawDocumentBuf { +impl<'a, T: Into>> FromIterator<(&'a str, T)> for RawDocumentBuf { fn from_iter>(iter: I) -> Self { let mut buf = RawDocumentBuf::empty(); for (k, v) in iter { diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs index ee4f415d..4a543281 100644 --- a/src/raw/test/append.rs +++ b/src/raw/test/append.rs @@ -1,26 +1,9 @@ use std::iter::FromIterator; use crate::{ - oid::ObjectId, - spec::BinarySubtype, - tests::LOCK, - Binary, - Bson, - DateTime, - DbPointer, - Decimal128, - Document, - JavaScriptCodeWithScope, - RawArrayBuf, - RawBinary, - RawBson, - RawDbPointer, - RawDocument, - RawDocumentBuf, - RawJavaScriptCodeWithScope, - RawRegex, - Regex, - Timestamp, + oid::ObjectId, spec::BinarySubtype, tests::LOCK, Binary, Bson, DateTime, DbPointer, Decimal128, + Document, JavaScriptCodeWithScope, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, + RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, Regex, Timestamp, }; use pretty_assertions::assert_eq; @@ -390,15 +373,35 @@ fn general() { #[test] fn from_iter() { - let mut doc = RawDocumentBuf::empty(); - doc.append("ok", false); - doc.append("other", "hello"); - - let ab = RawArrayBuf::from_iter(vec![ - RawBson::Boolean(true), - RawBson::Document(&RawDocumentBuf::from_iter(vec![ - ("ok", RawBson::Boolean(false)), - ("other", RawBson::String("hello")) - ])) + let doc_buf = RawDocumentBuf::from_iter([ + ( + "array", + RawBson::Array(&RawArrayBuf::from_iter([ + RawBson::Boolean(true), + RawBson::Document(&RawDocumentBuf::from_iter([ + ("ok", RawBson::Boolean(false)), + ("other", RawBson::String("hello")), + ])), + ])), + ), + ("bool", RawBson::Boolean(true)), + ("string", RawBson::String("some string")) ]); + + let doc = doc! { + "array": [ + true, + { + "ok": false, + "other": "hello" + } + ], + "bool": true, + "string": "some string" + }; + + let expected = doc! { "expected": doc }; + append_test(expected, |doc| { + doc.append("expected", &doc_buf); + }); } From 4c4b93be2a2f45a095e0fc2b2e3ca4d7adf60f4c Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Wed, 17 Nov 2021 14:46:53 -0500 Subject: [PATCH 05/21] rename bson.rs -> bson_ref.rs --- src/raw/{bson.rs => bson_ref.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/raw/{bson.rs => bson_ref.rs} (100%) diff --git a/src/raw/bson.rs b/src/raw/bson_ref.rs similarity index 100% rename from src/raw/bson.rs rename to src/raw/bson_ref.rs From 6eaff65da59907435abd076afdea97e5eb90f63b Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Wed, 17 Nov 2021 15:03:10 -0500 Subject: [PATCH 06/21] document arraybuf --- src/raw/array.rs | 3 ++ src/raw/array_buf.rs | 86 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/raw/array.rs b/src/raw/array.rs index 188be715..e6a333d0 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -83,6 +83,9 @@ impl RawArray { unsafe { &*(doc as *const RawDocument as *const RawArray) } } + /// Convert this borrowed [`RawArray`] into an owned [`RawArrayBuf`]. + /// + /// This involves a traversal of the array to count the values. pub fn to_raw_array_buf(&self) -> RawArrayBuf { RawArrayBuf::from } diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index 1436bb5b..cafeb83b 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -8,7 +8,38 @@ use crate::{raw::Result, RawArray, RawBson, RawDocumentBuf}; use super::RawArrayIter; -#[derive(Clone)] +/// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes. +/// This type can be used to construct owned array values, which can be used to append to [`RawDocumentBuf`] +/// or as a field in a `Deserialize` struct. +/// +/// Iterating over a [`RawArrayBuf`] yields either an error or a key-value pair that borrows from +/// the original document without making any additional allocations. +/// ``` +/// # use bson::raw::Error; +/// use bson::raw::RawDocumentBuf; +/// +/// let mut array = RawArrayBuf::new(); +/// array.append("a string"); +/// array.append(12_i32); +/// +/// let mut iter = array.iter(); +/// +/// let value = iter.next().unwrap()?; +/// assert_eq!(value.as_str(), Some("a string")); +/// +/// let value = iter.next().unwrap()?; +/// assert_eq!(value.as_i32(), Some(12)); +/// +/// assert!(iter.next().is_none()); +/// # Ok::<(), Error>(()) +/// ``` +/// +/// This type implements `Deref` to [`RawArray`], meaning that all methods on [`RawArray`] are +/// available on [`RawArrayBuf`] values as well. This includes [`RawArray::get`] or any of the +/// type-specific getters, such as [`RawArray::get_object_id`] or [`RawArray::get_str`]. Note +/// that accessing elements is an O(N) operation, as it requires iterating through the document from +/// the beginning to find the requested key. +#[derive(Clone, PartialEq)] pub struct RawArrayBuf { inner: RawDocumentBuf, len: usize, @@ -23,20 +54,55 @@ impl RawArrayBuf { } } - pub fn from_vec(bytes: Vec) -> Result { - let doc = RawDocumentBuf::new(bytes)?; + /// Construct a new `RawArrayBuf` from the provided `Vec` of bytes. + /// + /// This involves a traversal of the array to count the values. + pub(crate) fn from_raw_document_buf(doc: RawDocumentBuf) -> Self { let len = doc.iter().count(); - - Ok(Self { inner: doc, len }) + Self { inner: doc, len } } - pub fn append<'a>(&mut self, value: impl Into>) { + /// Append a value to the end of the array. + /// + /// ``` + /// # use bson::raw::Error; + /// use bson::raw::{RawArrayBuf, RawDocumentBuf}; + /// + /// let mut array = RawArrayBuf::new(); + /// array.push("a string"); + /// array.push(12_i32); + /// + /// let mut doc = RawDocumentBuf::new(); + /// doc.append("a key", "a value"); + /// array.push(&doc); + /// + /// assert_eq!(array.len(), 3); + /// + /// let mut iter = array.iter(); + /// + /// let value = iter.next().unwrap()?; + /// assert_eq!(value.as_str(), Some("a string")); + /// + /// let value = iter.next().unwrap()?; + /// assert_eq!(value.as_i32(), Some(12)); + /// + /// let value = iter.next().unwrap()?; + /// assert_eq!(value.as_document(), Some(&doc)); + /// + /// assert!(iter.next().is_none()); + /// # Ok::<(), Error>(()) + /// ``` + pub fn push<'a>(&mut self, value: impl Into>) { self.inner.append(self.len.to_string(), value); self.len += 1; } - pub fn as_bytes(&self) -> &[u8] { - self.inner.as_bytes() + /// Returns the number of elements in the [`RawArrayBuf`]. + /// + /// To retrieve the number of BSON bytes in the backing buffer, use + /// `.as_bytes().len()`. + pub fn len(&self) -> usize { + self.len } } @@ -74,7 +140,7 @@ impl<'a> IntoIterator for &'a RawArrayBuf { type Item = super::Result>; fn into_iter(self) -> RawArrayIter<'a> { - self.deref().into_iter() + self.as_ref().into_iter() } } @@ -94,7 +160,7 @@ impl<'a, T: Into>> FromIterator for RawArrayBuf { fn from_iter>(iter: I) -> Self { let mut array_buf = RawArrayBuf::new(); for item in iter { - array_buf.append(item); + array_buf.push(item); } array_buf } From 3f46173aebd6f003fa732429393fc9e262ea7584 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Wed, 17 Nov 2021 15:03:30 -0500 Subject: [PATCH 07/21] Revert "rename bson.rs -> bson_ref.rs" This reverts commit 0f96cb0c67b21a5708c32d39a380d15aff0f6795. --- src/raw/{bson_ref.rs => bson.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/raw/{bson_ref.rs => bson.rs} (100%) diff --git a/src/raw/bson_ref.rs b/src/raw/bson.rs similarity index 100% rename from src/raw/bson_ref.rs rename to src/raw/bson.rs From 706c1670e1cf0785a0e65ab6dacda1ff2d8e3f41 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Wed, 17 Nov 2021 19:18:45 -0500 Subject: [PATCH 08/21] wip owned bson --- src/de/raw.rs | 18 +- src/lib.rs | 9 +- src/raw/array.rs | 18 +- src/raw/array_buf.rs | 10 +- src/raw/bson.rs | 361 +++++------------------------ src/raw/document.rs | 15 +- src/raw/document_buf.rs | 178 ++++++++++----- src/raw/mod.rs | 5 +- src/raw/owned_bson.rs | 486 ++++++++++++++++++++++++++++++++++++++++ src/raw/serde.rs | 374 +++++++++++++++++++++++++++++++ src/raw/test/append.rs | 16 +- src/raw/test/mod.rs | 6 +- 12 files changed, 1089 insertions(+), 407 deletions(-) create mode 100644 src/raw/owned_bson.rs create mode 100644 src/raw/serde.rs diff --git a/src/de/raw.rs b/src/de/raw.rs index 05817831..83f654ef 100644 --- a/src/de/raw.rs +++ b/src/de/raw.rs @@ -648,13 +648,20 @@ impl<'d, 'de> serde::de::Deserializer<'de> for DocumentKeyDeserializer<'d, 'de> } } + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de> + { + visitor.visit_newtype_struct(self) + } + fn is_human_readable(&self) -> bool { false } forward_to_deserialize_any! { bool char str bytes byte_buf option unit unit_struct string - identifier newtype_struct seq tuple tuple_struct struct map enum + identifier seq tuple tuple_struct struct map enum ignored_any i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 } } @@ -674,13 +681,20 @@ impl<'de> serde::de::Deserializer<'de> for FieldDeserializer { visitor.visit_borrowed_str(self.field_name) } + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de> + { + visitor.visit_newtype_struct(self) + } + fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq - bytes byte_buf map struct option unit newtype_struct + bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } diff --git a/src/lib.rs b/src/lib.rs index 7d9d23d6..16693ddf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,13 +272,14 @@ pub use self::{ bson::{Array, Binary, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp}, datetime::DateTime, de::{ - from_bson, from_bson_with_options, from_document, from_document_with_options, from_reader, from_reader_utf8_lossy, - from_slice, from_slice_utf8_lossy, Deserializer, DeserializerOptions, + from_bson, from_bson_with_options, from_document, from_document_with_options, from_reader, + from_reader_utf8_lossy, from_slice, from_slice_utf8_lossy, Deserializer, + DeserializerOptions, }, decimal128::Decimal128, raw::{ - RawArray, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, - RawRegex, + OwnedRawBson, RawArray, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, + RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, }, ser::{ to_bson, to_bson_with_options, to_document, to_document_with_options, to_vec, Serializer, diff --git a/src/raw/array.rs b/src/raw/array.rs index e6a333d0..9d57f09b 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::{borrow::Cow, convert::TryFrom}; use serde::{ser::SerializeSeq, Deserialize, Serialize}; @@ -12,7 +12,7 @@ use super::{ RawRegex, Result, }; -use crate::{Bson, DateTime, RawArrayBuf, Timestamp, oid::ObjectId, raw::{RawBsonVisitor, RAW_ARRAY_NEWTYPE}, spec::{BinarySubtype, ElementType}}; +use crate::{Bson, DateTime, RawArrayBuf, Timestamp, oid::ObjectId, raw::{RAW_ARRAY_NEWTYPE, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}, spec::{BinarySubtype, ElementType}}; /// A slice of a BSON document containing a BSON array value (akin to [`std::str`]). This can be /// retrieved from a [`RawDocument`] via [`RawDocument::get`]. @@ -87,7 +87,7 @@ impl RawArray { /// /// This involves a traversal of the array to count the values. pub fn to_raw_array_buf(&self) -> RawArrayBuf { - RawArrayBuf::from + RawArrayBuf::from_raw_document_buf(self.doc.to_raw_document_buf()) } /// Gets a reference to the value at the given index. @@ -226,12 +226,12 @@ impl ToOwned for RawArray { type Owned = RawArrayBuf; fn to_owned(&self) -> Self::Owned { - self.into_iter().collect() + self.to_raw_array_buf() } } -impl<'a> From<&'a RawDocument> for Cow<'a, RawDocument> { - fn from(rdr: &'a RawDocument) -> Self { +impl<'a> From<&'a RawArray> for Cow<'a, RawArray> { + fn from(rdr: &'a RawArray) -> Self { Cow::Borrowed(rdr) } } @@ -269,9 +269,9 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray { where D: serde::Deserializer<'de>, { - match deserializer.deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, RawBsonVisitor)? { - RawBson::Array(d) => Ok(d), - RawBson::Binary(b) if b.subtype == BinarySubtype::Generic => { + match deserializer.deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(d), + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; Ok(RawArray::from_doc(doc)) } diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index cafeb83b..c8cea8f8 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -4,9 +4,9 @@ use std::{ iter::FromIterator, }; -use crate::{raw::Result, RawArray, RawBson, RawDocumentBuf}; +use crate::{RawArray, RawBson, RawDocumentBuf}; -use super::RawArrayIter; +use super::{RawArrayIter, owned_bson::OwnedRawBson}; /// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes. /// This type can be used to construct owned array values, which can be used to append to [`RawDocumentBuf`] @@ -49,7 +49,7 @@ impl RawArrayBuf { /// Construct a new, empty `RawArrayBuf`. pub fn new() -> RawArrayBuf { Self { - inner: RawDocumentBuf::empty(), + inner: RawDocumentBuf::new(), len: 0, } } @@ -92,7 +92,7 @@ impl RawArrayBuf { /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` - pub fn push<'a>(&mut self, value: impl Into>) { + pub fn push(&mut self, value: impl Into) { self.inner.append(self.len.to_string(), value); self.len += 1; } @@ -156,7 +156,7 @@ impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> { } } -impl<'a, T: Into>> FromIterator for RawArrayBuf { +impl> FromIterator for RawArrayBuf { fn from_iter>(iter: I) -> Self { let mut array_buf = RawArrayBuf::new(); for item in iter { diff --git a/src/raw/bson.rs b/src/raw/bson.rs index be5cb89e..4e0945a5 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -6,22 +6,21 @@ use std::{ use serde::{de::Visitor, ser::SerializeStruct, Deserialize, Serialize}; use serde_bytes::{ByteBuf, Bytes}; -use super::{Error, RawArray, RawDocument, Result}; +use super::{ + owned_bson::OwnedRawBson, + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + Error, RawArray, RawDocument, Result, +}; use crate::{ de::convert_unsigned_to_signed_raw, extjson, oid::{self, ObjectId}, - raw::{RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, + raw::{ + OwnedRawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE, + }, spec::{BinarySubtype, ElementType}, - Binary, - Bson, - DateTime, - DbPointer, - Decimal128, - JavaScriptCodeWithScope, - RawArrayBuf, - RawDocumentBuf, - Timestamp, + Binary, Bson, DateTime, DbPointer, Decimal128, JavaScriptCodeWithScope, RawArrayBuf, + RawDocumentBuf, Regex, Timestamp, }; /// A BSON value referencing raw bytes stored elsewhere. @@ -251,245 +250,44 @@ impl<'a> RawBson<'a> { _ => None, } } -} - -/// A visitor used to deserialize types backed by raw BSON. -pub(crate) struct RawBsonVisitor; - -impl<'de> Visitor<'de> for RawBsonVisitor { - type Value = RawBson<'de>; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "a raw BSON reference") - } - - fn visit_borrowed_str(self, v: &'de str) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::String(v)) - } - - fn visit_borrowed_bytes(self, bytes: &'de [u8]) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Binary(RawBinary { - bytes, - subtype: BinarySubtype::Generic, - })) - } - - fn visit_i8(self, v: i8) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Int32(v.into())) - } - - fn visit_i16(self, v: i16) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Int32(v.into())) - } - - fn visit_i32(self, v: i32) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Int32(v)) - } - - fn visit_i64(self, v: i64) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Int64(v)) - } - - fn visit_u8(self, value: u8) -> std::result::Result - where - E: serde::de::Error, - { - convert_unsigned_to_signed_raw(value.into()) - } - - fn visit_u16(self, value: u16) -> std::result::Result - where - E: serde::de::Error, - { - convert_unsigned_to_signed_raw(value.into()) - } - - fn visit_u32(self, value: u32) -> std::result::Result - where - E: serde::de::Error, - { - convert_unsigned_to_signed_raw(value.into()) - } - - fn visit_u64(self, value: u64) -> std::result::Result - where - E: serde::de::Error, - { - convert_unsigned_to_signed_raw(value) - } - - fn visit_bool(self, v: bool) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Boolean(v)) - } - - fn visit_f64(self, v: f64) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Double(v)) - } - - fn visit_none(self) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Null) - } - - fn visit_unit(self) -> std::result::Result - where - E: serde::de::Error, - { - Ok(RawBson::Null) - } - - fn visit_newtype_struct(self, deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_any(self) - } - - fn visit_map(self, mut map: A) -> std::result::Result - where - A: serde::de::MapAccess<'de>, - { - let k = map - .next_key::<&str>()? - .ok_or_else(|| serde::de::Error::custom("expected a key when deserializing RawBson"))?; - match k { - "$oid" => { - let oid: ObjectId = map.next_value()?; - Ok(RawBson::ObjectId(oid)) - } - "$symbol" => { - let s: &str = map.next_value()?; - Ok(RawBson::Symbol(s)) - } - "$numberDecimalBytes" => { - let bytes = map.next_value::()?; - return Ok(RawBson::Decimal128(Decimal128::deserialize_from_slice( - &bytes, - )?)); - } - "$regularExpression" => { - #[derive(Debug, Deserialize)] - struct BorrowedRegexBody<'a> { - pattern: &'a str, - - options: &'a str, - } - let body: BorrowedRegexBody = map.next_value()?; - Ok(RawBson::RegularExpression(RawRegex { - pattern: body.pattern, - options: body.options, - })) - } - "$undefined" => { - let _: bool = map.next_value()?; - Ok(RawBson::Undefined) - } - "$binary" => { - #[derive(Debug, Deserialize)] - struct BorrowedBinaryBody<'a> { - bytes: &'a [u8], - - #[serde(rename = "subType")] - subtype: u8, - } - - let v = map.next_value::()?; - Ok(RawBson::Binary(RawBinary { - bytes: v.bytes, - subtype: v.subtype.into(), - })) - } - "$date" => { - let v = map.next_value::()?; - Ok(RawBson::DateTime(DateTime::from_millis(v))) - } - "$timestamp" => { - let v = map.next_value::()?; - Ok(RawBson::Timestamp(Timestamp { - time: v.t, - increment: v.i, - })) - } - "$minKey" => { - let _ = map.next_value::()?; - Ok(RawBson::MinKey) - } - "$maxKey" => { - let _ = map.next_value::()?; - Ok(RawBson::MaxKey) - } - "$code" => { - let code = map.next_value::<&str>()?; - if let Some(key) = map.next_key::<&str>()? { - if key == "$scope" { - let scope = map.next_value::<&RawDocument>()?; - Ok(RawBson::JavaScriptCodeWithScope( - RawJavaScriptCodeWithScope { code, scope }, - )) - } else { - Err(serde::de::Error::unknown_field(key, &["$scope"])) - } - } else { - Ok(RawBson::JavaScriptCode(code)) - } - } - "$dbPointer" => { - #[derive(Deserialize)] - struct BorrowedDbPointerBody<'a> { - #[serde(rename = "$ref")] - ns: &'a str, - - #[serde(rename = "$id")] - id: ObjectId, - } - - let body: BorrowedDbPointerBody = map.next_value()?; - Ok(RawBson::DbPointer(RawDbPointer { - namespace: body.ns, - id: body.id, - })) - } - RAW_DOCUMENT_NEWTYPE => { - let bson = map.next_value::<&[u8]>()?; - let doc = RawDocument::new(bson).map_err(serde::de::Error::custom)?; - Ok(RawBson::Document(doc)) + /// Convert this [`RawBson`] to the equivalent [`OwnedRawBson`]. + pub fn to_owned_raw_bson(self) -> OwnedRawBson { + match self { + RawBson::Double(d) => OwnedRawBson::Double(d), + RawBson::String(s) => OwnedRawBson::String(s.to_string()), + RawBson::Array(a) => OwnedRawBson::Array(a.to_owned()), + RawBson::Document(d) => OwnedRawBson::Document(d.to_owned()), + RawBson::Boolean(b) => OwnedRawBson::Boolean(b), + RawBson::Null => OwnedRawBson::Null, + RawBson::RegularExpression(re) => { + OwnedRawBson::RegularExpression(Regex::new(re.pattern, re.options)) } - RAW_ARRAY_NEWTYPE => { - let bson = map.next_value::<&[u8]>()?; - let doc = RawDocument::new(bson).map_err(serde::de::Error::custom)?; - Ok(RawBson::Array(RawArray::from_doc(doc))) + RawBson::JavaScriptCode(c) => OwnedRawBson::JavaScriptCode(c.to_owned()), + RawBson::JavaScriptCodeWithScope(c_w_s) => { + OwnedRawBson::JavaScriptCodeWithScope(OwnedRawJavaScriptCodeWithScope { + code: c_w_s.code.to_string(), + scope: c_w_s.scope.to_owned(), + }) } - k => Err(serde::de::Error::custom(format!( - "can't deserialize RawBson from map, key={}", - k - ))), + RawBson::Int32(i) => OwnedRawBson::Int32(i), + RawBson::Int64(i) => OwnedRawBson::Int64(i), + RawBson::Timestamp(t) => OwnedRawBson::Timestamp(t), + RawBson::Binary(b) => OwnedRawBson::Binary(Binary { + bytes: b.bytes.to_vec(), + subtype: b.subtype + }), + RawBson::ObjectId(o) => OwnedRawBson::ObjectId(o), + RawBson::DateTime(dt) => OwnedRawBson::DateTime(dt), + RawBson::Symbol(s) => OwnedRawBson::Symbol(s.to_string()), + RawBson::Decimal128(d) => OwnedRawBson::Decimal128(d), + RawBson::Undefined => OwnedRawBson::Undefined, + RawBson::MaxKey => OwnedRawBson::MaxKey, + RawBson::MinKey => OwnedRawBson::MinKey, + RawBson::DbPointer(d) => OwnedRawBson::DbPointer(DbPointer { + namespace: d.namespace.to_string(), + id: d.id + }), } } } @@ -499,7 +297,14 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawBson<'a> { where D: serde::Deserializer<'de>, { - deserializer.deserialize_newtype_struct(RAW_BSON_NEWTYPE, RawBsonVisitor) + match deserializer + .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b), + _ => Err(serde::de::Error::custom( + "RawBson must be deserialized from borrowed content", + )), + } } } @@ -558,59 +363,7 @@ impl<'a> TryFrom> for Bson { type Error = Error; fn try_from(rawbson: RawBson<'a>) -> Result { - Ok(match rawbson { - RawBson::Double(d) => Bson::Double(d), - RawBson::String(s) => Bson::String(s.to_string()), - RawBson::Document(rawdoc) => { - let doc = rawdoc.try_into()?; - Bson::Document(doc) - } - RawBson::Array(rawarray) => { - let mut items = Vec::new(); - for v in rawarray { - let bson: Bson = v?.try_into()?; - items.push(bson); - } - Bson::Array(items) - } - RawBson::Binary(rawbson) => { - let RawBinary { - subtype, - bytes: data, - } = rawbson; - Bson::Binary(crate::Binary { - subtype, - bytes: data.to_vec(), - }) - } - RawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), - RawBson::Boolean(rawbson) => Bson::Boolean(rawbson), - RawBson::DateTime(rawbson) => Bson::DateTime(rawbson), - RawBson::Null => Bson::Null, - RawBson::RegularExpression(rawregex) => Bson::RegularExpression(crate::Regex::new( - rawregex.pattern.to_string(), - rawregex.options.to_string(), - )), - RawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson.to_string()), - RawBson::Int32(rawbson) => Bson::Int32(rawbson), - RawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), - RawBson::Int64(rawbson) => Bson::Int64(rawbson), - RawBson::Undefined => Bson::Undefined, - RawBson::DbPointer(rawbson) => Bson::DbPointer(DbPointer { - namespace: rawbson.namespace.to_string(), - id: rawbson.id, - }), - RawBson::Symbol(rawbson) => Bson::Symbol(rawbson.to_string()), - RawBson::JavaScriptCodeWithScope(rawbson) => { - Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope { - code: rawbson.code.to_string(), - scope: rawbson.scope.try_into()?, - }) - } - RawBson::Decimal128(rawbson) => Bson::Decimal128(rawbson), - RawBson::MaxKey => Bson::MaxKey, - RawBson::MinKey => Bson::MinKey, - }) + rawbson.to_owned_raw_bson().try_into() } } @@ -692,12 +445,6 @@ impl<'a> From for RawBson<'a> { } } -impl<'a, 'b> From<&'a RawBson<'b>> for RawBson<'b> { - fn from(b: &'a RawBson<'b>) -> Self { - *b - } -} - /// A BSON binary value referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawBinary<'a> { diff --git a/src/raw/document.rs b/src/raw/document.rs index 5bbcee80..004a5437 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -5,12 +5,7 @@ use std::{ use serde::{ser::SerializeMap, Deserialize, Serialize}; -use crate::{ - raw::{error::ErrorKind, RawBsonVisitor, RAW_DOCUMENT_NEWTYPE}, - spec::BinarySubtype, - DateTime, - Timestamp, -}; +use crate::{DateTime, Timestamp, raw::{RAW_DOCUMENT_NEWTYPE, error::ErrorKind, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}, spec::BinarySubtype}; use super::{ error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, @@ -149,7 +144,7 @@ impl RawDocument { /// # Ok::<(), Error>(()) pub fn to_raw_document_buf(&self) -> RawDocumentBuf { // unwrap is ok here because we already verified the bytes in `RawDocumentRef::new` - RawDocumentBuf::new(self.data.to_owned()).unwrap() + RawDocumentBuf::from_bytes(self.data.to_owned()).unwrap() } /// Gets a reference to the value corresponding to the given key by iterating until the key is @@ -499,13 +494,13 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { where D: serde::Deserializer<'de>, { - match deserializer.deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, RawBsonVisitor)? { - RawBson::Document(d) => Ok(d), + match deserializer.deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(d), // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializier will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - RawBson::Binary(b) if b.subtype == BinarySubtype::Generic => { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { RawDocument::new(b.bytes).map_err(serde::de::Error::custom) } diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 432ec7f3..a08919fd 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -1,14 +1,16 @@ -use std::{borrow::{Borrow, Cow}, convert::{TryFrom, TryInto}, ffi::CString, iter::FromIterator, ops::Deref}; +use std::{ + borrow::{Borrow, Cow}, + convert::{TryFrom, TryInto}, + ffi::CString, + iter::FromIterator, + ops::Deref, +}; use serde::{Deserialize, Serialize}; -use crate::{ - de::MIN_BSON_DOCUMENT_SIZE, - spec::{BinarySubtype, ElementType}, - Document, -}; +use crate::{Document, RawBinary, RawJavaScriptCodeWithScope, de::MIN_BSON_DOCUMENT_SIZE, raw::{RAW_DOCUMENT_NEWTYPE, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}, spec::{BinarySubtype, ElementType}}; -use super::{Error, ErrorKind, Iter, RawBson, RawDocument, Result}; +use super::{owned_bson::OwnedRawBson, Error, ErrorKind, Iter, RawBson, RawDocument, Result}; /// An owned BSON document (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes. /// This can be created from a `Vec` or a [`crate::Document`]. @@ -52,7 +54,8 @@ pub struct RawDocumentBuf { } impl RawDocumentBuf { - pub fn empty() -> RawDocumentBuf { + /// Creates a new, empty [`RawDocumentBuf`]. + pub fn new() -> RawDocumentBuf { let mut data: Vec = MIN_BSON_DOCUMENT_SIZE.to_le_bytes().to_vec(); data.push(0); Self { data } @@ -72,10 +75,10 @@ impl RawDocumentBuf { /// /// ``` /// # use bson::raw::{RawDocumentBuf, Error}; - /// let doc = RawDocumentBuf::new(b"\x05\0\0\0\0".to_vec())?; + /// let doc = RawDocumentBuf::from_bytes(b"\x05\0\0\0\0".to_vec())?; /// # Ok::<(), Error>(()) /// ``` - pub fn new(data: Vec) -> Result { + pub fn from_bytes(data: Vec) -> Result { let _ = RawDocument::new(data.as_slice())?; Ok(Self { data }) } @@ -146,23 +149,48 @@ impl RawDocumentBuf { self.data } - pub fn append_document_buf(&mut self, key: impl AsRef, value: RawDocumentBuf) { - self.append(key, RawBson::Document(&value)) - } - - pub fn append<'a>(&mut self, key: impl AsRef, value: impl Into>) { - fn append_str(doc: &mut RawDocumentBuf, value: &str) { + /// Append a key value pair to the end of the document without checking to see if + /// the key already exists. + /// + /// It is a user error to append the same key more than once to the same document, and it may result + /// in errors when communicating with MongoDB. + /// + /// If the provided key contains an interior null byte, this method will panic. + /// + /// ``` + /// # use bson::raw::Error; + /// use bson::raw::RawDocumentBuf; + /// + /// let mut doc = RawDocumentBuf::new(); + /// doc.append("a string", "some string"); + /// doc.append("an integer", 12_i32); + /// + /// let mut subdoc = RawDocumentBuf::new(); + /// subdoc.append("a key", true); + /// doc.push("a document", subdoc); + /// + /// let expected = doc! { + /// "a string": "some string", + /// "an integer": 12_i32, + /// "a document": { "a key": true }, + /// }; + /// + /// assert_eq!(doc.to_document()?, expected); + /// # Ok::<(), Error>(()) + /// ``` + pub fn append(&mut self, key: impl Into, value: impl Into) { + fn append_string(doc: &mut RawDocumentBuf, value: String) { doc.data .extend(((value.as_bytes().len() + 1) as i32).to_le_bytes()); - doc.data.extend(value.as_bytes()); + doc.data.extend(value.into_bytes()); doc.data.push(0); } - fn append_cstr(doc: &mut RawDocumentBuf, value: &str) { + fn append_cstring(doc: &mut RawDocumentBuf, value: String) { if value.contains('\0') { panic!("cstr includes interior null byte: {}", value) } - doc.data.extend(value.as_bytes()); + doc.data.extend(value.into_bytes()); doc.data.push(0); } @@ -170,77 +198,89 @@ impl RawDocumentBuf { // write the key for the next value to the end // the element type will replace the previous null byte terminator of the document - append_cstr(self, key.as_ref()); + append_cstring(self, key.into()); let value = value.into(); + let element_type = value.element_type(); match value { - RawBson::Int32(i) => { + OwnedRawBson::Int32(i) => { self.data.extend(i.to_le_bytes()); } - RawBson::String(s) => { - append_str(self, s); + OwnedRawBson::String(s) => { + append_string(self, s); } - RawBson::Document(d) => { - self.data.extend(d.as_bytes()); + OwnedRawBson::Document(d) => { + self.data.extend(d.into_vec()); } - RawBson::Array(a) => { + OwnedRawBson::Array(a) => { self.data.extend(a.as_bytes()); } - RawBson::Binary(b) => { - self.data.extend(b.len().to_le_bytes()); + OwnedRawBson::Binary(b) => { + let len = RawBinary { + bytes: b.bytes.as_slice(), + subtype: b.subtype, + } + .len(); + self.data.extend(len.to_le_bytes()); self.data.push(b.subtype.into()); if let BinarySubtype::BinaryOld = b.subtype { - self.data.extend((b.len() - 4).to_le_bytes()) + self.data.extend((len - 4).to_le_bytes()) } self.data.extend(b.bytes); } - RawBson::Boolean(b) => { + OwnedRawBson::Boolean(b) => { let byte = if b { 1 } else { 0 }; self.data.push(byte); } - RawBson::DateTime(dt) => { + OwnedRawBson::DateTime(dt) => { self.data.extend(dt.timestamp_millis().to_le_bytes()); } - RawBson::DbPointer(dbp) => { - append_str(self, dbp.namespace); + OwnedRawBson::DbPointer(dbp) => { + append_string(self, dbp.namespace); self.data.extend(dbp.id.bytes()); } - RawBson::Decimal128(d) => { + OwnedRawBson::Decimal128(d) => { self.data.extend(d.bytes()); } - RawBson::Double(d) => { + OwnedRawBson::Double(d) => { self.data.extend(d.to_le_bytes()); } - RawBson::Int64(i) => { + OwnedRawBson::Int64(i) => { self.data.extend(i.to_le_bytes()); } - RawBson::RegularExpression(re) => { - append_cstr(self, re.pattern); - append_cstr(self, re.options); + OwnedRawBson::RegularExpression(re) => { + append_cstring(self, re.pattern); + append_cstring(self, re.options); } - RawBson::JavaScriptCode(js) => { - append_str(self, js); + OwnedRawBson::JavaScriptCode(js) => { + append_string(self, js); } - RawBson::JavaScriptCodeWithScope(code_w_scope) => { - let len = code_w_scope.len(); + OwnedRawBson::JavaScriptCodeWithScope(code_w_scope) => { + let len = RawJavaScriptCodeWithScope { + code: code_w_scope.code.as_str(), + scope: &code_w_scope.scope, + }.len(); self.data.extend(len.to_le_bytes()); - append_str(self, code_w_scope.code); - self.data.extend(code_w_scope.scope.as_bytes()); + append_string(self, code_w_scope.code); + self.data.extend(code_w_scope.scope.into_vec()); } - RawBson::Timestamp(ts) => { + OwnedRawBson::Timestamp(ts) => { self.data.extend(ts.to_le_i64().to_le_bytes()); } - RawBson::ObjectId(oid) => { + OwnedRawBson::ObjectId(oid) => { self.data.extend(oid.bytes()); } - RawBson::Symbol(s) => { - append_str(self, s); + OwnedRawBson::Symbol(s) => { + append_string(self, s); } - RawBson::Null | RawBson::Undefined | RawBson::MinKey | RawBson::MaxKey => {} + OwnedRawBson::Null + | OwnedRawBson::Undefined + | OwnedRawBson::MinKey + | OwnedRawBson::MaxKey => {} } // update element type - self.data[original_len - 1] = value.element_type() as u8; + self.data[original_len - 1] = element_type as u8; // append trailing null byte self.data.push(0); // update length @@ -248,19 +288,43 @@ impl RawDocumentBuf { .splice(0..4, (self.data.len() as i32).to_le_bytes()); } + /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error + /// if invalid BSON is encountered. pub fn to_document(&self) -> Result { self.as_ref().try_into() } } +impl Default for RawDocumentBuf { + fn default() -> Self { + Self::new() + } +} + impl<'de> Deserialize<'de> for RawDocumentBuf { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { - // TODO: RUST-1045 implement visit_map to deserialize from arbitrary maps. - let doc: &'de RawDocument = Deserialize::deserialize(deserializer)?; - Ok(doc.to_owned()) + match deserializer.deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(d.to_owned()), + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(d)) => Ok(d), + + // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize + // from them here too. For BSON, the deserializier will return an error if it + // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { + RawDocumentBuf::from_bytes(b.bytes.to_vec()).map_err(serde::de::Error::custom) + } + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { + RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom) + } + + o => Err(serde::de::Error::custom(format!( + "expected raw document, instead got {:?}", + o + ))), + } } } @@ -331,9 +395,9 @@ impl Borrow for RawDocumentBuf { } } -impl<'a, T: Into>> FromIterator<(&'a str, T)> for RawDocumentBuf { - fn from_iter>(iter: I) -> Self { - let mut buf = RawDocumentBuf::empty(); +impl, T: Into> FromIterator<(S, T)> for RawDocumentBuf { + fn from_iter>(iter: I) -> Self { + let mut buf = RawDocumentBuf::new(); for (k, v) in iter { buf.append(k, v); } diff --git a/src/raw/mod.rs b/src/raw/mod.rs index a0aeb47a..061fd656 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -121,6 +121,8 @@ mod error; mod iter; #[cfg(test)] mod test; +mod owned_bson; +mod serde; use std::convert::{TryFrom, TryInto}; @@ -134,10 +136,9 @@ pub use self::{ document_buf::RawDocumentBuf, error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, iter::Iter, + owned_bson::{OwnedRawJavaScriptCodeWithScope, OwnedRawBson}, }; -pub(crate) use self::bson::RawBsonVisitor; - /// Special newtype name indicating that the type being (de)serialized is a raw BSON document. pub(crate) const RAW_DOCUMENT_NEWTYPE: &str = "$__private__bson_RawDocument"; diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs new file mode 100644 index 00000000..da6d83fb --- /dev/null +++ b/src/raw/owned_bson.rs @@ -0,0 +1,486 @@ +use std::convert::{TryFrom, TryInto}; + +use serde::{Deserialize, Serialize}; + +use crate::{Binary, Bson, DbPointer, Decimal128, JavaScriptCodeWithScope, RawArray, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, Regex, Timestamp, oid::{self, ObjectId}, raw::RAW_BSON_NEWTYPE, spec::ElementType}; + +use super::{Result, Error, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}; + +/// A BSON value backed by owned raw BSON bytes. +#[derive(Debug, Clone, PartialEq)] +pub enum OwnedRawBson { + /// 64-bit binary floating point + Double(f64), + /// UTF-8 string + String(String), + /// Array + Array(RawArrayBuf), + /// Embedded document + Document(RawDocumentBuf), + /// Boolean value + Boolean(bool), + /// Null value + Null, + /// Regular expression + RegularExpression(Regex), + /// JavaScript code + JavaScriptCode(String), + /// JavaScript code w/ scope + JavaScriptCodeWithScope(OwnedRawJavaScriptCodeWithScope), + /// 32-bit signed integer + Int32(i32), + /// 64-bit signed integer + Int64(i64), + /// Timestamp + Timestamp(Timestamp), + /// Binary data + Binary(Binary), + /// [ObjectId](http://dochub.mongodb.org/core/objectids) + ObjectId(oid::ObjectId), + /// UTC datetime + DateTime(crate::DateTime), + /// Symbol (Deprecated) + Symbol(String), + /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) + Decimal128(Decimal128), + /// Undefined value (Deprecated) + Undefined, + /// Max key + MaxKey, + /// Min key + MinKey, + /// DBPointer (Deprecated) + DbPointer(DbPointer), +} + +impl OwnedRawBson { + /// Get the [`ElementType`] of this value. + pub fn element_type(&self) -> ElementType { + match *self { + OwnedRawBson::Double(..) => ElementType::Double, + OwnedRawBson::String(..) => ElementType::String, + OwnedRawBson::Array(..) => ElementType::Array, + OwnedRawBson::Document(..) => ElementType::EmbeddedDocument, + OwnedRawBson::Boolean(..) => ElementType::Boolean, + OwnedRawBson::Null => ElementType::Null, + OwnedRawBson::RegularExpression(..) => ElementType::RegularExpression, + OwnedRawBson::JavaScriptCode(..) => ElementType::JavaScriptCode, + OwnedRawBson::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope, + OwnedRawBson::Int32(..) => ElementType::Int32, + OwnedRawBson::Int64(..) => ElementType::Int64, + OwnedRawBson::Timestamp(..) => ElementType::Timestamp, + OwnedRawBson::Binary(..) => ElementType::Binary, + OwnedRawBson::ObjectId(..) => ElementType::ObjectId, + OwnedRawBson::DateTime(..) => ElementType::DateTime, + OwnedRawBson::Symbol(..) => ElementType::Symbol, + OwnedRawBson::Decimal128(..) => ElementType::Decimal128, + OwnedRawBson::Undefined => ElementType::Undefined, + OwnedRawBson::MaxKey => ElementType::MaxKey, + OwnedRawBson::MinKey => ElementType::MinKey, + OwnedRawBson::DbPointer(..) => ElementType::DbPointer, + } + } + + /// Gets the wrapped `f64` value or returns `None` if the value isn't a BSON + /// double. + pub fn as_f64(&self) -> Option { + match self { + OwnedRawBson::Double(d) => Some(*d), + _ => None, + } + } + + /// Gets a reference to the `String` that's wrapped or returns `None` if the wrapped value isn't a BSON + /// String. + pub fn as_str(&self) -> Option<&'_ str> { + match self { + OwnedRawBson::String(s) => Some(s), + _ => None, + } + } + + /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the wrapped value isn't a BSON + /// array. + pub fn as_array(&self) -> Option<&'_ RawArray> { + match self { + OwnedRawBson::Array(v) => Some(v), + _ => None, + } + } + + /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped value isn't a BSON + /// document. + pub fn as_document(&self) -> Option<&'_ RawDocument> { + match self { + OwnedRawBson::Document(v) => Some(v), + _ => None, + } + } + + /// Gets the wrapped `bool` value or returns `None` if the wrapped value isn't a BSON + /// boolean. + pub fn as_bool(&self) -> Option { + match self { + OwnedRawBson::Boolean(v) => Some(*v), + _ => None, + } + } + + /// Gets the wrapped `i32` value or returns `None` if the wrapped value isn't a BSON + /// Int32. + pub fn as_i32(&self) -> Option { + match self { + OwnedRawBson::Int32(v) => Some(*v), + _ => None, + } + } + + /// Gets the wrapped `i64` value or returns `None` if the wrapped value isn't a BSON + /// Int64. + pub fn as_i64(&self) -> Option { + match self { + OwnedRawBson::Int64(v) => Some(*v), + _ => None, + } + } + + /// Gets the wrapped [`crate::oid::ObjectId`] value or returns `None` if the wrapped value isn't a BSON + /// ObjectID. + pub fn as_object_id(&self) -> Option { + match self { + OwnedRawBson::ObjectId(v) => Some(*v), + _ => None, + } + } + + /// Gets a reference to the [`Binary`] that's wrapped or returns `None` if the wrapped value isn't a BSON + /// binary. + pub fn as_binary(&self) -> Option> { + match self { + OwnedRawBson::Binary(v) => Some(RawBinary { + bytes: v.bytes.as_slice(), + subtype: v.subtype, + }), + _ => None, + } + } + + /// Gets a reference to the [`Regex`] that's wrapped or returns `None` if the wrapped value isn't a BSON + /// regular expression. + pub fn as_regex(&self) -> Option> { + match self { + OwnedRawBson::RegularExpression(v) => Some(RawRegex { + pattern: v.pattern.as_str(), + options: v.options.as_str(), + }), + _ => None, + } + } + + /// Gets the wrapped [`crate::DateTime`] value or returns `None` if the wrapped value isn't a BSON + /// datetime. + pub fn as_datetime(&self) -> Option { + match self { + OwnedRawBson::DateTime(v) => Some(*v), + _ => None, + } + } + + /// Gets a reference to the symbol that's wrapped or returns `None` if the wrapped value isn't a BSON + /// Symbol. + pub fn as_symbol(&self) -> Option<&'_ str> { + match self { + OwnedRawBson::Symbol(v) => Some(v), + _ => None, + } + } + + /// Gets the wrapped [`crate::Timestamp`] value or returns `None` if the wrapped value isn't a BSON + /// datetime. + pub fn as_timestamp(&self) -> Option { + match self { + OwnedRawBson::Timestamp(timestamp) => Some(*timestamp), + _ => None, + } + } + + /// Returns `Some(())` if this value is null, otherwise returns `None`. + pub fn as_null(&self) -> Option<()> { + match self { + OwnedRawBson::Null => Some(()), + _ => None, + } + } + + /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns `None` if the wrapped value isn't a BSON + /// DbPointer. + pub fn as_db_pointer(&self) -> Option> { + match self { + OwnedRawBson::DbPointer(d) => Some(RawDbPointer { + namespace: d.namespace.as_str(), + id: d.id, + }), + _ => None, + } + } + + /// Gets a reference to the code that's wrapped or returns `None` if the wrapped value isn't a BSON + /// JavaScript code. + pub fn as_javascript(&self) -> Option<&'_ str> { + match self { + OwnedRawBson::JavaScriptCode(s) => Some(s), + _ => None, + } + } + + /// Gets a reference to the [`OwnedRawJavaScriptCodeWithScope`] that's wrapped or returns `None` if + /// the wrapped value isn't a BSON JavaScript code with scope value. + pub fn as_javascript_with_scope(&self) -> Option> { + match self { + OwnedRawBson::JavaScriptCodeWithScope(s) => Some(RawJavaScriptCodeWithScope { + code: s.code.as_str(), + scope: &s.scope, + }), + _ => None, + } + } + + /// Gets a [`RawBson`] value referencing this owned raw BSON value. + pub fn as_raw_bson(&self) -> RawBson<'_> { + match self { + OwnedRawBson::Double(d) => RawBson::Double(*d), + OwnedRawBson::String(s) => RawBson::String(s.as_str()), + OwnedRawBson::Array(a) => RawBson::Array(&a), + OwnedRawBson::Document(d) => RawBson::Document(&d), + OwnedRawBson::Boolean(b) => RawBson::Boolean(*b), + OwnedRawBson::Null => RawBson::Null, + OwnedRawBson::RegularExpression(re) => RawBson::RegularExpression(RawRegex { + options: re.options.as_str(), + pattern: re.pattern.as_str(), + }), + OwnedRawBson::JavaScriptCode(c) => RawBson::JavaScriptCode(c.as_str()), + OwnedRawBson::JavaScriptCodeWithScope(code_w_scope) => { + RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { + code: code_w_scope.code.as_str(), + scope: code_w_scope.scope.as_ref(), + }) + } + OwnedRawBson::Int32(i) => RawBson::Int32(*i), + OwnedRawBson::Int64(i) => RawBson::Int64(*i), + OwnedRawBson::Timestamp(ts) => RawBson::Timestamp(*ts), + OwnedRawBson::Binary(b) => RawBson::Binary(RawBinary { + bytes: b.bytes.as_slice(), + subtype: b.subtype, + }), + OwnedRawBson::ObjectId(oid) => RawBson::ObjectId(*oid), + OwnedRawBson::DateTime(dt) => RawBson::DateTime(*dt), + OwnedRawBson::Symbol(s) => RawBson::Symbol(s.as_str()), + OwnedRawBson::Decimal128(d) => RawBson::Decimal128(*d), + OwnedRawBson::Undefined => RawBson::Undefined, + OwnedRawBson::MaxKey => RawBson::MaxKey, + OwnedRawBson::MinKey => RawBson::MinKey, + OwnedRawBson::DbPointer(dbp) => RawBson::DbPointer(RawDbPointer { + namespace: dbp.namespace.as_str(), + id: dbp.id, + }), + } + } +} + +impl From for OwnedRawBson { + fn from(i: i32) -> Self { + OwnedRawBson::Int32(i) + } +} + +impl From for OwnedRawBson { + fn from(i: i64) -> Self { + OwnedRawBson::Int64(i) + } +} + +impl From for OwnedRawBson { + fn from(s: String) -> Self { + OwnedRawBson::String(s) + } +} + +impl From for OwnedRawBson { + fn from(f: f64) -> Self { + OwnedRawBson::Double(f) + } +} + +impl From for OwnedRawBson { + fn from(b: bool) -> Self { + OwnedRawBson::Boolean(b) + } +} + +impl From for OwnedRawBson { + fn from(d: RawDocumentBuf) -> Self { + OwnedRawBson::Document(d) + } +} + +impl From for OwnedRawBson { + fn from(a: RawArrayBuf) -> Self { + OwnedRawBson::Array(a) + } +} + +impl From for OwnedRawBson { + fn from(dt: crate::DateTime) -> Self { + OwnedRawBson::DateTime(dt) + } +} + +impl From for OwnedRawBson { + fn from(ts: Timestamp) -> Self { + OwnedRawBson::Timestamp(ts) + } +} + +impl From for OwnedRawBson { + fn from(oid: ObjectId) -> Self { + OwnedRawBson::ObjectId(oid) + } +} + +impl From for OwnedRawBson { + fn from(d: Decimal128) -> Self { + OwnedRawBson::Decimal128(d) + } +} + +impl From for OwnedRawBson { + fn from(code_w_scope: OwnedRawJavaScriptCodeWithScope) -> Self { + OwnedRawBson::JavaScriptCodeWithScope(code_w_scope) + } +} + +impl From for OwnedRawBson { + fn from(b: Binary) -> Self { + OwnedRawBson::Binary(b) + } +} + +impl From for OwnedRawBson { + fn from(re: Regex) -> Self { + OwnedRawBson::RegularExpression(re) + } +} + +impl<'de> Deserialize<'de> for OwnedRawBson { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match deserializer + .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Owned(o) => Ok(o), + OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_owned_raw_bson()), + } + } +} + +impl Serialize for OwnedRawBson { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + self.as_raw_bson().serialize(serializer) + } +} + +impl<'a> TryFrom for Bson { + type Error = Error; + + fn try_from(rawbson: OwnedRawBson) -> Result { + Ok(match rawbson { + OwnedRawBson::Double(d) => Bson::Double(d), + OwnedRawBson::String(s) => Bson::String(s), + OwnedRawBson::Document(rawdoc) => { + Bson::Document(rawdoc.as_ref().try_into()?) + } + OwnedRawBson::Array(rawarray) => { + let mut items = Vec::new(); + for v in rawarray.into_iter() { + let bson: Bson = v?.try_into()?; + items.push(bson); + } + Bson::Array(items) + } + OwnedRawBson::Binary(rawbson) => { + Bson::Binary(rawbson) + } + OwnedRawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), + OwnedRawBson::Boolean(rawbson) => Bson::Boolean(rawbson), + OwnedRawBson::DateTime(rawbson) => Bson::DateTime(rawbson), + OwnedRawBson::Null => Bson::Null, + OwnedRawBson::RegularExpression(rawregex) => Bson::RegularExpression(crate::Regex::new( + rawregex.pattern, + rawregex.options, + )), + OwnedRawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson), + OwnedRawBson::Int32(rawbson) => Bson::Int32(rawbson), + OwnedRawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), + OwnedRawBson::Int64(rawbson) => Bson::Int64(rawbson), + OwnedRawBson::Undefined => Bson::Undefined, + OwnedRawBson::DbPointer(rawbson) => Bson::DbPointer(DbPointer { + namespace: rawbson.namespace, + id: rawbson.id, + }), + OwnedRawBson::Symbol(rawbson) => Bson::Symbol(rawbson), + OwnedRawBson::JavaScriptCodeWithScope(rawbson) => { + Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope { + code: rawbson.code, + scope: rawbson.scope.try_into()?, + }) + } + OwnedRawBson::Decimal128(rawbson) => Bson::Decimal128(rawbson), + OwnedRawBson::MaxKey => Bson::MaxKey, + OwnedRawBson::MinKey => Bson::MinKey, + }) + } +} + +/// A BSON "code with scope" value backed by owned raw BSON. +#[derive(Debug, Clone, PartialEq)] +pub struct OwnedRawJavaScriptCodeWithScope { + /// The code value. + pub code: String, + + /// The scope document. + pub scope: RawDocumentBuf, +} + +impl<'de> Deserialize<'de> for OwnedRawJavaScriptCodeWithScope { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match OwnedRawBson::deserialize(deserializer)? { + OwnedRawBson::JavaScriptCodeWithScope(b) => Ok(b), + c => Err(serde::de::Error::custom(format!( + "expected CodeWithScope, but got {:?} instead", + c + ))), + } + } +} + +impl Serialize for OwnedRawJavaScriptCodeWithScope { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer + { + let raw = RawJavaScriptCodeWithScope { + code: self.code.as_str(), + scope: self.scope.as_ref() + }; + + raw.serialize(serializer) + } +} diff --git a/src/raw/serde.rs b/src/raw/serde.rs new file mode 100644 index 00000000..182ac991 --- /dev/null +++ b/src/raw/serde.rs @@ -0,0 +1,374 @@ +use std::{borrow::Cow, fmt::Debug}; + +use serde::{de::Visitor, Deserialize}; +use serde_bytes::ByteBuf; + +use crate::{ + de::convert_unsigned_to_signed_raw, + extjson, + oid::ObjectId, + raw::{OwnedRawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, + spec::BinarySubtype, + Binary, DateTime, DbPointer, Decimal128, RawArray, RawBinary, RawBson, RawDbPointer, + RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, Regex, Timestamp, +}; + +use super::owned_bson::OwnedRawBson; + +pub(crate) enum OwnedOrBorrowedRawBson<'a> { + Owned(OwnedRawBson), + Borrowed(RawBson<'a>), +} + +impl<'a> Debug for OwnedOrBorrowedRawBson<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Owned(o) => o.fmt(f), + Self::Borrowed(b) => b.fmt(f), + } + } +} + +impl<'a> From> for OwnedOrBorrowedRawBson<'a> { + fn from(b: RawBson<'a>) -> Self { + OwnedOrBorrowedRawBson::Borrowed(b) + } +} + +impl<'a> From for OwnedOrBorrowedRawBson<'a> { + fn from(b: OwnedRawBson) -> Self { + OwnedOrBorrowedRawBson::Owned(b) + } +} + +#[derive(Debug, Deserialize)] +struct CowStr<'a>(#[serde(borrow)] Cow<'a, str>); + +#[derive(Debug, Deserialize)] +struct CowRawDocument<'a>(#[serde(borrow)] Cow<'a, RawDocument>); + +/// A visitor used to deserialize types backed by raw BSON. +pub(crate) struct OwnedOrBorrowedRawBsonVisitor; + +impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { + type Value = OwnedOrBorrowedRawBson<'de>; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "a raw BSON value") + } + + fn visit_borrowed_str(self, v: &'de str) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::String(v).into()) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(OwnedRawBson::String(v).into()) + } + + fn visit_borrowed_bytes(self, bytes: &'de [u8]) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Binary(RawBinary { + bytes, + subtype: BinarySubtype::Generic, + }) + .into()) + } + + fn visit_i8(self, v: i8) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Int32(v.into()).into()) + } + + fn visit_i16(self, v: i16) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Int32(v.into()).into()) + } + + fn visit_i32(self, v: i32) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Int32(v).into()) + } + + fn visit_i64(self, v: i64) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Int64(v).into()) + } + + fn visit_u8(self, value: u8) -> std::result::Result + where + E: serde::de::Error, + { + Ok(convert_unsigned_to_signed_raw(value.into())?.into()) + } + + fn visit_u16(self, value: u16) -> std::result::Result + where + E: serde::de::Error, + { + Ok(convert_unsigned_to_signed_raw(value.into())?.into()) + } + + fn visit_u32(self, value: u32) -> std::result::Result + where + E: serde::de::Error, + { + Ok(convert_unsigned_to_signed_raw(value.into())?.into()) + } + + fn visit_u64(self, value: u64) -> std::result::Result + where + E: serde::de::Error, + { + Ok(convert_unsigned_to_signed_raw(value)?.into()) + } + + fn visit_bool(self, v: bool) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Boolean(v).into()) + } + + fn visit_f64(self, v: f64) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Double(v).into()) + } + + fn visit_none(self) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Null.into()) + } + + fn visit_unit(self) -> std::result::Result + where + E: serde::de::Error, + { + Ok(RawBson::Null.into()) + } + + fn visit_newtype_struct(self, deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_any(self) + } + + fn visit_map(self, mut map: A) -> std::result::Result + where + A: serde::de::MapAccess<'de>, + { + fn build_doc<'de, A>( + first_key: &str, + mut map: A, + ) -> std::result::Result, A::Error> + where + A: serde::de::MapAccess<'de>, + { + let mut doc = RawDocumentBuf::new(); + let v: OwnedRawBson = map.next_value()?; + doc.append(first_key, v); + + while let Some((k, v)) = map.next_entry::<&str, OwnedRawBson>()? { + doc.append(k, v); + } + + Ok(OwnedRawBson::Document(doc).into()) + } + + println!("deserializing cow"); + let k = match map.next_key::()? { + Some(k) => k, + None => return Ok(OwnedRawBson::Document(RawDocumentBuf::new()).into()), + }; + println!("deserialized {}", k.0); + + match k.0 { + Cow::Borrowed(_) => println!("borrowed"), + _ => println!("not borrowed"), + }; + + match k.0.as_ref() { + "$oid" => { + let oid: ObjectId = map.next_value()?; + Ok(RawBson::ObjectId(oid).into()) + } + "$symbol" => { + let s: CowStr = map.next_value()?; + match s.0 { + Cow::Borrowed(s) => Ok(RawBson::Symbol(s).into()), + Cow::Owned(s) => Ok(OwnedRawBson::Symbol(s).into()), + } + } + "$numberDecimalBytes" => { + let bytes = map.next_value::()?; + return Ok(RawBson::Decimal128(Decimal128::deserialize_from_slice(&bytes)?).into()); + } + "$regularExpression" => { + #[derive(Debug, Deserialize)] + struct BorrowedRegexBody<'a> { + #[serde(borrow)] + pattern: Cow<'a, str>, + + #[serde(borrow)] + options: Cow<'a, str>, + } + let body: BorrowedRegexBody = map.next_value()?; + + match (body.pattern, body.options) { + (Cow::Borrowed(p), Cow::Borrowed(o)) => { + Ok(RawBson::RegularExpression(RawRegex { + pattern: p, + options: o, + }) + .into()) + } + (p, o) => Ok(OwnedRawBson::RegularExpression(Regex { + pattern: p.into_owned(), + options: o.into_owned(), + }) + .into()), + } + } + "$undefined" => { + let _: bool = map.next_value()?; + Ok(RawBson::Undefined.into()) + } + "$binary" => { + #[derive(Debug, Deserialize)] + struct BorrowedBinaryBody<'a> { + #[serde(borrow)] + bytes: Cow<'a, [u8]>, + + #[serde(rename = "subType")] + subtype: u8, + } + + let v = map.next_value::()?; + + if let Cow::Borrowed(bytes) = v.bytes { + Ok(RawBson::Binary(RawBinary { + bytes, + subtype: v.subtype.into(), + }) + .into()) + } else { + Ok(OwnedRawBson::Binary(Binary { + bytes: v.bytes.into_owned(), + subtype: v.subtype.into(), + }) + .into()) + } + } + "$date" => { + let v = map.next_value::()?; + Ok(RawBson::DateTime(DateTime::from_millis(v)).into()) + } + "$timestamp" => { + let v = map.next_value::()?; + Ok(RawBson::Timestamp(Timestamp { + time: v.t, + increment: v.i, + }) + .into()) + } + "$minKey" => { + let _ = map.next_value::()?; + Ok(RawBson::MinKey.into()) + } + "$maxKey" => { + let _ = map.next_value::()?; + Ok(RawBson::MaxKey.into()) + } + "$code" => { + let code = map.next_value::()?; + if let Some(key) = map.next_key::()? { + if key.0.as_ref() == "$scope" { + let scope = map.next_value::()?; + + match (code.0, scope.0) { + (Cow::Borrowed(code), Cow::Borrowed(scope)) => Ok( + RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { + code, + scope, + }) + .into(), + ), + (code, scope) => Ok(OwnedRawBson::JavaScriptCodeWithScope( + OwnedRawJavaScriptCodeWithScope { + code: code.into_owned(), + scope: scope.into_owned(), + }, + ) + .into()), + } + } else { + Err(serde::de::Error::unknown_field(&key.0, &["$scope"])) + } + } else { + if let Cow::Borrowed(code) = code.0 { + Ok(RawBson::JavaScriptCode(code).into()) + } else { + Ok(OwnedRawBson::JavaScriptCode(code.0.into_owned()).into()) + } + } + } + "$dbPointer" => { + #[derive(Deserialize)] + struct BorrowedDbPointerBody<'a> { + #[serde(rename = "$ref")] + #[serde(borrow)] + ns: CowStr<'a>, + + #[serde(rename = "$id")] + id: ObjectId, + } + + let body: BorrowedDbPointerBody = map.next_value()?; + if let Cow::Borrowed(ns) = body.ns.0 { + Ok(RawBson::DbPointer(RawDbPointer { + namespace: ns, + id: body.id, + }) + .into()) + } else { + Ok(OwnedRawBson::DbPointer(DbPointer { + namespace: body.ns.0.into_owned(), + id: body.id, + }) + .into()) + } + } + RAW_DOCUMENT_NEWTYPE => { + let bson = map.next_value::<&[u8]>()?; + let doc = RawDocument::new(bson).map_err(serde::de::Error::custom)?; + Ok(RawBson::Document(doc).into()) + } + RAW_ARRAY_NEWTYPE => { + let bson = map.next_value::<&[u8]>()?; + let doc = RawDocument::new(bson).map_err(serde::de::Error::custom)?; + Ok(RawBson::Array(RawArray::from_doc(doc)).into()) + } + k => build_doc(k, map), + } + } +} diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs index 4a543281..942bdcab 100644 --- a/src/raw/test/append.rs +++ b/src/raw/test/append.rs @@ -10,7 +10,7 @@ use pretty_assertions::assert_eq; fn append_test(expected: Document, append: impl FnOnce(&mut RawDocumentBuf)) { let bytes = crate::to_vec(&expected).unwrap(); - let mut buf = RawDocumentBuf::empty(); + let mut buf = RawDocumentBuf::new(); append(&mut buf); assert_eq!(buf.as_bytes(), bytes); } @@ -109,8 +109,8 @@ fn document() { } }; append_test(expected, |doc| { - doc.append("empty", &RawDocumentBuf::empty()); - let mut buf = RawDocumentBuf::empty(); + doc.append("empty", &RawDocumentBuf::new()); + let mut buf = RawDocumentBuf::new(); buf.append("a", 1_i32); buf.append("b", true); doc.append("subdoc", &buf); @@ -133,7 +133,7 @@ fn array() { let mut buf = RawArrayBuf::new(); buf.append(true); buf.append("string"); - let mut subdoc = RawDocumentBuf::empty(); + let mut subdoc = RawDocumentBuf::new(); subdoc.append("a", "subdoc"); buf.append(&subdoc); buf.append(123_i32); @@ -265,7 +265,7 @@ fn code() { append_test(expected, |doc| { doc.append("code", RawBson::JavaScriptCode("some code")); - let mut scope = RawDocumentBuf::empty(); + let mut scope = RawDocumentBuf::new(); scope.append("a", 1_i32); scope.append("b", true); doc.append( @@ -346,10 +346,10 @@ fn general() { doc.append("third", 15_i64); doc.append("32", -100101_i32); - let mut subdoc = RawDocumentBuf::empty(); + let mut subdoc = RawDocumentBuf::new(); subdoc.append("a", "subkey"); - let mut subsubdoc = RawDocumentBuf::empty(); + let mut subsubdoc = RawDocumentBuf::new(); subsubdoc.append("subdoc", dt); subdoc.append("another", &subsubdoc); doc.append("subdoc", &subdoc); @@ -358,7 +358,7 @@ fn general() { array.append(1_i64); array.append(true); - let mut array_subdoc = RawDocumentBuf::empty(); + let mut array_subdoc = RawDocumentBuf::new(); array_subdoc.append("doc", 23_i64); array.append(&array_subdoc); diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index f5919ea0..dc233f36 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -483,7 +483,7 @@ fn into_bson_conversion() { #[test] fn append() { - let mut buf = RawDocumentBuf::empty(); + let mut buf = RawDocumentBuf::new(); buf.append("dog", RawBson::Int32(4)); buf.append("cat", RawBson::Int32(1)); @@ -498,14 +498,14 @@ use std::convert::TryInto; proptest! { #[test] fn no_crashes(s: Vec) { - let _ = RawDocumentBuf::new(s); + let _ = RawDocumentBuf::from_bytes(s); } #[test] fn roundtrip_bson(bson in arbitrary_bson()) { let doc = doc!{"bson": bson}; let raw = to_bytes(&doc); - let raw = RawDocumentBuf::new(raw); + let raw = RawDocumentBuf::from_bytes(raw); prop_assert!(raw.is_ok()); let raw = raw.unwrap(); let roundtrip: Result = raw.try_into(); From d45ee9dcb8981780706b8f284e6f4a3625e3d583 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 15:30:20 -0500 Subject: [PATCH 09/21] add owned raw bson to corpus field tests --- src/de/raw.rs | 40 +++++++++++--- src/raw/array.rs | 21 ++++++-- src/raw/array_buf.rs | 12 ++--- src/raw/bson.rs | 33 ++++++++---- src/raw/document.rs | 19 +++++-- src/raw/document_buf.rs | 33 +++++++++--- src/raw/mod.rs | 6 +-- src/raw/owned_bson.rs | 109 +++++++++++++++++++++++-------------- src/raw/serde.rs | 74 +++++++++++++++++++++----- src/raw/test/append.rs | 112 ++++++++++++++++++++++----------------- src/raw/test/mod.rs | 10 ---- src/tests/spec/corpus.rs | 30 ++++++++--- 12 files changed, 346 insertions(+), 153 deletions(-) diff --git a/src/de/raw.rs b/src/de/raw.rs index 83f654ef..82906a8d 100644 --- a/src/de/raw.rs +++ b/src/de/raw.rs @@ -650,7 +650,7 @@ impl<'d, 'de> serde::de::Deserializer<'de> for DocumentKeyDeserializer<'d, 'de> fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where - V: serde::de::Visitor<'de> + V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } @@ -683,7 +683,7 @@ impl<'de> serde::de::Deserializer<'de> for FieldDeserializer { fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where - V: serde::de::Visitor<'de> + V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } @@ -1110,13 +1110,20 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut DateTimeDeserializer { } } + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq - bytes byte_buf map struct option unit newtype_struct + bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } @@ -1343,13 +1350,20 @@ impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserial } } + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq - bytes byte_buf map struct option unit newtype_struct + bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } @@ -1452,13 +1466,20 @@ impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut DbPointerDeserializer } } + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq - bytes byte_buf map struct option unit newtype_struct + bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } @@ -1660,13 +1681,20 @@ impl<'de, 'a> serde::de::Deserializer<'de> for RawBsonDeserializer<'de> { } } + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq - bytes byte_buf map struct option unit newtype_struct + bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } diff --git a/src/raw/array.rs b/src/raw/array.rs index 9d57f09b..7deb5c5d 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -12,7 +12,18 @@ use super::{ RawRegex, Result, }; -use crate::{Bson, DateTime, RawArrayBuf, Timestamp, oid::ObjectId, raw::{RAW_ARRAY_NEWTYPE, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}, spec::{BinarySubtype, ElementType}}; +use crate::{ + oid::ObjectId, + raw::{ + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + RAW_ARRAY_NEWTYPE, + }, + spec::{BinarySubtype, ElementType}, + Bson, + DateTime, + RawArrayBuf, + Timestamp, +}; /// A slice of a BSON document containing a BSON array value (akin to [`std::str`]). This can be /// retrieved from a [`RawDocument`] via [`RawDocument::get`]. @@ -269,9 +280,13 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray { where D: serde::Deserializer<'de>, { - match deserializer.deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { + match deserializer + .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(d), - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; Ok(RawArray::from_doc(doc)) } diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index c8cea8f8..c2af02ae 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -6,11 +6,11 @@ use std::{ use crate::{RawArray, RawBson, RawDocumentBuf}; -use super::{RawArrayIter, owned_bson::OwnedRawBson}; +use super::{owned_bson::OwnedRawBson, RawArrayIter}; -/// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes. -/// This type can be used to construct owned array values, which can be used to append to [`RawDocumentBuf`] -/// or as a field in a `Deserialize` struct. +/// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON +/// bytes. This type can be used to construct owned array values, which can be used to append to +/// [`RawDocumentBuf`] or as a field in a `Deserialize` struct. /// /// Iterating over a [`RawArrayBuf`] yields either an error or a key-value pair that borrows from /// the original document without making any additional allocations. @@ -29,7 +29,7 @@ use super::{RawArrayIter, owned_bson::OwnedRawBson}; /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_i32(), Some(12)); -/// +/// /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` @@ -85,7 +85,7 @@ impl RawArrayBuf { /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_i32(), Some(12)); - /// + /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_document(), Some(&doc)); /// diff --git a/src/raw/bson.rs b/src/raw/bson.rs index 4e0945a5..dada057d 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -9,18 +9,32 @@ use serde_bytes::{ByteBuf, Bytes}; use super::{ owned_bson::OwnedRawBson, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - Error, RawArray, RawDocument, Result, + Error, + RawArray, + RawDocument, + Result, }; use crate::{ de::convert_unsigned_to_signed_raw, extjson, oid::{self, ObjectId}, raw::{ - OwnedRawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE, + OwnedRawJavaScriptCodeWithScope, + RAW_ARRAY_NEWTYPE, + RAW_BSON_NEWTYPE, + RAW_DOCUMENT_NEWTYPE, }, spec::{BinarySubtype, ElementType}, - Binary, Bson, DateTime, DbPointer, Decimal128, JavaScriptCodeWithScope, RawArrayBuf, - RawDocumentBuf, Regex, Timestamp, + Binary, + Bson, + DateTime, + DbPointer, + Decimal128, + JavaScriptCodeWithScope, + RawArrayBuf, + RawDocumentBuf, + Regex, + Timestamp, }; /// A BSON value referencing raw bytes stored elsewhere. @@ -275,7 +289,7 @@ impl<'a> RawBson<'a> { RawBson::Timestamp(t) => OwnedRawBson::Timestamp(t), RawBson::Binary(b) => OwnedRawBson::Binary(Binary { bytes: b.bytes.to_vec(), - subtype: b.subtype + subtype: b.subtype, }), RawBson::ObjectId(o) => OwnedRawBson::ObjectId(o), RawBson::DateTime(dt) => OwnedRawBson::DateTime(dt), @@ -286,7 +300,7 @@ impl<'a> RawBson<'a> { RawBson::MinKey => OwnedRawBson::MinKey, RawBson::DbPointer(d) => OwnedRawBson::DbPointer(DbPointer { namespace: d.namespace.to_string(), - id: d.id + id: d.id, }), } } @@ -301,9 +315,10 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawBson<'a> { .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b), - _ => Err(serde::de::Error::custom( - "RawBson must be deserialized from borrowed content", - )), + o => Err(serde::de::Error::custom(format!( + "RawBson must be deserialized from borrowed content, instead got {:?}", + o + ))), } } } diff --git a/src/raw/document.rs b/src/raw/document.rs index 004a5437..9293c531 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -5,7 +5,16 @@ use std::{ use serde::{ser::SerializeMap, Deserialize, Serialize}; -use crate::{DateTime, Timestamp, raw::{RAW_DOCUMENT_NEWTYPE, error::ErrorKind, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}, spec::BinarySubtype}; +use crate::{ + raw::{ + error::ErrorKind, + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + RAW_DOCUMENT_NEWTYPE, + }, + spec::BinarySubtype, + DateTime, + Timestamp, +}; use super::{ error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, @@ -494,13 +503,17 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { where D: serde::Deserializer<'de>, { - match deserializer.deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { + match deserializer + .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(d), // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializier will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { RawDocument::new(b.bytes).map_err(serde::de::Error::custom) } diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index a08919fd..aba81deb 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -8,7 +8,17 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{Document, RawBinary, RawJavaScriptCodeWithScope, de::MIN_BSON_DOCUMENT_SIZE, raw::{RAW_DOCUMENT_NEWTYPE, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}, spec::{BinarySubtype, ElementType}}; +use crate::{ + de::MIN_BSON_DOCUMENT_SIZE, + raw::{ + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + RAW_DOCUMENT_NEWTYPE, + }, + spec::{BinarySubtype, ElementType}, + Document, + RawBinary, + RawJavaScriptCodeWithScope, +}; use super::{owned_bson::OwnedRawBson, Error, ErrorKind, Iter, RawBson, RawDocument, Result}; @@ -152,8 +162,8 @@ impl RawDocumentBuf { /// Append a key value pair to the end of the document without checking to see if /// the key already exists. /// - /// It is a user error to append the same key more than once to the same document, and it may result - /// in errors when communicating with MongoDB. + /// It is a user error to append the same key more than once to the same document, and it may + /// result in errors when communicating with MongoDB. /// /// If the provided key contains an interior null byte, this method will panic. /// @@ -174,7 +184,7 @@ impl RawDocumentBuf { /// "an integer": 12_i32, /// "a document": { "a key": true }, /// }; - /// + /// /// assert_eq!(doc.to_document()?, expected); /// # Ok::<(), Error>(()) /// ``` @@ -260,7 +270,8 @@ impl RawDocumentBuf { let len = RawJavaScriptCodeWithScope { code: code_w_scope.code.as_str(), scope: &code_w_scope.scope, - }.len(); + } + .len(); self.data.extend(len.to_le_bytes()); append_string(self, code_w_scope.code); self.data.extend(code_w_scope.scope.into_vec()); @@ -306,17 +317,23 @@ impl<'de> Deserialize<'de> for RawDocumentBuf { where D: serde::Deserializer<'de>, { - match deserializer.deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { + match deserializer + .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(d.to_owned()), OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(d)) => Ok(d), // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializier will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { RawDocumentBuf::from_bytes(b.bytes.to_vec()).map_err(serde::de::Error::custom) } - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom) } diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 061fd656..5e066c18 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -119,10 +119,10 @@ mod document; mod document_buf; mod error; mod iter; -#[cfg(test)] -mod test; mod owned_bson; mod serde; +#[cfg(test)] +mod test; use std::convert::{TryFrom, TryInto}; @@ -136,7 +136,7 @@ pub use self::{ document_buf::RawDocumentBuf, error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, iter::Iter, - owned_bson::{OwnedRawJavaScriptCodeWithScope, OwnedRawBson}, + owned_bson::{OwnedRawBson, OwnedRawJavaScriptCodeWithScope}, }; /// Special newtype name indicating that the type being (de)serialized is a raw BSON document. diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs index da6d83fb..18379f75 100644 --- a/src/raw/owned_bson.rs +++ b/src/raw/owned_bson.rs @@ -2,9 +2,33 @@ use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; -use crate::{Binary, Bson, DbPointer, Decimal128, JavaScriptCodeWithScope, RawArray, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, Regex, Timestamp, oid::{self, ObjectId}, raw::RAW_BSON_NEWTYPE, spec::ElementType}; - -use super::{Result, Error, serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}}; +use crate::{ + oid::{self, ObjectId}, + raw::RAW_BSON_NEWTYPE, + spec::ElementType, + Binary, + Bson, + DbPointer, + Decimal128, + JavaScriptCodeWithScope, + RawArray, + RawArrayBuf, + RawBinary, + RawBson, + RawDbPointer, + RawDocument, + RawDocumentBuf, + RawJavaScriptCodeWithScope, + RawRegex, + Regex, + Timestamp, +}; + +use super::{ + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + Error, + Result, +}; /// A BSON value backed by owned raw BSON bytes. #[derive(Debug, Clone, PartialEq)] @@ -90,8 +114,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the `String` that's wrapped or returns `None` if the wrapped value isn't a BSON - /// String. + /// Gets a reference to the `String` that's wrapped or returns `None` if the wrapped value isn't + /// a BSON String. pub fn as_str(&self) -> Option<&'_ str> { match self { OwnedRawBson::String(s) => Some(s), @@ -99,8 +123,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the wrapped value isn't a BSON - /// array. + /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the wrapped + /// value isn't a BSON array. pub fn as_array(&self) -> Option<&'_ RawArray> { match self { OwnedRawBson::Array(v) => Some(v), @@ -108,8 +132,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped value isn't a BSON - /// document. + /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped + /// value isn't a BSON document. pub fn as_document(&self) -> Option<&'_ RawDocument> { match self { OwnedRawBson::Document(v) => Some(v), @@ -144,8 +168,8 @@ impl OwnedRawBson { } } - /// Gets the wrapped [`crate::oid::ObjectId`] value or returns `None` if the wrapped value isn't a BSON - /// ObjectID. + /// Gets the wrapped [`crate::oid::ObjectId`] value or returns `None` if the wrapped value isn't + /// a BSON ObjectID. pub fn as_object_id(&self) -> Option { match self { OwnedRawBson::ObjectId(v) => Some(*v), @@ -153,8 +177,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the [`Binary`] that's wrapped or returns `None` if the wrapped value isn't a BSON - /// binary. + /// Gets a reference to the [`Binary`] that's wrapped or returns `None` if the wrapped value + /// isn't a BSON binary. pub fn as_binary(&self) -> Option> { match self { OwnedRawBson::Binary(v) => Some(RawBinary { @@ -165,8 +189,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the [`Regex`] that's wrapped or returns `None` if the wrapped value isn't a BSON - /// regular expression. + /// Gets a reference to the [`Regex`] that's wrapped or returns `None` if the wrapped value + /// isn't a BSON regular expression. pub fn as_regex(&self) -> Option> { match self { OwnedRawBson::RegularExpression(v) => Some(RawRegex { @@ -177,8 +201,8 @@ impl OwnedRawBson { } } - /// Gets the wrapped [`crate::DateTime`] value or returns `None` if the wrapped value isn't a BSON - /// datetime. + /// Gets the wrapped [`crate::DateTime`] value or returns `None` if the wrapped value isn't a + /// BSON datetime. pub fn as_datetime(&self) -> Option { match self { OwnedRawBson::DateTime(v) => Some(*v), @@ -186,8 +210,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the symbol that's wrapped or returns `None` if the wrapped value isn't a BSON - /// Symbol. + /// Gets a reference to the symbol that's wrapped or returns `None` if the wrapped value isn't a + /// BSON Symbol. pub fn as_symbol(&self) -> Option<&'_ str> { match self { OwnedRawBson::Symbol(v) => Some(v), @@ -195,8 +219,8 @@ impl OwnedRawBson { } } - /// Gets the wrapped [`crate::Timestamp`] value or returns `None` if the wrapped value isn't a BSON - /// datetime. + /// Gets the wrapped [`crate::Timestamp`] value or returns `None` if the wrapped value isn't a + /// BSON datetime. pub fn as_timestamp(&self) -> Option { match self { OwnedRawBson::Timestamp(timestamp) => Some(*timestamp), @@ -212,8 +236,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns `None` if the wrapped value isn't a BSON - /// DbPointer. + /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns `None` if the wrapped + /// value isn't a BSON DbPointer. pub fn as_db_pointer(&self) -> Option> { match self { OwnedRawBson::DbPointer(d) => Some(RawDbPointer { @@ -224,8 +248,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the code that's wrapped or returns `None` if the wrapped value isn't a BSON - /// JavaScript code. + /// Gets a reference to the code that's wrapped or returns `None` if the wrapped value isn't a + /// BSON JavaScript code. pub fn as_javascript(&self) -> Option<&'_ str> { match self { OwnedRawBson::JavaScriptCode(s) => Some(s), @@ -233,8 +257,8 @@ impl OwnedRawBson { } } - /// Gets a reference to the [`OwnedRawJavaScriptCodeWithScope`] that's wrapped or returns `None` if - /// the wrapped value isn't a BSON JavaScript code with scope value. + /// Gets a reference to the [`OwnedRawJavaScriptCodeWithScope`] that's wrapped or returns `None` + /// if the wrapped value isn't a BSON JavaScript code with scope value. pub fn as_javascript_with_scope(&self) -> Option> { match self { OwnedRawBson::JavaScriptCodeWithScope(s) => Some(RawJavaScriptCodeWithScope { @@ -305,6 +329,12 @@ impl From for OwnedRawBson { } } +impl From<&str> for OwnedRawBson { + fn from(s: &str) -> Self { + OwnedRawBson::String(s.to_owned()) + } +} + impl From for OwnedRawBson { fn from(f: f64) -> Self { OwnedRawBson::Double(f) @@ -371,6 +401,12 @@ impl From for OwnedRawBson { } } +impl From for OwnedRawBson { + fn from(d: DbPointer) -> Self { + OwnedRawBson::DbPointer(d) + } +} + impl<'de> Deserialize<'de> for OwnedRawBson { fn deserialize(deserializer: D) -> std::result::Result where @@ -401,9 +437,7 @@ impl<'a> TryFrom for Bson { Ok(match rawbson { OwnedRawBson::Double(d) => Bson::Double(d), OwnedRawBson::String(s) => Bson::String(s), - OwnedRawBson::Document(rawdoc) => { - Bson::Document(rawdoc.as_ref().try_into()?) - } + OwnedRawBson::Document(rawdoc) => Bson::Document(rawdoc.as_ref().try_into()?), OwnedRawBson::Array(rawarray) => { let mut items = Vec::new(); for v in rawarray.into_iter() { @@ -412,17 +446,14 @@ impl<'a> TryFrom for Bson { } Bson::Array(items) } - OwnedRawBson::Binary(rawbson) => { - Bson::Binary(rawbson) - } + OwnedRawBson::Binary(rawbson) => Bson::Binary(rawbson), OwnedRawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), OwnedRawBson::Boolean(rawbson) => Bson::Boolean(rawbson), OwnedRawBson::DateTime(rawbson) => Bson::DateTime(rawbson), OwnedRawBson::Null => Bson::Null, - OwnedRawBson::RegularExpression(rawregex) => Bson::RegularExpression(crate::Regex::new( - rawregex.pattern, - rawregex.options, - )), + OwnedRawBson::RegularExpression(rawregex) => { + Bson::RegularExpression(crate::Regex::new(rawregex.pattern, rawregex.options)) + } OwnedRawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson), OwnedRawBson::Int32(rawbson) => Bson::Int32(rawbson), OwnedRawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), @@ -474,11 +505,11 @@ impl<'de> Deserialize<'de> for OwnedRawJavaScriptCodeWithScope { impl Serialize for OwnedRawJavaScriptCodeWithScope { fn serialize(&self, serializer: S) -> std::result::Result where - S: serde::Serializer + S: serde::Serializer, { let raw = RawJavaScriptCodeWithScope { code: self.code.as_str(), - scope: self.scope.as_ref() + scope: self.scope.as_ref(), }; raw.serialize(serializer) diff --git a/src/raw/serde.rs b/src/raw/serde.rs index 182ac991..b518509f 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -9,17 +9,39 @@ use crate::{ oid::ObjectId, raw::{OwnedRawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, - Binary, DateTime, DbPointer, Decimal128, RawArray, RawBinary, RawBson, RawDbPointer, - RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, Regex, Timestamp, + Binary, + DateTime, + DbPointer, + Decimal128, + RawArray, + RawArrayBuf, + RawBinary, + RawBson, + RawDbPointer, + RawDocument, + RawDocumentBuf, + RawJavaScriptCodeWithScope, + RawRegex, + Regex, + Timestamp, }; -use super::owned_bson::OwnedRawBson; +use super::{owned_bson::OwnedRawBson, RAW_BSON_NEWTYPE}; pub(crate) enum OwnedOrBorrowedRawBson<'a> { Owned(OwnedRawBson), Borrowed(RawBson<'a>), } +impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawBson<'a> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor) + } +} + impl<'a> Debug for OwnedOrBorrowedRawBson<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -173,6 +195,28 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { deserializer.deserialize_any(self) } + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(OwnedRawBson::Binary(Binary { + bytes: v, + subtype: BinarySubtype::Generic, + }) + .into()) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut array = RawArrayBuf::new(); + while let Some(v) = seq.next_element::()? { + array.push(v); + } + Ok(OwnedRawBson::Array(array).into()) + } + fn visit_map(self, mut map: A) -> std::result::Result where A: serde::de::MapAccess<'de>, @@ -303,23 +347,29 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let code = map.next_value::()?; if let Some(key) = map.next_key::()? { if key.0.as_ref() == "$scope" { - let scope = map.next_value::()?; - - match (code.0, scope.0) { - (Cow::Borrowed(code), Cow::Borrowed(scope)) => Ok( + let scope = map.next_value::()?; + match (code.0, scope) { + ( + Cow::Borrowed(code), + OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(scope)), + ) => Ok( RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code, scope, }) .into(), ), - (code, scope) => Ok(OwnedRawBson::JavaScriptCodeWithScope( - OwnedRawJavaScriptCodeWithScope { - code: code.into_owned(), - scope: scope.into_owned(), - }, + ( + Cow::Owned(code), + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(scope)), + ) => Ok(OwnedRawBson::JavaScriptCodeWithScope( + OwnedRawJavaScriptCodeWithScope { code, scope }, ) .into()), + (code, scope) => Err(serde::de::Error::custom(format!( + "invalid code_w_scope: code: {:?}, scope: {:?}", + code, scope + ))), } } else { Err(serde::de::Error::unknown_field(&key.0, &["$scope"])) diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs index 942bdcab..625a46e9 100644 --- a/src/raw/test/append.rs +++ b/src/raw/test/append.rs @@ -1,9 +1,28 @@ use std::iter::FromIterator; use crate::{ - oid::ObjectId, spec::BinarySubtype, tests::LOCK, Binary, Bson, DateTime, DbPointer, Decimal128, - Document, JavaScriptCodeWithScope, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, - RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, Regex, Timestamp, + oid::ObjectId, + raw::OwnedRawJavaScriptCodeWithScope, + spec::BinarySubtype, + tests::LOCK, + Binary, + Bson, + DateTime, + DbPointer, + Decimal128, + Document, + JavaScriptCodeWithScope, + OwnedRawBson, + RawArrayBuf, + RawBinary, + RawBson, + RawDbPointer, + RawDocument, + RawDocumentBuf, + RawJavaScriptCodeWithScope, + RawRegex, + Regex, + Timestamp, }; use pretty_assertions::assert_eq; @@ -95,7 +114,7 @@ fn null() { "null": null, }; append_test(expected, |doc| { - doc.append("null", RawBson::Null); + doc.append("null", OwnedRawBson::Null); }); } @@ -109,11 +128,11 @@ fn document() { } }; append_test(expected, |doc| { - doc.append("empty", &RawDocumentBuf::new()); + doc.append("empty", RawDocumentBuf::new()); let mut buf = RawDocumentBuf::new(); buf.append("a", 1_i32); buf.append("b", true); - doc.append("subdoc", &buf); + doc.append("subdoc", buf); }); } @@ -129,15 +148,15 @@ fn array() { ] }; append_test(expected, |doc| { - doc.append("empty", &RawArrayBuf::new()); + doc.append("empty", RawArrayBuf::new()); let mut buf = RawArrayBuf::new(); - buf.append(true); - buf.append("string"); + buf.push(true); + buf.push("string"); let mut subdoc = RawDocumentBuf::new(); subdoc.append("a", "subdoc"); - buf.append(&subdoc); - buf.append(123_i32); - doc.append("array", &buf); + buf.push(subdoc); + buf.push(123_i32); + doc.append("array", buf); }); } @@ -204,8 +223,8 @@ fn binary() { }; append_test(expected, |doc| { - doc.append("generic", &bin); - doc.append("binary_old", &old); + doc.append("generic", bin); + doc.append("binary_old", old); }); } @@ -217,8 +236,8 @@ fn min_max_key() { }; append_test(expected, |doc| { - doc.append("min", RawBson::MinKey); - doc.append("max", RawBson::MaxKey); + doc.append("min", OwnedRawBson::MinKey); + doc.append("max", OwnedRawBson::MaxKey); }); } @@ -229,7 +248,7 @@ fn undefined() { }; append_test(expected, |doc| { - doc.append("undefined", RawBson::Undefined); + doc.append("undefined", OwnedRawBson::Undefined); }); } @@ -240,13 +259,7 @@ fn regex() { }; append_test(expected, |doc| { - doc.append( - "regex", - RawRegex { - pattern: "some pattern", - options: "abc", - }, - ) + doc.append("regex", Regex::new("some pattern", "abc")); }); } @@ -263,16 +276,19 @@ fn code() { }; append_test(expected, |doc| { - doc.append("code", RawBson::JavaScriptCode("some code")); + doc.append( + "code", + OwnedRawBson::JavaScriptCode("some code".to_string()), + ); let mut scope = RawDocumentBuf::new(); scope.append("a", 1_i32); scope.append("b", true); doc.append( "code_w_scope", - RawJavaScriptCodeWithScope { - code: "some code", - scope: &scope, + OwnedRawJavaScriptCodeWithScope { + code: "some code".to_string(), + scope, }, ); }); @@ -285,7 +301,7 @@ fn symbol() { }; append_test(expected, |doc| { - doc.append("symbol", RawBson::Symbol("symbol")); + doc.append("symbol", OwnedRawBson::Symbol("symbol".to_string())); }); } @@ -305,8 +321,8 @@ fn dbpointer() { append_test(expected, |doc| { doc.append( "symbol", - RawBson::DbPointer(RawDbPointer { - namespace: "ns", + OwnedRawBson::DbPointer(DbPointer { + namespace: "ns".to_string(), id, }), ); @@ -351,23 +367,23 @@ fn general() { let mut subsubdoc = RawDocumentBuf::new(); subsubdoc.append("subdoc", dt); - subdoc.append("another", &subsubdoc); - doc.append("subdoc", &subdoc); + subdoc.append("another", subsubdoc); + doc.append("subdoc", subdoc); let mut array = RawArrayBuf::new(); - array.append(1_i64); - array.append(true); + array.push(1_i64); + array.push(true); let mut array_subdoc = RawDocumentBuf::new(); array_subdoc.append("doc", 23_i64); - array.append(&array_subdoc); + array.push(array_subdoc); let mut sub_array = RawArrayBuf::new(); - sub_array.append("another"); - sub_array.append("array"); - array.append(&sub_array); + sub_array.push("another"); + sub_array.push("array"); + array.push(sub_array); - doc.append("array", &array); + doc.append("array", array); }); } @@ -376,16 +392,16 @@ fn from_iter() { let doc_buf = RawDocumentBuf::from_iter([ ( "array", - RawBson::Array(&RawArrayBuf::from_iter([ - RawBson::Boolean(true), - RawBson::Document(&RawDocumentBuf::from_iter([ - ("ok", RawBson::Boolean(false)), - ("other", RawBson::String("hello")), + OwnedRawBson::Array(RawArrayBuf::from_iter([ + OwnedRawBson::Boolean(true), + OwnedRawBson::Document(RawDocumentBuf::from_iter([ + ("ok", OwnedRawBson::Boolean(false)), + ("other", OwnedRawBson::String("hello".to_string())), ])), ])), ), - ("bool", RawBson::Boolean(true)), - ("string", RawBson::String("some string")) + ("bool", OwnedRawBson::Boolean(true)), + ("string", OwnedRawBson::String("some string".to_string())), ]); let doc = doc! { @@ -402,6 +418,6 @@ fn from_iter() { let expected = doc! { "expected": doc }; append_test(expected, |doc| { - doc.append("expected", &doc_buf); + doc.append("expected", doc_buf); }); } diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index dc233f36..77e41ab7 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -481,16 +481,6 @@ fn into_bson_conversion() { ); } -#[test] -fn append() { - let mut buf = RawDocumentBuf::new(); - buf.append("dog", RawBson::Int32(4)); - buf.append("cat", RawBson::Int32(1)); - - let doc = buf.to_document().unwrap(); - println!("{:#?}", doc); -} - use props::arbitrary_bson; use proptest::prelude::*; use std::convert::TryInto; diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs index b4329fb1..0ae32612 100644 --- a/src/tests/spec/corpus.rs +++ b/src/tests/spec/corpus.rs @@ -1,5 +1,6 @@ use std::{ convert::{TryFrom, TryInto}, + iter::FromIterator, marker::PhantomData, str::FromStr, }; @@ -9,6 +10,8 @@ use crate::{ tests::LOCK, Bson, Document, + OwnedRawBson, + RawDocumentBuf, }; use pretty_assertions::assert_eq; use serde::{Deserialize, Deserializer}; @@ -177,6 +180,18 @@ fn run_test(test: TestFile) { test_key: bson }; + // deserialize the field from raw Bytes into an OwnedRawBson + let mut deserializer_raw = + crate::de::RawDeserializer::new(canonical_bson.as_slice(), false); + let owned_raw_bson_field = deserializer_raw + .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) + .expect(&description); + // convert to an owned Bson and put into a Document + let bson: Bson = owned_raw_bson_field.try_into().expect(&description); + let from_raw_owned_raw_doc = doc! { + test_key: bson + }; + // deserialize the field from raw Bytes into a Bson let mut deserializer_value = crate::de::RawDeserializer::new(canonical_bson.as_slice(), false); @@ -184,7 +199,7 @@ fn run_test(test: TestFile) { .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) .expect(&description); // put into a Document - let from_value_doc = doc! { + let from_slice_value_doc = doc! { test_key: bson_field, }; @@ -201,13 +216,16 @@ fn run_test(test: TestFile) { // convert back into raw BSON for comparison with canonical BSON let from_raw_vec = crate::to_vec(&from_raw_doc).expect(&description); - let from_value_vec = crate::to_vec(&from_value_doc).expect(&description); - let from_value_value_vec = - crate::to_vec(&from_value_value_doc).expect(&description); + let from_slice_value_vec = + crate::to_vec(&from_slice_value_doc).expect(&description); + let from_bson_value_vec = crate::to_vec(&from_value_value_doc).expect(&description); + let from_slice_owned_vec = + crate::to_vec(&from_raw_owned_raw_doc).expect(&description); assert_eq!(from_raw_vec, canonical_bson, "{}", description); - assert_eq!(from_value_vec, canonical_bson, "{}", description); - assert_eq!(from_value_value_vec, canonical_bson, "{}", description); + assert_eq!(from_slice_value_vec, canonical_bson, "{}", description); + assert_eq!(from_bson_value_vec, canonical_bson, "{}", description); + assert_eq!(from_slice_owned_vec, canonical_bson, "{}", description); } } From b8089f2d435ee200dc2eee2b12857900cdf2592a Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 16:36:23 -0500 Subject: [PATCH 10/21] minor improvements --- src/raw/document_buf.rs | 2 +- src/raw/serde.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index aba81deb..01719546 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -224,7 +224,7 @@ impl RawDocumentBuf { self.data.extend(d.into_vec()); } OwnedRawBson::Array(a) => { - self.data.extend(a.as_bytes()); + self.data.extend(a.into_vec()); } OwnedRawBson::Binary(b) => { let len = RawBinary { diff --git a/src/raw/serde.rs b/src/raw/serde.rs index b518509f..2b476ccd 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -86,6 +86,13 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { Ok(RawBson::String(v).into()) } + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(OwnedRawBson::String(v.to_string()).into()) + } + fn visit_string(self, v: String) -> Result where E: serde::de::Error, @@ -232,7 +239,7 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let v: OwnedRawBson = map.next_value()?; doc.append(first_key, v); - while let Some((k, v)) = map.next_entry::<&str, OwnedRawBson>()? { + while let Some((k, v)) = map.next_entry::()? { doc.append(k, v); } From ae501783923ae94c7a63efacab37f49d746a0ac8 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 16:47:13 -0500 Subject: [PATCH 11/21] add serialize/deserialize impl to rawarraybuf, serde tests for owned --- serde-tests/json.rs | 132 +++++++++++++++++++++++++++++++++++++++ serde-tests/test.rs | 109 +++++++++++++++++--------------- src/raw/array_buf.rs | 59 ++++++++++++++++- src/raw/owned_bson.rs | 5 +- src/tests/spec/corpus.rs | 6 ++ 5 files changed, 257 insertions(+), 54 deletions(-) create mode 100644 serde-tests/json.rs diff --git a/serde-tests/json.rs b/serde-tests/json.rs new file mode 100644 index 00000000..b5b44435 --- /dev/null +++ b/serde-tests/json.rs @@ -0,0 +1,132 @@ +use pretty_assertions::assert_eq; +use serde_json::json; + +use super::AllTypes; + +use bson::{doc, Bson, JavaScriptCodeWithScope, OwnedRawBson, RawArrayBuf, RawDocumentBuf}; + +use serde::{Deserialize, Serialize}; + +#[test] +fn all_types_json() { + let (mut v, _) = AllTypes::fixtures(); + + let code = match v.code { + Bson::JavaScriptCode(ref c) => c.clone(), + c => panic!("expected code, found {:?}", c), + }; + + let code_w_scope = JavaScriptCodeWithScope { + code: "hello world".to_string(), + scope: doc! { "x": 1 }, + }; + let scope_json = serde_json::json!({ "x": 1 }); + v.code_w_scope = code_w_scope.clone(); + + let json = serde_json::json!({ + "x": 1, + "y": 2, + "s": "oke", + "array": vec![ + serde_json::json!(true), + serde_json::json!("oke".to_string()), + serde_json::json!({ "12": 24 }), + ], + "bson": 1234.5, + "oid": { "$oid": v.oid.to_hex() }, + "null": serde_json::Value::Null, + "subdoc": { "k": true, "b": { "hello": "world" } }, + "b": true, + "d": 12.5, + "binary": v.binary.bytes, + "binary_old": { "$binary": { "base64": base64::encode(&v.binary_old.bytes), "subType": "02" } }, + "binary_other": { "$binary": { "base64": base64::encode(&v.binary_old.bytes), "subType": "81" } }, + "date": { "$date": { "$numberLong": v.date.timestamp_millis().to_string() } }, + "regex": { "$regularExpression": { "pattern": v.regex.pattern, "options": v.regex.options } }, + "ts": { "$timestamp": { "t": 123, "i": 456 } }, + "i": { "a": v.i.a, "b": v.i.b }, + "undefined": { "$undefined": true }, + "code": { "$code": code }, + "code_w_scope": { "$code": code_w_scope.code, "$scope": scope_json }, + "decimal": { "$numberDecimalBytes": v.decimal.bytes() }, + "symbol": { "$symbol": "ok" }, + "min_key": { "$minKey": 1 }, + "max_key": { "$maxKey": 1 }, + }); + + assert_eq!(serde_json::to_value(&v).unwrap(), json); +} + +#[test] +fn owned_raw_bson() { + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct Foo { + doc_buf: RawDocumentBuf, + array_buf: RawArrayBuf, + bson_array: OwnedRawBson, + bson_doc: OwnedRawBson, + bson_integer: OwnedRawBson, + bson_string: OwnedRawBson, + bson_bool: OwnedRawBson, + bson_null: OwnedRawBson, + bson_float: OwnedRawBson, + } + + let json = json!({ + "doc_buf": { + "a": "key", + "number": 12, + "bool": false, + "nu": null + }, + "array_buf": [ + json!(1), + json!("string"), + ], + "bson_array": [ + json!(1), + json!("string"), + ], + "bson_doc": { + "first": true, + "second": "string", + }, + "bson_integer": 12, + "bson_string": "String", + "bson_bool": true, + "bson_null": null, + "bson_float": 123.4 + }); + + let mut doc_buf = RawDocumentBuf::new(); + doc_buf.append("a", "key"); + doc_buf.append("number", 12); + doc_buf.append("bool", false); + doc_buf.append("nu", OwnedRawBson::Null); + + let mut array_buf = RawArrayBuf::new(); + array_buf.push(1); + array_buf.push("string"); + + let mut bson_doc = RawDocumentBuf::new(); + bson_doc.append("first", true); + bson_doc.append("second", "string"); + + let expected = Foo { + doc_buf, + array_buf: array_buf.clone(), + bson_array: OwnedRawBson::Array(array_buf), + bson_doc: OwnedRawBson::Document(bson_doc), + bson_integer: OwnedRawBson::Int32(12), + bson_string: OwnedRawBson::String("String".to_string()), + bson_bool: OwnedRawBson::Boolean(true), + bson_null: OwnedRawBson::Null, + bson_float: OwnedRawBson::Double(123.4), + }; + + let f: Foo = serde_json::from_value(json.clone()).unwrap(); + assert_eq!(f, expected); + + let round_trip = serde_json::to_value(&f).unwrap(); + assert_eq!(round_trip, json); +} diff --git a/serde-tests/test.rs b/serde-tests/test.rs index 85c62ace..ee88df15 100644 --- a/serde-tests/test.rs +++ b/serde-tests/test.rs @@ -1,6 +1,7 @@ #![allow(clippy::cognitive_complexity)] #![allow(clippy::vec_init_then_push)] +mod json; mod options; use pretty_assertions::assert_eq; @@ -14,6 +15,7 @@ use serde::{ use std::{ borrow::Cow, collections::{BTreeMap, HashSet}, + iter::FromIterator, }; use bson::{ @@ -29,7 +31,9 @@ use bson::{ DeserializerOptions, Document, JavaScriptCodeWithScope, + OwnedRawBson, RawArray, + RawArrayBuf, RawBinary, RawBson, RawDbPointer, @@ -1018,56 +1022,6 @@ fn all_types() { run_test(&v, &doc, "all types"); } -#[test] -fn all_types_json() { - let (mut v, _) = AllTypes::fixtures(); - - let code = match v.code { - Bson::JavaScriptCode(ref c) => c.clone(), - c => panic!("expected code, found {:?}", c), - }; - - let code_w_scope = JavaScriptCodeWithScope { - code: "hello world".to_string(), - scope: doc! { "x": 1 }, - }; - let scope_json = serde_json::json!({ "x": 1 }); - v.code_w_scope = code_w_scope.clone(); - - let json = serde_json::json!({ - "x": 1, - "y": 2, - "s": "oke", - "array": vec![ - serde_json::json!(true), - serde_json::json!("oke".to_string()), - serde_json::json!({ "12": 24 }), - ], - "bson": 1234.5, - "oid": { "$oid": v.oid.to_hex() }, - "null": serde_json::Value::Null, - "subdoc": { "k": true, "b": { "hello": "world" } }, - "b": true, - "d": 12.5, - "binary": v.binary.bytes, - "binary_old": { "$binary": { "base64": base64::encode(&v.binary_old.bytes), "subType": "02" } }, - "binary_other": { "$binary": { "base64": base64::encode(&v.binary_old.bytes), "subType": "81" } }, - "date": { "$date": { "$numberLong": v.date.timestamp_millis().to_string() } }, - "regex": { "$regularExpression": { "pattern": v.regex.pattern, "options": v.regex.options } }, - "ts": { "$timestamp": { "t": 123, "i": 456 } }, - "i": { "a": v.i.a, "b": v.i.b }, - "undefined": { "$undefined": true }, - "code": { "$code": code }, - "code_w_scope": { "$code": code_w_scope.code, "$scope": scope_json }, - "decimal": { "$numberDecimalBytes": v.decimal.bytes() }, - "symbol": { "$symbol": "ok" }, - "min_key": { "$minKey": 1 }, - "max_key": { "$maxKey": 1 }, - }); - - assert_eq!(serde_json::to_value(&v).unwrap(), json); -} - #[test] fn all_types_rmp() { let (v, _) = AllTypes::fixtures(); @@ -1111,7 +1065,7 @@ fn all_raw_types_rmp() { } }) .unwrap(); - let doc_buf = RawDocumentBuf::new(doc_bytes).unwrap(); + let doc_buf = RawDocumentBuf::from_bytes(doc_bytes).unwrap(); let document = &doc_buf; let array = document.get_array("array").unwrap(); @@ -1280,6 +1234,59 @@ fn serde_with_uuid() { run_test(&f, &expected, "serde_with - uuid"); } +#[test] +fn owned_raw_types() { + #[derive(Debug, Deserialize, Serialize, PartialEq)] + struct Foo { + subdoc: RawDocumentBuf, + array: RawArrayBuf, + } + + let oid = ObjectId::new(); + let dt = DateTime::now(); + + let f = Foo { + subdoc: RawDocumentBuf::from_iter([ + ("a key", OwnedRawBson::String("a value".to_string())), + ("an objectid", OwnedRawBson::ObjectId(oid)), + ("a date", OwnedRawBson::DateTime(dt)), + ]), + array: RawArrayBuf::from_iter([ + OwnedRawBson::String("a string".to_string()), + OwnedRawBson::ObjectId(oid), + OwnedRawBson::DateTime(dt), + ]), + }; + + let expected = doc! { + "subdoc": { + "a key": "a value", + "an objectid": oid, + "a date": dt, + }, + "array": [ + "a string", + oid, + dt + ] + }; + + // TODO: RUST-1111 + // can't use run_test here because deserializing RawDocumentBuf and RawArrayBuf + // from Bson or Document currently don't work. + + let bytes = bson::to_vec(&expected).unwrap(); + + let deserialized: Foo = bson::from_slice(bytes.as_slice()).unwrap(); + assert_eq!(deserialized, f); + + let serialized = bson::to_document(&deserialized).unwrap(); + assert_eq!(serialized, expected); + + let serialized_bytes = bson::to_vec(&deserialized).unwrap(); + assert_eq!(serialized_bytes, bytes); +} + #[test] fn hint_cleared() { #[derive(Debug, Serialize, Deserialize)] diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index c2af02ae..c169b44e 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -4,7 +4,19 @@ use std::{ iter::FromIterator, }; -use crate::{RawArray, RawBson, RawDocumentBuf}; +use serde::{Deserialize, Serialize}; + +use crate::{ + raw::{ + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + RAW_ARRAY_NEWTYPE, + }, + spec::BinarySubtype, + RawArray, + RawBson, + RawDocument, + RawDocumentBuf, +}; use super::{owned_bson::OwnedRawBson, RawArrayIter}; @@ -74,7 +86,7 @@ impl RawArrayBuf { /// /// let mut doc = RawDocumentBuf::new(); /// doc.append("a key", "a value"); - /// array.push(&doc); + /// array.push(doc); /// /// assert_eq!(array.len(), 3); /// @@ -104,6 +116,10 @@ impl RawArrayBuf { pub fn len(&self) -> usize { self.len } + + pub(crate) fn into_vec(self) -> Vec { + self.inner.into_vec() + } } impl Debug for RawArrayBuf { @@ -165,3 +181,42 @@ impl> FromIterator for RawArrayBuf { array_buf } } + +impl<'de> Deserialize<'de> for RawArrayBuf { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match deserializer + .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(d.to_owned()), + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { + let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; + Ok(RawArray::from_doc(doc).to_owned()) + } + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Array(d)) => Ok(d), + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { + let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?; + Ok(RawArrayBuf::from_raw_document_buf(doc)) + } + b => Err(serde::de::Error::custom(format!( + "expected raw BSON array, instead got {:?}", + b + ))), + } + } +} + +impl Serialize for RawArrayBuf { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.as_ref().serialize(serializer) + } +} diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs index 18379f75..25211a0b 100644 --- a/src/raw/owned_bson.rs +++ b/src/raw/owned_bson.rs @@ -1,4 +1,7 @@ -use std::convert::{TryFrom, TryInto}; +use std::{ + borrow::Borrow, + convert::{TryFrom, TryInto}, +}; use serde::{Deserialize, Serialize}; diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs index 0ae32612..a680d64a 100644 --- a/src/tests/spec/corpus.rs +++ b/src/tests/spec/corpus.rs @@ -126,6 +126,9 @@ fn run_test(test: TestFile) { .as_document() .expect(&description); + let canonical_owned_raw_bson_from_slice = + crate::from_slice::(canonical_bson.as_slice()).expect(&description); + let canonical_raw_document_from_slice = crate::from_slice::<&RawDocument>(canonical_bson.as_slice()).expect(&description); @@ -163,6 +166,8 @@ fn run_test(test: TestFile) { let tovec_rawdocument_from_slice = crate::to_vec(&canonical_raw_document_from_slice).expect(&description); let tovec_rawbson = crate::to_vec(&canonical_raw_bson_from_slice).expect(&description); + let tovec_ownedrawbson = + crate::to_vec(&canonical_owned_raw_bson_from_slice).expect(&description); // test Bson / RawBson field deserialization if let Some(ref test_key) = test.test_key { @@ -281,6 +286,7 @@ fn run_test(test: TestFile) { "{}", description ); + assert_eq!(tovec_rawdocument, tovec_ownedrawbson, "{}", description); assert_eq!( hex::encode(tovec_rawdocument).to_lowercase(), From 52e6176a75f960bb78b677e5ac33e86dc290b5d4 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 16:55:27 -0500 Subject: [PATCH 12/21] fix clippy --- src/de/raw.rs | 6 +++--- src/raw/array_buf.rs | 16 ++++++---------- src/raw/bson.rs | 21 +++++---------------- src/raw/document.rs | 5 ----- src/raw/document_buf.rs | 3 +-- src/raw/owned_bson.rs | 10 +++------- src/raw/serde.rs | 8 +++----- src/raw/test/append.rs | 8 +------- src/raw/test/mod.rs | 1 - src/ser/mod.rs | 1 - src/tests/spec/corpus.rs | 2 -- 11 files changed, 22 insertions(+), 59 deletions(-) diff --git a/src/de/raw.rs b/src/de/raw.rs index 82906a8d..073c5197 100644 --- a/src/de/raw.rs +++ b/src/de/raw.rs @@ -648,7 +648,7 @@ impl<'d, 'de> serde::de::Deserializer<'de> for DocumentKeyDeserializer<'d, 'de> } } - fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { @@ -681,7 +681,7 @@ impl<'de> serde::de::Deserializer<'de> for FieldDeserializer { visitor.visit_borrowed_str(self.field_name) } - fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { @@ -1350,7 +1350,7 @@ impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserial } } - fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index c169b44e..b4aea7e9 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -88,8 +88,6 @@ impl RawArrayBuf { /// doc.append("a key", "a value"); /// array.push(doc); /// - /// assert_eq!(array.len(), 3); - /// /// let mut iter = array.iter(); /// /// let value = iter.next().unwrap()?; @@ -109,14 +107,6 @@ impl RawArrayBuf { self.len += 1; } - /// Returns the number of elements in the [`RawArrayBuf`]. - /// - /// To retrieve the number of BSON bytes in the backing buffer, use - /// `.as_bytes().len()`. - pub fn len(&self) -> usize { - self.len - } - pub(crate) fn into_vec(self) -> Vec { self.inner.into_vec() } @@ -220,3 +210,9 @@ impl Serialize for RawArrayBuf { self.as_ref().serialize(serializer) } } + +impl Default for RawArrayBuf { + fn default() -> Self { + Self::new() + } +} diff --git a/src/raw/bson.rs b/src/raw/bson.rs index dada057d..241f6770 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -1,10 +1,7 @@ -use std::{ - convert::{TryFrom, TryInto}, - iter::FromIterator, -}; +use std::convert::{TryFrom, TryInto}; -use serde::{de::Visitor, ser::SerializeStruct, Deserialize, Serialize}; -use serde_bytes::{ByteBuf, Bytes}; +use serde::{ser::SerializeStruct, Deserialize, Serialize}; +use serde_bytes::Bytes; use super::{ owned_bson::OwnedRawBson, @@ -15,22 +12,14 @@ use super::{ Result, }; use crate::{ - de::convert_unsigned_to_signed_raw, extjson, oid::{self, ObjectId}, - raw::{ - OwnedRawJavaScriptCodeWithScope, - RAW_ARRAY_NEWTYPE, - RAW_BSON_NEWTYPE, - RAW_DOCUMENT_NEWTYPE, - }, + raw::{OwnedRawJavaScriptCodeWithScope, RAW_BSON_NEWTYPE}, spec::{BinarySubtype, ElementType}, Binary, Bson, - DateTime, DbPointer, Decimal128, - JavaScriptCodeWithScope, RawArrayBuf, RawDocumentBuf, Regex, @@ -622,7 +611,7 @@ impl<'a> RawJavaScriptCodeWithScope<'a> { } pub(crate) fn len(self) -> i32 { - 4 + 4 + self.code.len() as i32 + 1 + self.scope.len() as i32 + 4 + 4 + self.code.len() as i32 + 1 + self.scope.as_bytes().len() as i32 } } diff --git a/src/raw/document.rs b/src/raw/document.rs index 9293c531..f01e7a35 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -491,11 +491,6 @@ impl RawDocument { pub fn as_bytes(&self) -> &[u8] { &self.data } - - /// The number of bytes in this document. - pub fn len(&self) -> usize { - self.data.len() - } } impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 01719546..9229d6b9 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -1,7 +1,6 @@ use std::{ borrow::{Borrow, Cow}, convert::{TryFrom, TryInto}, - ffi::CString, iter::FromIterator, ops::Deref, }; @@ -14,7 +13,7 @@ use crate::{ serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, RAW_DOCUMENT_NEWTYPE, }, - spec::{BinarySubtype, ElementType}, + spec::BinarySubtype, Document, RawBinary, RawJavaScriptCodeWithScope, diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs index 25211a0b..7b8d533e 100644 --- a/src/raw/owned_bson.rs +++ b/src/raw/owned_bson.rs @@ -1,7 +1,4 @@ -use std::{ - borrow::Borrow, - convert::{TryFrom, TryInto}, -}; +use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; @@ -13,7 +10,6 @@ use crate::{ Bson, DbPointer, Decimal128, - JavaScriptCodeWithScope, RawArray, RawArrayBuf, RawBinary, @@ -277,8 +273,8 @@ impl OwnedRawBson { match self { OwnedRawBson::Double(d) => RawBson::Double(*d), OwnedRawBson::String(s) => RawBson::String(s.as_str()), - OwnedRawBson::Array(a) => RawBson::Array(&a), - OwnedRawBson::Document(d) => RawBson::Document(&d), + OwnedRawBson::Array(a) => RawBson::Array(a), + OwnedRawBson::Document(d) => RawBson::Document(d), OwnedRawBson::Boolean(b) => RawBson::Boolean(*b), OwnedRawBson::Null => RawBson::Null, OwnedRawBson::RegularExpression(re) => RawBson::RegularExpression(RawRegex { diff --git a/src/raw/serde.rs b/src/raw/serde.rs index 2b476ccd..0b74b57d 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -381,12 +381,10 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { } else { Err(serde::de::Error::unknown_field(&key.0, &["$scope"])) } + } else if let Cow::Borrowed(code) = code.0 { + Ok(RawBson::JavaScriptCode(code).into()) } else { - if let Cow::Borrowed(code) = code.0 { - Ok(RawBson::JavaScriptCode(code).into()) - } else { - Ok(OwnedRawBson::JavaScriptCode(code.0.into_owned()).into()) - } + Ok(OwnedRawBson::JavaScriptCode(code.0.into_owned()).into()) } } "$dbPointer" => { diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs index 625a46e9..3e27e88b 100644 --- a/src/raw/test/append.rs +++ b/src/raw/test/append.rs @@ -14,13 +14,7 @@ use crate::{ JavaScriptCodeWithScope, OwnedRawBson, RawArrayBuf, - RawBinary, - RawBson, - RawDbPointer, - RawDocument, RawDocumentBuf, - RawJavaScriptCodeWithScope, - RawRegex, Regex, Timestamp, }; @@ -213,7 +207,7 @@ fn binary() { }; let old = Binary { - bytes: bytes.clone(), + bytes, subtype: BinarySubtype::BinaryOld, }; diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index 77e41ab7..28b0237f 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -10,7 +10,6 @@ use crate::{ Binary, Bson, DateTime, - Document, JavaScriptCodeWithScope, Regex, Timestamp, diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 12b8bbb7..5341c38f 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -37,7 +37,6 @@ use crate::{ de::MAX_BSON_SIZE, spec::BinarySubtype, Binary, - RawJavaScriptCodeWithScope, }; use ::serde::{ser::Error as SerdeError, Serialize}; diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs index a680d64a..09162c7e 100644 --- a/src/tests/spec/corpus.rs +++ b/src/tests/spec/corpus.rs @@ -1,6 +1,5 @@ use std::{ convert::{TryFrom, TryInto}, - iter::FromIterator, marker::PhantomData, str::FromStr, }; @@ -11,7 +10,6 @@ use crate::{ Bson, Document, OwnedRawBson, - RawDocumentBuf, }; use pretty_assertions::assert_eq; use serde::{Deserialize, Deserializer}; From af29b3e1e4e354cd9c8836427f98600daf386cda Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 17:15:01 -0500 Subject: [PATCH 13/21] various cleanup --- src/macros.rs | 177 --------------------------------------- src/raw/array_buf.rs | 14 ++-- src/raw/document_buf.rs | 8 +- src/raw/mod.rs | 2 +- src/raw/owned_bson.rs | 18 +--- src/raw/serde.rs | 14 ++-- src/ser/mod.rs | 2 +- src/tests/spec/corpus.rs | 11 +-- 8 files changed, 27 insertions(+), 219 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index d6355591..b69ca155 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -212,180 +212,3 @@ macro_rules! doc { object }}; } - -// #[macro_export] -// macro_rules! rawbson { -// ////////////////////////////////////////////////////////////////////////// -// // TT muncher for parsing the inside of an array [...]. Produces a vec![...] -// // of the elements. -// // -// // Must be invoked as: bson!(@array [] $($tt)*) -// ////////////////////////////////////////////////////////////////////////// - -// // Finished with trailing comma. -// (@array [$($elems:expr,)*]) => { -// vec![$($elems,)*] -// }; - -// // Finished without trailing comma. -// (@array [$($elems:expr),*]) => { -// vec![$($elems),*] -// }; - -// // Next element is `null`. -// (@array [$($elems:expr,)*] null $($rest:tt)*) => { -// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!(null)] $($rest)*) -// }; - -// // Next element is an array. -// (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { -// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!([$($array)*])] $($rest)*) -// }; - -// // Next element is a map. -// (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { -// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!({$($map)*})] $($rest)*) -// }; - -// // Next element is an expression followed by comma. -// (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { -// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($next),] $($rest)*) -// }; - -// // Last element is an expression with no trailing comma. -// (@array [$($elems:expr,)*] $last:expr) => { -// $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($last)]) -// }; - -// // Comma after the most recent element. -// (@array [$($elems:expr),*] , $($rest:tt)*) => { -// $crate::rawbson!(@array [$($elems,)*] $($rest)*) -// }; - -// ////////////////////////////////////////////////////////////////////////// -// // TT muncher for parsing the inside of an object {...}. Each entry is -// // inserted into the given map variable. -// // -// // Must be invoked as: bson!(@object $map () ($($tt)*) ($($tt)*)) -// // -// // We require two copies of the input tokens so that we can match on one -// // copy and trigger errors on the other copy. -// ////////////////////////////////////////////////////////////////////////// - -// // Finished. -// (@object $object:ident () () ()) => {}; - -// // Insert the current entry followed by trailing comma. -// (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { -// $object.append(($($key)+), $value); -// $crate::rawbson!(@object $object () ($($rest)*) ($($rest)*)); -// }; - -// // Insert the last entry without trailing comma. -// (@object $object:ident [$($key:tt)+] ($value:expr)) => { -// $object.append(($($key)+), $value); -// }; - -// // // Next value is `null`. -// // (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { -// // $crate::bson!(@object $object [$($key)+] ($crate::bson!(null)) $($rest)*); -// // }; - -// // Next value is an array. -// (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { -// $crate::bson!(@object $object [$($key)+] ($crate::bson!([$($array)*])) $($rest)*); -// }; - -// // Next value is a map. -// (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { -// $crate::bson!(@object $object [$($key)+] ($crate::bson!({$($map)*})) $($rest)*); -// }; - -// // Next value is an expression followed by comma. -// (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { -// $crate::bson!(@object $object [$($key)+] ($crate::bson!($value)) , $($rest)*); -// }; - -// // Last value is an expression with no trailing comma. -// (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { -// $crate::bson!(@object $object [$($key)+] ($crate::bson!($value))); -// }; - -// // Missing value for last entry. Trigger a reasonable error message. -// (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { -// // "unexpected end of macro invocation" -// $crate::bson!(); -// }; - -// // Missing key-value separator and value for last entry. -// // Trigger a reasonable error message. -// (@object $object:ident ($($key:tt)+) () $copy:tt) => { -// // "unexpected end of macro invocation" -// $crate::bson!(); -// }; - -// // Misplaced key-value separator. Trigger a reasonable error message. -// (@object $object:ident () (: $($rest:tt)*) ($kv_separator:tt $($copy:tt)*)) => { -// // Takes no arguments so "no rules expected the token `:`". -// unimplemented!($kv_separator); -// }; - -// // Found a comma inside a key. Trigger a reasonable error message. -// (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { -// // Takes no arguments so "no rules expected the token `,`". -// unimplemented!($comma); -// }; - -// // Key is fully parenthesized. This avoids clippy double_parens false -// // positives because the parenthesization may be necessary here. -// (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { -// $crate::bson!(@object $object ($key) (: $($rest)*) (: $($rest)*)); -// }; - -// // Munch a token into the current key. -// (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { -// $crate::bson!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); -// }; - -// ////////////////////////////////////////////////////////////////////////// -// // The main implementation. -// // -// // Must be invoked as: bson!($($bson)+) -// ////////////////////////////////////////////////////////////////////////// - -// (null) => { -// $crate::Bson::Null -// }; - -// ([]) => { -// $crate::Bson::Array(vec![]) -// }; - -// ([ $($tt:tt)+ ]) => { -// $crate::Bson::Array($crate::bson!(@array [] $($tt)+)) -// }; - -// ({}) => { -// $crate::RawBson::Document($crate::rawdoc!{}) -// }; - -// ({$($tt:tt)+}) => { -// $crate::RawBson::Document($crate::rawdoc!{$($tt)+}) -// }; - -// // Any Into type. -// // Must be below every other rule. -// ($other:expr) => { -// $crate::RawBson::from($other) -// }; -// } - -// #[macro_export] -// macro_rules! rawdoc { -// () => {{ $crate::RawDocumentBuf::empty() }}; -// ( $($tt:tt)+ ) => {{ -// let mut object = $crate::RawDocumentBuf::empty(); -// $crate::rawbson!(@object object () ($($tt)+) ($($tt)+)); -// object -// }}; -// } diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index b4aea7e9..204afc6e 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -28,13 +28,13 @@ use super::{owned_bson::OwnedRawBson, RawArrayIter}; /// the original document without making any additional allocations. /// ``` /// # use bson::raw::Error; -/// use bson::raw::RawDocumentBuf; +/// use bson::raw::RawArrayBuf; /// /// let mut array = RawArrayBuf::new(); -/// array.append("a string"); -/// array.append(12_i32); +/// array.push("a string"); +/// array.push(12_i32); /// -/// let mut iter = array.iter(); +/// let mut iter = array.into_iter(); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_str(), Some("a string")); @@ -86,9 +86,9 @@ impl RawArrayBuf { /// /// let mut doc = RawDocumentBuf::new(); /// doc.append("a key", "a value"); - /// array.push(doc); + /// array.push(doc.clone()); /// - /// let mut iter = array.iter(); + /// let mut iter = array.into_iter(); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_str(), Some("a string")); @@ -97,7 +97,7 @@ impl RawArrayBuf { /// assert_eq!(value.as_i32(), Some(12)); /// /// let value = iter.next().unwrap()?; - /// assert_eq!(value.as_document(), Some(&doc)); + /// assert_eq!(value.as_document(), Some(doc.as_ref())); /// /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 9229d6b9..63a7243f 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -35,7 +35,7 @@ use super::{owned_bson::OwnedRawBson, Error, ErrorKind, Iter, RawBson, RawDocume /// # use bson::raw::Error; /// use bson::raw::RawDocumentBuf; /// -/// let doc = RawDocumentBuf::new(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; +/// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; /// let mut iter = doc.iter(); /// let (key, value) = iter.next().unwrap()?; /// assert_eq!(key, "hi"); @@ -53,7 +53,7 @@ use super::{owned_bson::OwnedRawBson, Error, ErrorKind, Iter, RawBson, RawDocume /// ``` /// use bson::raw::RawDocumentBuf; /// -/// let doc = RawDocumentBuf::new(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; +/// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; /// assert_eq!(doc.get_str("hi")?, "y'all"); /// # Ok::<(), Box>(()) /// ``` @@ -168,7 +168,7 @@ impl RawDocumentBuf { /// /// ``` /// # use bson::raw::Error; - /// use bson::raw::RawDocumentBuf; + /// use bson::{doc, raw::RawDocumentBuf}; /// /// let mut doc = RawDocumentBuf::new(); /// doc.append("a string", "some string"); @@ -176,7 +176,7 @@ impl RawDocumentBuf { /// /// let mut subdoc = RawDocumentBuf::new(); /// subdoc.append("a key", true); - /// doc.push("a document", subdoc); + /// doc.append("a document", subdoc); /// /// let expected = doc! { /// "a string": "some string", diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 5e066c18..d9b78d41 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -23,7 +23,7 @@ //! }; //! //! // See http://bsonspec.org/spec.html for details on the binary encoding of BSON. -//! let doc = RawDocumentBuf::new(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; +//! let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; //! let elem = doc.get("hi")?.unwrap(); //! //! assert_eq!( diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs index 7b8d533e..d0572126 100644 --- a/src/raw/owned_bson.rs +++ b/src/raw/owned_bson.rs @@ -437,31 +437,19 @@ impl<'a> TryFrom for Bson { OwnedRawBson::Double(d) => Bson::Double(d), OwnedRawBson::String(s) => Bson::String(s), OwnedRawBson::Document(rawdoc) => Bson::Document(rawdoc.as_ref().try_into()?), - OwnedRawBson::Array(rawarray) => { - let mut items = Vec::new(); - for v in rawarray.into_iter() { - let bson: Bson = v?.try_into()?; - items.push(bson); - } - Bson::Array(items) - } + OwnedRawBson::Array(rawarray) => Bson::Array(rawarray.as_ref().try_into()?), OwnedRawBson::Binary(rawbson) => Bson::Binary(rawbson), OwnedRawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), OwnedRawBson::Boolean(rawbson) => Bson::Boolean(rawbson), OwnedRawBson::DateTime(rawbson) => Bson::DateTime(rawbson), OwnedRawBson::Null => Bson::Null, - OwnedRawBson::RegularExpression(rawregex) => { - Bson::RegularExpression(crate::Regex::new(rawregex.pattern, rawregex.options)) - } + OwnedRawBson::RegularExpression(rawregex) => Bson::RegularExpression(rawregex), OwnedRawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson), OwnedRawBson::Int32(rawbson) => Bson::Int32(rawbson), OwnedRawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), OwnedRawBson::Int64(rawbson) => Bson::Int64(rawbson), OwnedRawBson::Undefined => Bson::Undefined, - OwnedRawBson::DbPointer(rawbson) => Bson::DbPointer(DbPointer { - namespace: rawbson.namespace, - id: rawbson.id, - }), + OwnedRawBson::DbPointer(rawbson) => Bson::DbPointer(rawbson), OwnedRawBson::Symbol(rawbson) => Bson::Symbol(rawbson), OwnedRawBson::JavaScriptCodeWithScope(rawbson) => { Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope { diff --git a/src/raw/serde.rs b/src/raw/serde.rs index 0b74b57d..320c9685 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -28,6 +28,10 @@ use crate::{ use super::{owned_bson::OwnedRawBson, RAW_BSON_NEWTYPE}; +/// A raw BSON value that may either be borrowed or owned. +/// +/// This is used to consolidate the `Serialize` and `Deserialize` implementations for +/// `RawBson` and `OwnedRawBson`. pub(crate) enum OwnedOrBorrowedRawBson<'a> { Owned(OwnedRawBson), Borrowed(RawBson<'a>), @@ -228,6 +232,9 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { where A: serde::de::MapAccess<'de>, { + /// Helper function used to build up the rest of a document once we determine that + /// the map being visited isn't the serde data model version of a BSON type and is + /// in fact a regular map. fn build_doc<'de, A>( first_key: &str, mut map: A, @@ -246,17 +253,10 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { Ok(OwnedRawBson::Document(doc).into()) } - println!("deserializing cow"); let k = match map.next_key::()? { Some(k) => k, None => return Ok(OwnedRawBson::Document(RawDocumentBuf::new()).into()), }; - println!("deserialized {}", k.0); - - match k.0 { - Cow::Borrowed(_) => println!("borrowed"), - _ => println!("not borrowed"), - }; match k.0.as_ref() { "$oid" => { diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 5341c38f..e133d952 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -47,7 +47,7 @@ fn write_string(writer: &mut W, s: &str) -> Result<()> { Ok(()) } -pub(crate) fn write_cstring(writer: &mut W, s: &str) -> Result<()> { +fn write_cstring(writer: &mut W, s: &str) -> Result<()> { if s.contains('\0') { return Err(Error::InvalidCString(s.into())); } diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs index 09162c7e..64298f82 100644 --- a/src/tests/spec/corpus.rs +++ b/src/tests/spec/corpus.rs @@ -1,5 +1,6 @@ use std::{ convert::{TryFrom, TryInto}, + iter::FromIterator, marker::PhantomData, str::FromStr, }; @@ -10,6 +11,7 @@ use crate::{ Bson, Document, OwnedRawBson, + RawDocumentBuf, }; use pretty_assertions::assert_eq; use serde::{Deserialize, Deserializer}; @@ -189,11 +191,8 @@ fn run_test(test: TestFile) { let owned_raw_bson_field = deserializer_raw .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) .expect(&description); - // convert to an owned Bson and put into a Document - let bson: Bson = owned_raw_bson_field.try_into().expect(&description); - let from_raw_owned_raw_doc = doc! { - test_key: bson - }; + let from_slice_owned_vec = + RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_vec(); // deserialize the field from raw Bytes into a Bson let mut deserializer_value = @@ -222,8 +221,6 @@ fn run_test(test: TestFile) { let from_slice_value_vec = crate::to_vec(&from_slice_value_doc).expect(&description); let from_bson_value_vec = crate::to_vec(&from_value_value_doc).expect(&description); - let from_slice_owned_vec = - crate::to_vec(&from_raw_owned_raw_doc).expect(&description); assert_eq!(from_raw_vec, canonical_bson, "{}", description); assert_eq!(from_slice_value_vec, canonical_bson, "{}", description); From ed680efda2ac6f744b65c3138f5cbd69f93d7078 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 17:26:33 -0500 Subject: [PATCH 14/21] further consolidate deserialization logic --- src/raw/document.rs | 29 +++----------- src/raw/document_buf.rs | 41 ++++++-------------- src/raw/serde.rs | 86 +++++++++++++++++++++++++++++++---------- 3 files changed, 83 insertions(+), 73 deletions(-) diff --git a/src/raw/document.rs b/src/raw/document.rs index f01e7a35..5e70dbe3 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -6,12 +6,7 @@ use std::{ use serde::{ser::SerializeMap, Deserialize, Serialize}; use crate::{ - raw::{ - error::ErrorKind, - serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - RAW_DOCUMENT_NEWTYPE, - }, - spec::BinarySubtype, + raw::{error::ErrorKind, serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE}, DateTime, Timestamp, }; @@ -498,23 +493,11 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { where D: serde::Deserializer<'de>, { - match deserializer - .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? - { - OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(d), - - // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize - // from them here too. For BSON, the deserializier will return an error if it - // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) - if b.subtype == BinarySubtype::Generic => - { - RawDocument::new(b.bytes).map_err(serde::de::Error::custom) - } - - o => Err(serde::de::Error::custom(format!( - "expected raw document reference, instead got {:?}", - o + match OwnedOrBorrowedRawDocument::deserialize(deserializer)? { + OwnedOrBorrowedRawDocument::Borrowed(b) => Ok(b), + OwnedOrBorrowedRawDocument::Owned(d) => Err(serde::de::Error::custom(format!( + "expected borrowed raw document, instead got owned {:?}", + d ))), } } diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 63a7243f..886f723d 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -9,17 +9,22 @@ use serde::{Deserialize, Serialize}; use crate::{ de::MIN_BSON_DOCUMENT_SIZE, - raw::{ - serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - RAW_DOCUMENT_NEWTYPE, - }, spec::BinarySubtype, Document, RawBinary, RawJavaScriptCodeWithScope, }; -use super::{owned_bson::OwnedRawBson, Error, ErrorKind, Iter, RawBson, RawDocument, Result}; +use super::{ + owned_bson::OwnedRawBson, + serde::OwnedOrBorrowedRawDocument, + Error, + ErrorKind, + Iter, + RawBson, + RawDocument, + Result, +}; /// An owned BSON document (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes. /// This can be created from a `Vec` or a [`crate::Document`]. @@ -316,31 +321,7 @@ impl<'de> Deserialize<'de> for RawDocumentBuf { where D: serde::Deserializer<'de>, { - match deserializer - .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? - { - OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(d.to_owned()), - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(d)) => Ok(d), - - // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize - // from them here too. For BSON, the deserializier will return an error if it - // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) - if b.subtype == BinarySubtype::Generic => - { - RawDocumentBuf::from_bytes(b.bytes.to_vec()).map_err(serde::de::Error::custom) - } - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) - if b.subtype == BinarySubtype::Generic => - { - RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom) - } - - o => Err(serde::de::Error::custom(format!( - "expected raw document, instead got {:?}", - o - ))), - } + Ok(OwnedOrBorrowedRawDocument::deserialize(deserializer)?.into_owned()) } } diff --git a/src/raw/serde.rs b/src/raw/serde.rs index 320c9685..c09e13aa 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -70,6 +70,57 @@ impl<'a> From for OwnedOrBorrowedRawBson<'a> { #[derive(Debug, Deserialize)] struct CowStr<'a>(#[serde(borrow)] Cow<'a, str>); +pub(crate) enum OwnedOrBorrowedRawDocument<'a> { + Owned(RawDocumentBuf), + Borrowed(&'a RawDocument), +} + +impl<'a> OwnedOrBorrowedRawDocument<'a> { + pub(crate) fn into_owned(self) -> RawDocumentBuf { + match self { + Self::Owned(o) => o, + Self::Borrowed(b) => b.to_owned(), + } + } +} + +impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + match deserializer + .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(Self::Borrowed(d)), + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(d)) => Ok(Self::Owned(d)), + + // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize + // from them here too. For BSON, the deserializier will return an error if it + // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { + Ok(Self::Borrowed( + RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?, + )) + } + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { + Ok(Self::Owned( + RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?, + )) + } + + o => Err(serde::de::Error::custom(format!( + "expected raw document, instead got {:?}", + o + ))), + } + } +} + #[derive(Debug, Deserialize)] struct CowRawDocument<'a>(#[serde(borrow)] Cow<'a, RawDocument>); @@ -354,29 +405,24 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let code = map.next_value::()?; if let Some(key) = map.next_key::()? { if key.0.as_ref() == "$scope" { - let scope = map.next_value::()?; + let scope = map.next_value::()?; match (code.0, scope) { - ( - Cow::Borrowed(code), - OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(scope)), - ) => Ok( - RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { - code, - scope, - }) - .into(), - ), - ( - Cow::Owned(code), - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(scope)), - ) => Ok(OwnedRawBson::JavaScriptCodeWithScope( - OwnedRawJavaScriptCodeWithScope { code, scope }, + (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => { + Ok( + RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { + code, + scope, + }) + .into(), + ) + } + (code, scope) => Ok(OwnedRawBson::JavaScriptCodeWithScope( + OwnedRawJavaScriptCodeWithScope { + code: code.into_owned(), + scope: scope.into_owned(), + }, ) .into()), - (code, scope) => Err(serde::de::Error::custom(format!( - "invalid code_w_scope: code: {:?}, scope: {:?}", - code, scope - ))), } } else { Err(serde::de::Error::unknown_field(&key.0, &["$scope"])) From 9f33205e33663e30affdc742ab36d717adce86f3 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 17:59:17 -0500 Subject: [PATCH 15/21] consolidate array deserialization --- src/raw/array.rs | 26 +++++++------------- src/raw/array_buf.rs | 37 +++-------------------------- src/raw/serde.rs | 56 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 54 deletions(-) diff --git a/src/raw/array.rs b/src/raw/array.rs index 7deb5c5d..58aa138b 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -4,6 +4,7 @@ use serde::{ser::SerializeSeq, Deserialize, Serialize}; use super::{ error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, + serde::OwnedOrBorrowedRawArray, Error, Iter, RawBinary, @@ -14,11 +15,8 @@ use super::{ }; use crate::{ oid::ObjectId, - raw::{ - serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - RAW_ARRAY_NEWTYPE, - }, - spec::{BinarySubtype, ElementType}, + raw::RAW_ARRAY_NEWTYPE, + spec::ElementType, Bson, DateTime, RawArrayBuf, @@ -280,19 +278,11 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray { where D: serde::Deserializer<'de>, { - match deserializer - .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? - { - OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(d), - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) - if b.subtype == BinarySubtype::Generic => - { - let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; - Ok(RawArray::from_doc(doc)) - } - b => Err(serde::de::Error::custom(format!( - "expected raw array reference, instead got {:?}", - b + match OwnedOrBorrowedRawArray::deserialize(deserializer)? { + OwnedOrBorrowedRawArray::Borrowed(b) => Ok(b), + o => Err(serde::de::Error::custom(format!( + "expected borrowed raw array, instead got owned {:?}", + o ))), } } diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index 204afc6e..fa820def 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -6,19 +6,9 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{ - raw::{ - serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - RAW_ARRAY_NEWTYPE, - }, - spec::BinarySubtype, - RawArray, - RawBson, - RawDocument, - RawDocumentBuf, -}; +use crate::{RawArray, RawBson, RawDocumentBuf}; -use super::{owned_bson::OwnedRawBson, RawArrayIter}; +use super::{owned_bson::OwnedRawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter}; /// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON /// bytes. This type can be used to construct owned array values, which can be used to append to @@ -177,28 +167,7 @@ impl<'de> Deserialize<'de> for RawArrayBuf { where D: serde::Deserializer<'de>, { - match deserializer - .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? - { - OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(d.to_owned()), - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) - if b.subtype == BinarySubtype::Generic => - { - let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; - Ok(RawArray::from_doc(doc).to_owned()) - } - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Array(d)) => Ok(d), - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) - if b.subtype == BinarySubtype::Generic => - { - let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?; - Ok(RawArrayBuf::from_raw_document_buf(doc)) - } - b => Err(serde::de::Error::custom(format!( - "expected raw BSON array, instead got {:?}", - b - ))), - } + Ok(OwnedOrBorrowedRawArray::deserialize(deserializer)?.into_owned()) } } diff --git a/src/raw/serde.rs b/src/raw/serde.rs index c09e13aa..b6ae1dc7 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -67,9 +67,13 @@ impl<'a> From for OwnedOrBorrowedRawBson<'a> { } } +/// Wrapper around a `Cow` to enable borrowed deserialization. +/// The default `Deserialize` impl for `Cow` always uses the owned version. #[derive(Debug, Deserialize)] struct CowStr<'a>(#[serde(borrow)] Cow<'a, str>); +/// Wrapper type that can deserialize either an owned or a borrowed raw BSON document. +#[derive(Debug)] pub(crate) enum OwnedOrBorrowedRawDocument<'a> { Owned(RawDocumentBuf), Borrowed(&'a RawDocument), @@ -121,8 +125,56 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> { } } -#[derive(Debug, Deserialize)] -struct CowRawDocument<'a>(#[serde(borrow)] Cow<'a, RawDocument>); +/// Wrapper type that can deserialize either an owned or a borrowed raw BSON array. +#[derive(Debug)] +pub(crate) enum OwnedOrBorrowedRawArray<'a> { + Owned(RawArrayBuf), + Borrowed(&'a RawArray), +} + +impl<'a> OwnedOrBorrowedRawArray<'a> { + pub(crate) fn into_owned(self) -> RawArrayBuf { + match self { + Self::Owned(o) => o, + Self::Borrowed(b) => b.to_owned(), + } + } +} + +impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + match deserializer + .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(Self::Borrowed(d)), + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Array(d)) => Ok(Self::Owned(d)), + + // For non-BSON formats, RawArray gets serialized as bytes, so we need to deserialize + // from them here too. For BSON, the deserializier will return an error if it + // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. + OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { + let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; + Ok(Self::Borrowed(RawArray::from_doc(doc))) + } + OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) + if b.subtype == BinarySubtype::Generic => + { + let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?; + Ok(Self::Owned(RawArrayBuf::from_raw_document_buf(doc))) + } + + o => Err(serde::de::Error::custom(format!( + "expected raw array, instead got {:?}", + o + ))), + } + } +} /// A visitor used to deserialize types backed by raw BSON. pub(crate) struct OwnedOrBorrowedRawBsonVisitor; From b0cbaef850d6ab9ac196bfc8ea9c89f176d7492d Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 18:13:19 -0500 Subject: [PATCH 16/21] standardize on from/into_bytes --- serde-tests/test.rs | 4 ++-- src/de/raw.rs | 2 +- src/raw/array_buf.rs | 2 +- src/raw/document.rs | 2 +- src/raw/document_buf.rs | 8 ++++---- src/raw/iter.rs | 4 ++-- src/raw/serde.rs | 8 ++++---- src/raw/test/mod.rs | 10 +++++----- src/ser/raw/value_serializer.rs | 2 +- src/tests/spec/corpus.rs | 8 ++++---- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/serde-tests/test.rs b/serde-tests/test.rs index ee88df15..07950627 100644 --- a/serde-tests/test.rs +++ b/serde-tests/test.rs @@ -1308,7 +1308,7 @@ fn hint_cleared() { let bytes = bson::to_vec(&doc_value).unwrap(); - let doc = RawDocument::new(&bytes).unwrap(); + let doc = RawDocument::from_bytes(&bytes).unwrap(); let binary = doc.get_binary("binary").unwrap(); let f = Foo { doc, binary }; @@ -1328,7 +1328,7 @@ fn non_human_readable() { }; let doc_bytes = bson::to_vec(&doc! { "a": "b", "array": [1, 2, 3] }).unwrap(); - let doc = RawDocument::new(doc_bytes.as_slice()).unwrap(); + let doc = RawDocument::from_bytes(doc_bytes.as_slice()).unwrap(); let arr = doc.get_array("array").unwrap(); let oid = ObjectId::new(); let uuid = Uuid::new(); diff --git a/src/de/raw.rs b/src/de/raw.rs index 073c5197..d8e96220 100644 --- a/src/de/raw.rs +++ b/src/de/raw.rs @@ -163,7 +163,7 @@ impl<'de> Deserializer<'de> { let mut len = self.bytes.slice(4)?; let len = read_i32(&mut len)?; - let doc = RawDocument::new(self.bytes.read_slice(len as usize)?) + let doc = RawDocument::from_bytes(self.bytes.read_slice(len as usize)?) .map_err(Error::custom)?; let access = if is_array { diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index fa820def..ed8b473b 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -98,7 +98,7 @@ impl RawArrayBuf { } pub(crate) fn into_vec(self) -> Vec { - self.inner.into_vec() + self.inner.into_bytes() } } diff --git a/src/raw/document.rs b/src/raw/document.rs index 5e70dbe3..03ae048e 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -88,7 +88,7 @@ impl RawDocument { /// let doc = RawDocument::new(b"\x05\0\0\0\0")?; /// # Ok::<(), bson::raw::Error>(()) /// ``` - pub fn new + ?Sized>(data: &D) -> Result<&RawDocument> { + pub fn from_bytes + ?Sized>(data: &D) -> Result<&RawDocument> { let data = data.as_ref(); if data.len() < 5 { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 886f723d..b64e6425 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -93,7 +93,7 @@ impl RawDocumentBuf { /// # Ok::<(), Error>(()) /// ``` pub fn from_bytes(data: Vec) -> Result { - let _ = RawDocument::new(data.as_slice())?; + let _ = RawDocument::from_bytes(data.as_slice())?; Ok(Self { data }) } @@ -159,7 +159,7 @@ impl RawDocumentBuf { /// assert_eq!(doc.into_vec(), b"\x05\x00\x00\x00\x00".to_vec()); /// # Ok::<(), Error>(()) /// ``` - pub fn into_vec(self) -> Vec { + pub fn into_bytes(self) -> Vec { self.data } @@ -225,7 +225,7 @@ impl RawDocumentBuf { append_string(self, s); } OwnedRawBson::Document(d) => { - self.data.extend(d.into_vec()); + self.data.extend(d.into_bytes()); } OwnedRawBson::Array(a) => { self.data.extend(a.into_vec()); @@ -278,7 +278,7 @@ impl RawDocumentBuf { .len(); self.data.extend(len.to_le_bytes()); append_string(self, code_w_scope.code); - self.data.extend(code_w_scope.scope.into_vec()); + self.data.extend(code_w_scope.scope.into_bytes()); } OwnedRawBson::Timestamp(ts) => { self.data.extend(ts.to_le_i64().to_le_bytes()); diff --git a/src/raw/iter.rs b/src/raw/iter.rs index 2e46da52..8f0708d6 100644 --- a/src/raw/iter.rs +++ b/src/raw/iter.rs @@ -91,7 +91,7 @@ impl<'a> Iter<'a> { }, }); } - RawDocument::new(&self.doc.as_bytes()[starting_at..end]) + RawDocument::from_bytes(&self.doc.as_bytes()[starting_at..end]) } } @@ -263,7 +263,7 @@ impl<'a> Iterator for Iter<'a> { let slice = &&self.doc.as_bytes()[valueoffset..(valueoffset + length)]; let code = read_lenencoded(&slice[4..])?; let scope_start = 4 + 4 + code.len() + 1; - let scope = RawDocument::new(&slice[scope_start..])?; + let scope = RawDocument::from_bytes(&slice[scope_start..])?; ( RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code, diff --git a/src/raw/serde.rs b/src/raw/serde.rs index b6ae1dc7..3439801c 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -106,7 +106,7 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> { if b.subtype == BinarySubtype::Generic => { Ok(Self::Borrowed( - RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?, + RawDocument::from_bytes(b.bytes).map_err(serde::de::Error::custom)?, )) } OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) @@ -158,7 +158,7 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> { OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { - let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?; + let doc = RawDocument::from_bytes(b.bytes).map_err(serde::de::Error::custom)?; Ok(Self::Borrowed(RawArray::from_doc(doc))) } OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) @@ -513,12 +513,12 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { } RAW_DOCUMENT_NEWTYPE => { let bson = map.next_value::<&[u8]>()?; - let doc = RawDocument::new(bson).map_err(serde::de::Error::custom)?; + let doc = RawDocument::from_bytes(bson).map_err(serde::de::Error::custom)?; Ok(RawBson::Document(doc).into()) } RAW_ARRAY_NEWTYPE => { let bson = map.next_value::<&[u8]>()?; - let doc = RawDocument::new(bson).map_err(serde::de::Error::custom)?; + let doc = RawDocument::from_bytes(bson).map_err(serde::de::Error::custom)?; Ok(RawBson::Array(RawArray::from_doc(doc)).into()) } k => build_doc(k, map), diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index 28b0237f..40b64617 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -29,7 +29,7 @@ fn string_from_document() { "that": "second", "something": "else", }); - let rawdoc = RawDocument::new(&docbytes).unwrap(); + let rawdoc = RawDocument::from_bytes(&docbytes).unwrap(); assert_eq!( rawdoc.get("that").unwrap().unwrap().as_str().unwrap(), "second", @@ -44,7 +44,7 @@ fn nested_document() { "i64": 6_i64, }, }); - let rawdoc = RawDocument::new(&docbytes).unwrap(); + let rawdoc = RawDocument::from_bytes(&docbytes).unwrap(); let subdoc = rawdoc .get("outer") .expect("get doc result") @@ -79,7 +79,7 @@ fn iterate() { "peanut butter": "chocolate", "easy as": {"do": 1, "re": 2, "mi": 3}, }); - let rawdoc = RawDocument::new(&docbytes).expect("malformed bson document"); + let rawdoc = RawDocument::from_bytes(&docbytes).expect("malformed bson document"); let mut dociter = rawdoc.into_iter(); let next = dociter.next().expect("no result").expect("invalid bson"); assert_eq!(next.0, "apples"); @@ -116,7 +116,7 @@ fn rawdoc_to_doc() { "end": "END", }); - let rawdoc = RawDocument::new(&docbytes).expect("invalid document"); + let rawdoc = RawDocument::from_bytes(&docbytes).expect("invalid document"); let doc: crate::Document = rawdoc.try_into().expect("invalid bson"); let round_tripped_bytes = crate::to_vec(&doc).expect("serialize should work"); assert_eq!(round_tripped_bytes, docbytes); @@ -440,7 +440,7 @@ fn into_bson_conversion() { "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] }, "boolean": false, }); - let rawbson = RawBson::Document(RawDocument::new(docbytes.as_slice()).unwrap()); + let rawbson = RawBson::Document(RawDocument::from_bytes(docbytes.as_slice()).unwrap()); let b: Bson = rawbson.try_into().expect("invalid bson"); let doc = b.as_document().expect("not a document"); assert_eq!(*doc.get("f64").expect("f64 not found"), Bson::Double(2.5)); diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs index d5c7bca7..be120cc4 100644 --- a/src/ser/raw/value_serializer.rs +++ b/src/ser/raw/value_serializer.rs @@ -310,7 +310,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> { SerializationStep::CodeWithScopeScope { ref code, raw } if raw => { let raw = RawJavaScriptCodeWithScope { code, - scope: RawDocument::new(v).map_err(Error::custom)?, + scope: RawDocument::from_bytes(v).map_err(Error::custom)?, }; write_i32(&mut self.root_serializer.bytes, raw.len())?; write_string(&mut self.root_serializer.bytes, code)?; diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs index 64298f82..0a555226 100644 --- a/src/tests/spec/corpus.rs +++ b/src/tests/spec/corpus.rs @@ -117,7 +117,7 @@ fn run_test(test: TestFile) { crate::to_document(&documentfromreader_cb).expect(&description); let canonical_raw_document = - RawDocument::new(canonical_bson.as_slice()).expect(&description); + RawDocument::from_bytes(canonical_bson.as_slice()).expect(&description); let document_from_raw_document: Document = canonical_raw_document.try_into().expect(&description); @@ -192,7 +192,7 @@ fn run_test(test: TestFile) { .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) .expect(&description); let from_slice_owned_vec = - RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_vec(); + RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_bytes(); // deserialize the field from raw Bytes into a Bson let mut deserializer_value = @@ -343,7 +343,7 @@ fn run_test(test: TestFile) { description, ); - let document_from_raw_document: Document = RawDocument::new(db.as_slice()) + let document_from_raw_document: Document = RawDocument::from_bytes(db.as_slice()) .expect(&description) .try_into() .expect(&description); @@ -533,7 +533,7 @@ fn run_test(test: TestFile) { ); let bson = hex::decode(&decode_error.bson).expect("should decode from hex"); - if let Ok(doc) = RawDocument::new(bson.as_slice()) { + if let Ok(doc) = RawDocument::from_bytes(bson.as_slice()) { Document::try_from(doc).expect_err(description.as_str()); } From fc96e7fb284d7a982789bf473be52474b214efcd Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 18 Nov 2021 18:45:13 -0500 Subject: [PATCH 17/21] fix tests, compile on MSRV --- src/raw/array.rs | 4 ++-- src/raw/document.rs | 8 ++++---- src/raw/document_buf.rs | 28 ++++++++++++++-------------- src/raw/mod.rs | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/raw/array.rs b/src/raw/array.rs index 58aa138b..17af3768 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -43,7 +43,7 @@ use crate::{ /// }; /// let bytes = bson::to_vec(&doc)?; /// -/// let rawdoc = RawDocument::new(bytes.as_slice())?; +/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?; /// let rawarray = rawdoc.get_array("x")?; /// /// for v in rawarray { @@ -66,7 +66,7 @@ use crate::{ /// }; /// let bytes = bson::to_vec(&doc)?; /// -/// let rawdoc = RawDocument::new(bytes.as_slice())?; +/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?; /// let rawarray = rawdoc.get_array("x")?; /// /// assert_eq!(rawarray.get_bool(1)?, true); diff --git a/src/raw/document.rs b/src/raw/document.rs index 03ae048e..b27b7fb8 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -42,7 +42,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document}; /// # use bson::raw::{Error}; /// use bson::raw::RawDocument; /// -/// let doc = RawDocument::new(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?; +/// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?; /// let mut iter = doc.into_iter(); /// let (key, value) = iter.next().unwrap()?; /// assert_eq!(key, "hi"); @@ -59,7 +59,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document}; /// ``` /// use bson::raw::RawDocument; /// -/// let doc = RawDocument::new(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?; +/// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?; /// assert_eq!(doc.get_str("hi")?, "y'all"); /// # Ok::<(), Box>(()) /// ``` @@ -85,7 +85,7 @@ impl RawDocument { /// ``` /// use bson::raw::RawDocument; /// - /// let doc = RawDocument::new(b"\x05\0\0\0\0")?; + /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?; /// # Ok::<(), bson::raw::Error>(()) /// ``` pub fn from_bytes + ?Sized>(data: &D) -> Result<&RawDocument> { @@ -143,7 +143,7 @@ impl RawDocument { /// use bson::raw::{RawDocument, RawDocumentBuf, Error}; /// /// let data = b"\x05\0\0\0\0"; - /// let doc_ref = RawDocument::new(data)?; + /// let doc_ref = RawDocument::from_bytes(data)?; /// let doc: RawDocumentBuf = doc_ref.to_raw_document_buf(); /// # Ok::<(), Error>(()) pub fn to_raw_document_buf(&self) -> RawDocumentBuf { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index b64e6425..48adddae 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -156,7 +156,7 @@ impl RawDocumentBuf { /// use bson::{doc, raw::RawDocumentBuf}; /// /// let doc = RawDocumentBuf::from_document(&doc!{})?; - /// assert_eq!(doc.into_vec(), b"\x05\x00\x00\x00\x00".to_vec()); + /// assert_eq!(doc.into_bytes(), b"\x05\x00\x00\x00\x00".to_vec()); /// # Ok::<(), Error>(()) /// ``` pub fn into_bytes(self) -> Vec { @@ -195,7 +195,7 @@ impl RawDocumentBuf { pub fn append(&mut self, key: impl Into, value: impl Into) { fn append_string(doc: &mut RawDocumentBuf, value: String) { doc.data - .extend(((value.as_bytes().len() + 1) as i32).to_le_bytes()); + .extend(&((value.as_bytes().len() + 1) as i32).to_le_bytes()); doc.data.extend(value.into_bytes()); doc.data.push(0); } @@ -219,7 +219,7 @@ impl RawDocumentBuf { match value { OwnedRawBson::Int32(i) => { - self.data.extend(i.to_le_bytes()); + self.data.extend(&i.to_le_bytes()); } OwnedRawBson::String(s) => { append_string(self, s); @@ -236,10 +236,10 @@ impl RawDocumentBuf { subtype: b.subtype, } .len(); - self.data.extend(len.to_le_bytes()); + self.data.extend(&len.to_le_bytes()); self.data.push(b.subtype.into()); if let BinarySubtype::BinaryOld = b.subtype { - self.data.extend((len - 4).to_le_bytes()) + self.data.extend(&(len - 4).to_le_bytes()) } self.data.extend(b.bytes); } @@ -248,20 +248,20 @@ impl RawDocumentBuf { self.data.push(byte); } OwnedRawBson::DateTime(dt) => { - self.data.extend(dt.timestamp_millis().to_le_bytes()); + self.data.extend(&dt.timestamp_millis().to_le_bytes()); } OwnedRawBson::DbPointer(dbp) => { append_string(self, dbp.namespace); - self.data.extend(dbp.id.bytes()); + self.data.extend(&dbp.id.bytes()); } OwnedRawBson::Decimal128(d) => { - self.data.extend(d.bytes()); + self.data.extend(&d.bytes()); } OwnedRawBson::Double(d) => { - self.data.extend(d.to_le_bytes()); + self.data.extend(&d.to_le_bytes()); } OwnedRawBson::Int64(i) => { - self.data.extend(i.to_le_bytes()); + self.data.extend(&i.to_le_bytes()); } OwnedRawBson::RegularExpression(re) => { append_cstring(self, re.pattern); @@ -276,15 +276,15 @@ impl RawDocumentBuf { scope: &code_w_scope.scope, } .len(); - self.data.extend(len.to_le_bytes()); + self.data.extend(&len.to_le_bytes()); append_string(self, code_w_scope.code); self.data.extend(code_w_scope.scope.into_bytes()); } OwnedRawBson::Timestamp(ts) => { - self.data.extend(ts.to_le_i64().to_le_bytes()); + self.data.extend(&ts.to_le_i64().to_le_bytes()); } OwnedRawBson::ObjectId(oid) => { - self.data.extend(oid.bytes()); + self.data.extend(&oid.bytes()); } OwnedRawBson::Symbol(s) => { append_string(self, s); @@ -300,7 +300,7 @@ impl RawDocumentBuf { self.data.push(0); // update length self.data - .splice(0..4, (self.data.len() as i32).to_le_bytes()); + .splice(0..4, (self.data.len() as i32).to_le_bytes().iter().cloned()); } /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error diff --git a/src/raw/mod.rs b/src/raw/mod.rs index d9b78d41..970da631 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -76,7 +76,7 @@ //! use bson::raw::RawDocument; //! //! let bytes = b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00"; -//! assert_eq!(RawDocument::new(bytes)?.get_str("hi")?, "y'all"); +//! assert_eq!(RawDocument::from_bytes(bytes)?.get_str("hi")?, "y'all"); //! # Ok::<(), Box>(()) //! ``` //! From 6ddebbd24df9b9961fd19da573df8a6d052ea547 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Mon, 22 Nov 2021 13:31:22 -0500 Subject: [PATCH 18/21] fix comment --- src/raw/array_buf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index ed8b473b..a29f2f6a 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -14,7 +14,7 @@ use super::{owned_bson::OwnedRawBson, serde::OwnedOrBorrowedRawArray, RawArrayIt /// bytes. This type can be used to construct owned array values, which can be used to append to /// [`RawDocumentBuf`] or as a field in a `Deserialize` struct. /// -/// Iterating over a [`RawArrayBuf`] yields either an error or a key-value pair that borrows from +/// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`] value that borrows from /// the original document without making any additional allocations. /// ``` /// # use bson::raw::Error; From dd3aa9cdddff25380593ae7705435007b609036f Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Mon, 22 Nov 2021 13:34:04 -0500 Subject: [PATCH 19/21] add `as_document_mut` and `as_array_mut` --- src/raw/owned_bson.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs index d0572126..a1699fa4 100644 --- a/src/raw/owned_bson.rs +++ b/src/raw/owned_bson.rs @@ -131,6 +131,15 @@ impl OwnedRawBson { } } + /// Gets a mutable reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the + /// wrapped value isn't a BSON array. + pub fn as_array_mut(&mut self) -> Option<&mut RawArrayBuf> { + match self { + OwnedRawBson::Array(ref mut v) => Some(v), + _ => None, + } + } + /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped /// value isn't a BSON document. pub fn as_document(&self) -> Option<&'_ RawDocument> { @@ -140,6 +149,15 @@ impl OwnedRawBson { } } + /// Gets a mutable reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the + /// wrapped value isn't a BSON document. + pub fn as_document_mut(&mut self) -> Option<&mut RawDocumentBuf> { + match self { + OwnedRawBson::Document(ref mut v) => Some(v), + _ => None, + } + } + /// Gets the wrapped `bool` value or returns `None` if the wrapped value isn't a BSON /// boolean. pub fn as_bool(&self) -> Option { From 9abd6f9a2e282dd392d94b6624d6de675c919373 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Tue, 30 Nov 2021 12:40:15 -0500 Subject: [PATCH 20/21] refactor `RawBson` -> `RawBsonRef`, `OwnedRawBson` -> `RawBson` --- serde-tests/json.rs | 32 +- serde-tests/test.rs | 50 +-- src/bson.rs | 6 +- src/de/mod.rs | 4 +- src/de/raw.rs | 8 +- src/de/serde.rs | 8 +- src/lib.rs | 4 +- src/raw/array.rs | 48 ++- src/raw/array_buf.rs | 10 +- src/raw/bson.rs | 639 +++++++++++------------------ src/raw/bson_ref.rs | 695 ++++++++++++++++++++++++++++++++ src/raw/document.rs | 42 +- src/raw/document_buf.rs | 57 ++- src/raw/iter.rs | 56 +-- src/raw/mod.rs | 18 +- src/raw/owned_bson.rs | 522 ------------------------ src/raw/serde.rs | 133 +++--- src/raw/test/append.rs | 37 +- src/raw/test/mod.rs | 4 +- src/ser/raw/value_serializer.rs | 4 +- src/ser/serde.rs | 6 +- src/tests/spec/corpus.rs | 19 +- 22 files changed, 1203 insertions(+), 1199 deletions(-) create mode 100644 src/raw/bson_ref.rs delete mode 100644 src/raw/owned_bson.rs diff --git a/serde-tests/json.rs b/serde-tests/json.rs index b5b44435..473b3f21 100644 --- a/serde-tests/json.rs +++ b/serde-tests/json.rs @@ -3,7 +3,7 @@ use serde_json::json; use super::AllTypes; -use bson::{doc, Bson, JavaScriptCodeWithScope, OwnedRawBson, RawArrayBuf, RawDocumentBuf}; +use bson::{doc, Bson, JavaScriptCodeWithScope, RawArrayBuf, RawBson, RawDocumentBuf}; use serde::{Deserialize, Serialize}; @@ -63,13 +63,13 @@ fn owned_raw_bson() { struct Foo { doc_buf: RawDocumentBuf, array_buf: RawArrayBuf, - bson_array: OwnedRawBson, - bson_doc: OwnedRawBson, - bson_integer: OwnedRawBson, - bson_string: OwnedRawBson, - bson_bool: OwnedRawBson, - bson_null: OwnedRawBson, - bson_float: OwnedRawBson, + bson_array: RawBson, + bson_doc: RawBson, + bson_integer: RawBson, + bson_string: RawBson, + bson_bool: RawBson, + bson_null: RawBson, + bson_float: RawBson, } let json = json!({ @@ -102,7 +102,7 @@ fn owned_raw_bson() { doc_buf.append("a", "key"); doc_buf.append("number", 12); doc_buf.append("bool", false); - doc_buf.append("nu", OwnedRawBson::Null); + doc_buf.append("nu", RawBson::Null); let mut array_buf = RawArrayBuf::new(); array_buf.push(1); @@ -115,13 +115,13 @@ fn owned_raw_bson() { let expected = Foo { doc_buf, array_buf: array_buf.clone(), - bson_array: OwnedRawBson::Array(array_buf), - bson_doc: OwnedRawBson::Document(bson_doc), - bson_integer: OwnedRawBson::Int32(12), - bson_string: OwnedRawBson::String("String".to_string()), - bson_bool: OwnedRawBson::Boolean(true), - bson_null: OwnedRawBson::Null, - bson_float: OwnedRawBson::Double(123.4), + bson_array: RawBson::Array(array_buf), + bson_doc: RawBson::Document(bson_doc), + bson_integer: RawBson::Int32(12), + bson_string: RawBson::String("String".to_string()), + bson_bool: RawBson::Boolean(true), + bson_null: RawBson::Null, + bson_float: RawBson::Double(123.4), }; let f: Foo = serde_json::from_value(json.clone()).unwrap(); diff --git a/serde-tests/test.rs b/serde-tests/test.rs index 07950627..eeae4500 100644 --- a/serde-tests/test.rs +++ b/serde-tests/test.rs @@ -31,16 +31,16 @@ use bson::{ DeserializerOptions, Document, JavaScriptCodeWithScope, - OwnedRawBson, RawArray, RawArrayBuf, - RawBinary, + RawBinaryRef, RawBson, - RawDbPointer, + RawBsonRef, + RawDbPointerRef, RawDocument, RawDocumentBuf, - RawJavaScriptCodeWithScope, - RawRegex, + RawJavaScriptCodeWithScopeRef, + RawRegexRef, Regex, SerializerOptions, Timestamp, @@ -795,16 +795,16 @@ fn raw_binary() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Foo<'a> { #[serde(borrow)] - generic: RawBinary<'a>, + generic: RawBinaryRef<'a>, #[serde(borrow)] - old: RawBinary<'a>, + old: RawBinaryRef<'a>, #[serde(borrow)] - uuid: RawBinary<'a>, + uuid: RawBinaryRef<'a>, #[serde(borrow)] - other: RawBinary<'a>, + other: RawBinaryRef<'a>, } let bytes = bson::to_vec(&doc! { @@ -832,7 +832,7 @@ fn raw_regex() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Foo<'a> { #[serde(borrow)] - r: RawRegex<'a>, + r: RawRegexRef<'a>, } let bytes = bson::to_vec(&doc! { @@ -851,7 +851,7 @@ fn raw_code_w_scope() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Foo<'a> { #[serde(borrow)] - r: RawJavaScriptCodeWithScope<'a>, + r: RawJavaScriptCodeWithScopeRef<'a>, } let bytes = bson::to_vec(&doc! { @@ -870,7 +870,7 @@ fn raw_db_pointer() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Foo<'a> { #[serde(borrow)] - a: RawDbPointer<'a>, + a: RawDbPointerRef<'a>, } // From the "DBpointer" bson corpus test @@ -1036,18 +1036,18 @@ fn all_raw_types_rmp() { #[derive(Debug, Serialize, Deserialize, PartialEq)] struct AllRawTypes<'a> { #[serde(borrow)] - bson: RawBson<'a>, + bson: RawBsonRef<'a>, #[serde(borrow)] document: &'a RawDocument, #[serde(borrow)] array: &'a RawArray, buf: RawDocumentBuf, #[serde(borrow)] - binary: RawBinary<'a>, + binary: RawBinaryRef<'a>, #[serde(borrow)] - code_w_scope: RawJavaScriptCodeWithScope<'a>, + code_w_scope: RawJavaScriptCodeWithScopeRef<'a>, #[serde(borrow)] - regex: RawRegex<'a>, + regex: RawRegexRef<'a>, } let doc_bytes = bson::to_vec(&doc! { @@ -1247,14 +1247,14 @@ fn owned_raw_types() { let f = Foo { subdoc: RawDocumentBuf::from_iter([ - ("a key", OwnedRawBson::String("a value".to_string())), - ("an objectid", OwnedRawBson::ObjectId(oid)), - ("a date", OwnedRawBson::DateTime(dt)), + ("a key", RawBson::String("a value".to_string())), + ("an objectid", RawBson::ObjectId(oid)), + ("a date", RawBson::DateTime(dt)), ]), array: RawArrayBuf::from_iter([ - OwnedRawBson::String("a string".to_string()), - OwnedRawBson::ObjectId(oid), - OwnedRawBson::DateTime(dt), + RawBson::String("a string".to_string()), + RawBson::ObjectId(oid), + RawBson::DateTime(dt), ]), }; @@ -1294,7 +1294,7 @@ fn hint_cleared() { #[serde(borrow)] doc: &'a RawDocument, #[serde(borrow)] - binary: RawBinary<'a>, + binary: RawBinaryRef<'a>, } let binary_value = Binary { @@ -1322,7 +1322,7 @@ fn hint_cleared() { #[test] fn non_human_readable() { let bytes = vec![1, 2, 3, 4]; - let binary = RawBinary { + let binary = RawBinaryRef { bytes: &bytes, subtype: BinarySubtype::BinaryOld, }; @@ -1336,7 +1336,7 @@ fn non_human_readable() { #[derive(Debug, Deserialize, Serialize)] struct Foo<'a> { #[serde(borrow)] - binary: RawBinary<'a>, + binary: RawBinaryRef<'a>, #[serde(borrow)] doc: &'a RawDocument, #[serde(borrow)] diff --git a/src/bson.rs b/src/bson.rs index f70390e7..d8d7398f 100644 --- a/src/bson.rs +++ b/src/bson.rs @@ -34,7 +34,7 @@ use crate::{ oid::{self, ObjectId}, spec::{BinarySubtype, ElementType}, Decimal128, - RawBinary, + RawBinaryRef, }; /// Possible BSON value types. @@ -1098,8 +1098,8 @@ impl Binary { } } - pub(crate) fn as_raw_binary(&self) -> RawBinary<'_> { - RawBinary { + pub(crate) fn as_raw_binary(&self) -> RawBinaryRef<'_> { + RawBinaryRef { bytes: self.bytes.as_slice(), subtype: self.subtype, } diff --git a/src/de/mod.rs b/src/de/mod.rs index 3a8fef0d..dcb56d18 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -35,7 +35,7 @@ use std::io::Read; use crate::{ bson::{Array, Binary, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp}, oid::{self, ObjectId}, - raw::RawBinary, + raw::RawBinaryRef, ser::write_i32, spec::{self, BinarySubtype}, Decimal128, @@ -307,7 +307,7 @@ impl Binary { } } -impl<'a> RawBinary<'a> { +impl<'a> RawBinaryRef<'a> { pub(crate) fn from_slice_with_len_and_payload( mut bytes: &'a [u8], mut len: i32, diff --git a/src/de/raw.rs b/src/de/raw.rs index d8e96220..e9405f58 100644 --- a/src/de/raw.rs +++ b/src/de/raw.rs @@ -13,7 +13,7 @@ use serde::{ use crate::{ oid::ObjectId, - raw::{RawBinary, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, + raw::{RawBinaryRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::{BinarySubtype, ElementType}, uuid::UUID_NEWTYPE_NAME, Bson, @@ -266,7 +266,7 @@ impl<'de> Deserializer<'de> { visitor.visit_borrowed_bytes(self.bytes.read_slice(len as usize)?) } _ => { - let binary = RawBinary::from_slice_with_len_and_payload( + let binary = RawBinaryRef::from_slice_with_len_and_payload( self.bytes.read_slice(len as usize)?, len, subtype, @@ -1168,13 +1168,13 @@ impl<'de, 'd> serde::de::MapAccess<'de> for BinaryAccess<'d, 'de> { } struct BinaryDeserializer<'a> { - binary: RawBinary<'a>, + binary: RawBinaryRef<'a>, hint: DeserializerHint, stage: BinaryDeserializationStage, } impl<'a> BinaryDeserializer<'a> { - fn new(binary: RawBinary<'a>, hint: DeserializerHint) -> Self { + fn new(binary: RawBinaryRef<'a>, hint: DeserializerHint) -> Self { Self { binary, hint, diff --git a/src/de/serde.rs b/src/de/serde.rs index c6b03c3f..fe5042f5 100644 --- a/src/de/serde.rs +++ b/src/de/serde.rs @@ -25,7 +25,7 @@ use crate::{ datetime::DateTime, document::{Document, IntoIter}, oid::ObjectId, - raw::RawBson, + raw::RawBsonRef, spec::BinarySubtype, uuid::UUID_NEWTYPE_NAME, Decimal128, @@ -548,14 +548,14 @@ where } } -pub(crate) fn convert_unsigned_to_signed_raw<'a, E>(value: u64) -> Result, E> +pub(crate) fn convert_unsigned_to_signed_raw<'a, E>(value: u64) -> Result, E> where E: Error, { let bi = _convert_unsigned(value)?; match bi { - BsonInteger::Int32(i) => Ok(RawBson::Int32(i)), - BsonInteger::Int64(i) => Ok(RawBson::Int64(i)), + BsonInteger::Int32(i) => Ok(RawBsonRef::Int32(i)), + BsonInteger::Int64(i) => Ok(RawBsonRef::Int64(i)), } } diff --git a/src/lib.rs b/src/lib.rs index 16693ddf..8d309e4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -278,8 +278,8 @@ pub use self::{ }, decimal128::Decimal128, raw::{ - OwnedRawBson, RawArray, RawArrayBuf, RawBinary, RawBson, RawDbPointer, RawDocument, - RawDocumentBuf, RawJavaScriptCodeWithScope, RawRegex, + RawBson, RawArray, RawArrayBuf, RawBinaryRef, RawBsonRef, RawDbPointerRef, RawDocument, + RawDocumentBuf, RawJavaScriptCodeWithScopeRef, RawRegexRef, }, ser::{ to_bson, to_bson_with_options, to_document, to_document_with_options, to_vec, Serializer, diff --git a/src/raw/array.rs b/src/raw/array.rs index 17af3768..22c04251 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -7,10 +7,10 @@ use super::{ serde::OwnedOrBorrowedRawArray, Error, Iter, - RawBinary, - RawBson, + RawBinaryRef, + RawBsonRef, RawDocument, - RawRegex, + RawRegexRef, Result, }; use crate::{ @@ -100,7 +100,7 @@ impl RawArray { } /// Gets a reference to the value at the given index. - pub fn get(&self, index: usize) -> Result>> { + pub fn get(&self, index: usize) -> Result>> { self.into_iter().nth(index).transpose() } @@ -108,7 +108,7 @@ impl RawArray { &'a self, index: usize, expected_type: ElementType, - f: impl FnOnce(RawBson<'a>) -> Option, + f: impl FnOnce(RawBsonRef<'a>) -> Option, ) -> ValueAccessResult { let bson = self .get(index) @@ -135,73 +135,77 @@ impl RawArray { /// Gets the BSON double at the given index or returns an error if the value at that index isn't /// a double. pub fn get_f64(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::Double, RawBson::as_f64) + self.get_with(index, ElementType::Double, RawBsonRef::as_f64) } /// Gets a reference to the string at the given index or returns an error if the /// value at that index isn't a string. pub fn get_str(&self, index: usize) -> ValueAccessResult<&str> { - self.get_with(index, ElementType::String, RawBson::as_str) + self.get_with(index, ElementType::String, RawBsonRef::as_str) } /// Gets a reference to the document at the given index or returns an error if the /// value at that index isn't a document. pub fn get_document(&self, index: usize) -> ValueAccessResult<&RawDocument> { - self.get_with(index, ElementType::EmbeddedDocument, RawBson::as_document) + self.get_with( + index, + ElementType::EmbeddedDocument, + RawBsonRef::as_document, + ) } /// Gets a reference to the array at the given index or returns an error if the /// value at that index isn't a array. pub fn get_array(&self, index: usize) -> ValueAccessResult<&RawArray> { - self.get_with(index, ElementType::Array, RawBson::as_array) + self.get_with(index, ElementType::Array, RawBsonRef::as_array) } /// Gets a reference to the BSON binary value at the given index or returns an error if the /// value at that index isn't a binary. - pub fn get_binary(&self, index: usize) -> ValueAccessResult> { - self.get_with(index, ElementType::Binary, RawBson::as_binary) + pub fn get_binary(&self, index: usize) -> ValueAccessResult> { + self.get_with(index, ElementType::Binary, RawBsonRef::as_binary) } /// Gets the ObjectId at the given index or returns an error if the value at that index isn't an /// ObjectId. pub fn get_object_id(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::ObjectId, RawBson::as_object_id) + self.get_with(index, ElementType::ObjectId, RawBsonRef::as_object_id) } /// Gets the boolean at the given index or returns an error if the value at that index isn't a /// boolean. pub fn get_bool(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::Boolean, RawBson::as_bool) + self.get_with(index, ElementType::Boolean, RawBsonRef::as_bool) } /// Gets the DateTime at the given index or returns an error if the value at that index isn't a /// DateTime. pub fn get_datetime(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::DateTime, RawBson::as_datetime) + self.get_with(index, ElementType::DateTime, RawBsonRef::as_datetime) } /// Gets a reference to the BSON regex at the given index or returns an error if the /// value at that index isn't a regex. - pub fn get_regex(&self, index: usize) -> ValueAccessResult> { - self.get_with(index, ElementType::RegularExpression, RawBson::as_regex) + pub fn get_regex(&self, index: usize) -> ValueAccessResult> { + self.get_with(index, ElementType::RegularExpression, RawBsonRef::as_regex) } /// Gets a reference to the BSON timestamp at the given index or returns an error if the /// value at that index isn't a timestamp. pub fn get_timestamp(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::Timestamp, RawBson::as_timestamp) + self.get_with(index, ElementType::Timestamp, RawBsonRef::as_timestamp) } /// Gets the BSON int32 at the given index or returns an error if the value at that index isn't /// a 32-bit integer. pub fn get_i32(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::Int32, RawBson::as_i32) + self.get_with(index, ElementType::Int32, RawBsonRef::as_i32) } /// Gets BSON int64 at the given index or returns an error if the value at that index isn't a /// 64-bit integer. pub fn get_i64(&self, index: usize) -> ValueAccessResult { - self.get_with(index, ElementType::Int64, RawBson::as_i64) + self.get_with(index, ElementType::Int64, RawBsonRef::as_i64) } /// Gets a reference to the raw bytes of the [`RawArray`]. @@ -247,7 +251,7 @@ impl<'a> From<&'a RawArray> for Cow<'a, RawArray> { impl<'a> IntoIterator for &'a RawArray { type IntoIter = RawArrayIter<'a>; - type Item = Result>; + type Item = Result>; fn into_iter(self) -> RawArrayIter<'a> { RawArrayIter { @@ -262,9 +266,9 @@ pub struct RawArrayIter<'a> { } impl<'a> Iterator for RawArrayIter<'a> { - type Item = Result>; + type Item = Result>; - fn next(&mut self) -> Option>> { + fn next(&mut self) -> Option>> { match self.inner.next() { Some(Ok((_, v))) => Some(Ok(v)), Some(Err(e)) => Some(Err(e)), diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs index a29f2f6a..3c389d1f 100644 --- a/src/raw/array_buf.rs +++ b/src/raw/array_buf.rs @@ -6,9 +6,9 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{RawArray, RawBson, RawDocumentBuf}; +use crate::{RawArray, RawBsonRef, RawDocumentBuf}; -use super::{owned_bson::OwnedRawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter}; +use super::{bson::RawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter}; /// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON /// bytes. This type can be used to construct owned array values, which can be used to append to @@ -92,7 +92,7 @@ impl RawArrayBuf { /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` - pub fn push(&mut self, value: impl Into) { + pub fn push(&mut self, value: impl Into) { self.inner.append(self.len.to_string(), value); self.len += 1; } @@ -133,7 +133,7 @@ impl Borrow for RawArrayBuf { impl<'a> IntoIterator for &'a RawArrayBuf { type IntoIter = RawArrayIter<'a>; - type Item = super::Result>; + type Item = super::Result>; fn into_iter(self) -> RawArrayIter<'a> { self.as_ref().into_iter() @@ -152,7 +152,7 @@ impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> { } } -impl> FromIterator for RawArrayBuf { +impl> FromIterator for RawArrayBuf { fn from_iter>(iter: I) -> Self { let mut array_buf = RawArrayBuf::new(); for item in iter { diff --git a/src/raw/bson.rs b/src/raw/bson.rs index 241f6770..abe896d4 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -1,52 +1,55 @@ use std::convert::{TryFrom, TryInto}; -use serde::{ser::SerializeStruct, Deserialize, Serialize}; -use serde_bytes::Bytes; +use serde::{Deserialize, Serialize}; -use super::{ - owned_bson::OwnedRawBson, - serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - Error, - RawArray, - RawDocument, - Result, -}; use crate::{ - extjson, oid::{self, ObjectId}, - raw::{OwnedRawJavaScriptCodeWithScope, RAW_BSON_NEWTYPE}, - spec::{BinarySubtype, ElementType}, + raw::RAW_BSON_NEWTYPE, + spec::ElementType, Binary, Bson, DbPointer, Decimal128, + RawArray, RawArrayBuf, + RawBinaryRef, + RawBsonRef, + RawDbPointerRef, + RawDocument, RawDocumentBuf, + RawJavaScriptCodeWithScopeRef, + RawRegexRef, Regex, Timestamp, }; -/// A BSON value referencing raw bytes stored elsewhere. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum RawBson<'a> { +use super::{ + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + Error, + Result, +}; + +/// A BSON value backed by owned raw BSON bytes. +#[derive(Debug, Clone, PartialEq)] +pub enum RawBson { /// 64-bit binary floating point Double(f64), /// UTF-8 string - String(&'a str), + String(String), /// Array - Array(&'a RawArray), + Array(RawArrayBuf), /// Embedded document - Document(&'a RawDocument), + Document(RawDocumentBuf), /// Boolean value Boolean(bool), /// Null value Null, /// Regular expression - RegularExpression(RawRegex<'a>), + RegularExpression(Regex), /// JavaScript code - JavaScriptCode(&'a str), + JavaScriptCode(String), /// JavaScript code w/ scope - JavaScriptCodeWithScope(RawJavaScriptCodeWithScope<'a>), + JavaScriptCodeWithScope(RawJavaScriptCodeWithScope), /// 32-bit signed integer Int32(i32), /// 64-bit signed integer @@ -54,13 +57,13 @@ pub enum RawBson<'a> { /// Timestamp Timestamp(Timestamp), /// Binary data - Binary(RawBinary<'a>), + Binary(Binary), /// [ObjectId](http://dochub.mongodb.org/core/objectids) ObjectId(oid::ObjectId), /// UTC datetime DateTime(crate::DateTime), /// Symbol (Deprecated) - Symbol(&'a str), + Symbol(String), /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) Decimal128(Decimal128), /// Undefined value (Deprecated) @@ -70,10 +73,10 @@ pub enum RawBson<'a> { /// Min key MinKey, /// DBPointer (Deprecated) - DbPointer(RawDbPointer<'a>), + DbPointer(DbPointer), } -impl<'a> RawBson<'a> { +impl RawBson { /// Get the [`ElementType`] of this value. pub fn element_type(&self) -> ElementType { match *self { @@ -101,521 +104,395 @@ impl<'a> RawBson<'a> { } } - /// Gets the `f64` that's referenced or returns `None` if the referenced value isn't a BSON + /// Gets the wrapped `f64` value or returns `None` if the value isn't a BSON /// double. - pub fn as_f64(self) -> Option { + pub fn as_f64(&self) -> Option { match self { - RawBson::Double(d) => Some(d), + RawBson::Double(d) => Some(*d), _ => None, } } - /// Gets the `&str` that's referenced or returns `None` if the referenced value isn't a BSON - /// String. - pub fn as_str(self) -> Option<&'a str> { + /// Gets a reference to the `String` that's wrapped or returns `None` if the wrapped value isn't + /// a BSON String. + pub fn as_str(&self) -> Option<&'_ str> { match self { RawBson::String(s) => Some(s), _ => None, } } - /// Gets the [`RawArray`] that's referenced or returns `None` if the referenced value - /// isn't a BSON array. - pub fn as_array(self) -> Option<&'a RawArray> { + /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the wrapped + /// value isn't a BSON array. + pub fn as_array(&self) -> Option<&'_ RawArray> { match self { RawBson::Array(v) => Some(v), _ => None, } } - /// Gets the [`RawDocument`] that's referenced or returns `None` if the referenced value - /// isn't a BSON document. - pub fn as_document(self) -> Option<&'a RawDocument> { + /// Gets a mutable reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the + /// wrapped value isn't a BSON array. + pub fn as_array_mut(&mut self) -> Option<&mut RawArrayBuf> { + match self { + RawBson::Array(ref mut v) => Some(v), + _ => None, + } + } + + /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped + /// value isn't a BSON document. + pub fn as_document(&self) -> Option<&'_ RawDocument> { match self { RawBson::Document(v) => Some(v), _ => None, } } - /// Gets the `bool` that's referenced or returns `None` if the referenced value isn't a BSON + /// Gets a mutable reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the + /// wrapped value isn't a BSON document. + pub fn as_document_mut(&mut self) -> Option<&mut RawDocumentBuf> { + match self { + RawBson::Document(ref mut v) => Some(v), + _ => None, + } + } + + /// Gets the wrapped `bool` value or returns `None` if the wrapped value isn't a BSON /// boolean. - pub fn as_bool(self) -> Option { + pub fn as_bool(&self) -> Option { match self { - RawBson::Boolean(v) => Some(v), + RawBson::Boolean(v) => Some(*v), _ => None, } } - /// Gets the `i32` that's referenced or returns `None` if the referenced value isn't a BSON + /// Gets the wrapped `i32` value or returns `None` if the wrapped value isn't a BSON /// Int32. - pub fn as_i32(self) -> Option { + pub fn as_i32(&self) -> Option { match self { - RawBson::Int32(v) => Some(v), + RawBson::Int32(v) => Some(*v), _ => None, } } - /// Gets the `i64` that's referenced or returns `None` if the referenced value isn't a BSON + /// Gets the wrapped `i64` value or returns `None` if the wrapped value isn't a BSON /// Int64. - pub fn as_i64(self) -> Option { + pub fn as_i64(&self) -> Option { match self { - RawBson::Int64(v) => Some(v), + RawBson::Int64(v) => Some(*v), _ => None, } } - /// Gets the [`crate::oid::ObjectId`] that's referenced or returns `None` if the referenced - /// value isn't a BSON ObjectID. - pub fn as_object_id(self) -> Option { + /// Gets the wrapped [`crate::oid::ObjectId`] value or returns `None` if the wrapped value isn't + /// a BSON ObjectID. + pub fn as_object_id(&self) -> Option { match self { - RawBson::ObjectId(v) => Some(v), + RawBson::ObjectId(v) => Some(*v), _ => None, } } - /// Gets the [`RawBinary`] that's referenced or returns `None` if the referenced value isn't a - /// BSON binary. - pub fn as_binary(self) -> Option> { + /// Gets a reference to the [`Binary`] that's wrapped or returns `None` if the wrapped value + /// isn't a BSON binary. + pub fn as_binary(&self) -> Option> { match self { - RawBson::Binary(v) => Some(v), + RawBson::Binary(v) => Some(RawBinaryRef { + bytes: v.bytes.as_slice(), + subtype: v.subtype, + }), _ => None, } } - /// Gets the [`RawRegex`] that's referenced or returns `None` if the referenced value isn't a - /// BSON regular expression. - pub fn as_regex(self) -> Option> { + /// Gets a reference to the [`Regex`] that's wrapped or returns `None` if the wrapped value + /// isn't a BSON regular expression. + pub fn as_regex(&self) -> Option> { match self { - RawBson::RegularExpression(v) => Some(v), + RawBson::RegularExpression(v) => Some(RawRegexRef { + pattern: v.pattern.as_str(), + options: v.options.as_str(), + }), _ => None, } } - /// Gets the [`crate::DateTime`] that's referenced or returns `None` if the referenced value - /// isn't a BSON datetime. - pub fn as_datetime(self) -> Option { + /// Gets the wrapped [`crate::DateTime`] value or returns `None` if the wrapped value isn't a + /// BSON datetime. + pub fn as_datetime(&self) -> Option { match self { - RawBson::DateTime(v) => Some(v), + RawBson::DateTime(v) => Some(*v), _ => None, } } - /// Gets the symbol that's referenced or returns `None` if the referenced value isn't a BSON - /// symbol. - pub fn as_symbol(self) -> Option<&'a str> { + /// Gets a reference to the symbol that's wrapped or returns `None` if the wrapped value isn't a + /// BSON Symbol. + pub fn as_symbol(&self) -> Option<&'_ str> { match self { RawBson::Symbol(v) => Some(v), _ => None, } } - /// Gets the [`crate::Timestamp`] that's referenced or returns `None` if the referenced value - /// isn't a BSON timestamp. - pub fn as_timestamp(self) -> Option { + /// Gets the wrapped [`crate::Timestamp`] value or returns `None` if the wrapped value isn't a + /// BSON datetime. + pub fn as_timestamp(&self) -> Option { match self { - RawBson::Timestamp(timestamp) => Some(timestamp), + RawBson::Timestamp(timestamp) => Some(*timestamp), _ => None, } } - /// Gets the null value that's referenced or returns `None` if the referenced value isn't a BSON - /// null. - pub fn as_null(self) -> Option<()> { + /// Returns `Some(())` if this value is null, otherwise returns `None`. + pub fn as_null(&self) -> Option<()> { match self { RawBson::Null => Some(()), _ => None, } } - /// Gets the [`RawDbPointer`] that's referenced or returns `None` if the referenced value isn't - /// a BSON DB pointer. - pub fn as_db_pointer(self) -> Option> { + /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns `None` if the wrapped + /// value isn't a BSON DbPointer. + pub fn as_db_pointer(&self) -> Option> { match self { - RawBson::DbPointer(d) => Some(d), + RawBson::DbPointer(d) => Some(RawDbPointerRef { + namespace: d.namespace.as_str(), + id: d.id, + }), _ => None, } } - /// Gets the code that's referenced or returns `None` if the referenced value isn't a BSON - /// JavaScript. - pub fn as_javascript(self) -> Option<&'a str> { + /// Gets a reference to the code that's wrapped or returns `None` if the wrapped value isn't a + /// BSON JavaScript code. + pub fn as_javascript(&self) -> Option<&'_ str> { match self { RawBson::JavaScriptCode(s) => Some(s), _ => None, } } - /// Gets the [`RawJavaScriptCodeWithScope`] that's referenced or returns `None` if the - /// referenced value isn't a BSON JavaScript with scope. - pub fn as_javascript_with_scope(self) -> Option> { + /// Gets a reference to the [`RawJavaScriptCodeWithScope`] that's wrapped or returns `None` + /// if the wrapped value isn't a BSON JavaScript code with scope value. + pub fn as_javascript_with_scope(&self) -> Option> { match self { - RawBson::JavaScriptCodeWithScope(s) => Some(s), + RawBson::JavaScriptCodeWithScope(s) => Some(RawJavaScriptCodeWithScopeRef { + code: s.code.as_str(), + scope: &s.scope, + }), _ => None, } } - /// Convert this [`RawBson`] to the equivalent [`OwnedRawBson`]. - pub fn to_owned_raw_bson(self) -> OwnedRawBson { + /// Gets a [`RawBson`] value referencing this owned raw BSON value. + pub fn as_raw_bson(&self) -> RawBsonRef<'_> { match self { - RawBson::Double(d) => OwnedRawBson::Double(d), - RawBson::String(s) => OwnedRawBson::String(s.to_string()), - RawBson::Array(a) => OwnedRawBson::Array(a.to_owned()), - RawBson::Document(d) => OwnedRawBson::Document(d.to_owned()), - RawBson::Boolean(b) => OwnedRawBson::Boolean(b), - RawBson::Null => OwnedRawBson::Null, - RawBson::RegularExpression(re) => { - OwnedRawBson::RegularExpression(Regex::new(re.pattern, re.options)) - } - RawBson::JavaScriptCode(c) => OwnedRawBson::JavaScriptCode(c.to_owned()), - RawBson::JavaScriptCodeWithScope(c_w_s) => { - OwnedRawBson::JavaScriptCodeWithScope(OwnedRawJavaScriptCodeWithScope { - code: c_w_s.code.to_string(), - scope: c_w_s.scope.to_owned(), + RawBson::Double(d) => RawBsonRef::Double(*d), + RawBson::String(s) => RawBsonRef::String(s.as_str()), + RawBson::Array(a) => RawBsonRef::Array(a), + RawBson::Document(d) => RawBsonRef::Document(d), + RawBson::Boolean(b) => RawBsonRef::Boolean(*b), + RawBson::Null => RawBsonRef::Null, + RawBson::RegularExpression(re) => RawBsonRef::RegularExpression(RawRegexRef { + options: re.options.as_str(), + pattern: re.pattern.as_str(), + }), + RawBson::JavaScriptCode(c) => RawBsonRef::JavaScriptCode(c.as_str()), + RawBson::JavaScriptCodeWithScope(code_w_scope) => { + RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { + code: code_w_scope.code.as_str(), + scope: code_w_scope.scope.as_ref(), }) } - RawBson::Int32(i) => OwnedRawBson::Int32(i), - RawBson::Int64(i) => OwnedRawBson::Int64(i), - RawBson::Timestamp(t) => OwnedRawBson::Timestamp(t), - RawBson::Binary(b) => OwnedRawBson::Binary(Binary { - bytes: b.bytes.to_vec(), + RawBson::Int32(i) => RawBsonRef::Int32(*i), + RawBson::Int64(i) => RawBsonRef::Int64(*i), + RawBson::Timestamp(ts) => RawBsonRef::Timestamp(*ts), + RawBson::Binary(b) => RawBsonRef::Binary(RawBinaryRef { + bytes: b.bytes.as_slice(), subtype: b.subtype, }), - RawBson::ObjectId(o) => OwnedRawBson::ObjectId(o), - RawBson::DateTime(dt) => OwnedRawBson::DateTime(dt), - RawBson::Symbol(s) => OwnedRawBson::Symbol(s.to_string()), - RawBson::Decimal128(d) => OwnedRawBson::Decimal128(d), - RawBson::Undefined => OwnedRawBson::Undefined, - RawBson::MaxKey => OwnedRawBson::MaxKey, - RawBson::MinKey => OwnedRawBson::MinKey, - RawBson::DbPointer(d) => OwnedRawBson::DbPointer(DbPointer { - namespace: d.namespace.to_string(), - id: d.id, + RawBson::ObjectId(oid) => RawBsonRef::ObjectId(*oid), + RawBson::DateTime(dt) => RawBsonRef::DateTime(*dt), + RawBson::Symbol(s) => RawBsonRef::Symbol(s.as_str()), + RawBson::Decimal128(d) => RawBsonRef::Decimal128(*d), + RawBson::Undefined => RawBsonRef::Undefined, + RawBson::MaxKey => RawBsonRef::MaxKey, + RawBson::MinKey => RawBsonRef::MinKey, + RawBson::DbPointer(dbp) => RawBsonRef::DbPointer(RawDbPointerRef { + namespace: dbp.namespace.as_str(), + id: dbp.id, }), } } } -impl<'de: 'a, 'a> Deserialize<'de> for RawBson<'a> { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - match deserializer - .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? - { - OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b), - o => Err(serde::de::Error::custom(format!( - "RawBson must be deserialized from borrowed content, instead got {:?}", - o - ))), - } - } -} - -impl<'a> Serialize for RawBson<'a> { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - match self { - RawBson::Double(v) => serializer.serialize_f64(*v), - RawBson::String(v) => serializer.serialize_str(v), - RawBson::Array(v) => v.serialize(serializer), - RawBson::Document(v) => v.serialize(serializer), - RawBson::Boolean(v) => serializer.serialize_bool(*v), - RawBson::Null => serializer.serialize_unit(), - RawBson::Int32(v) => serializer.serialize_i32(*v), - RawBson::Int64(v) => serializer.serialize_i64(*v), - RawBson::ObjectId(oid) => oid.serialize(serializer), - RawBson::DateTime(dt) => dt.serialize(serializer), - RawBson::Binary(b) => b.serialize(serializer), - RawBson::JavaScriptCode(c) => { - let mut state = serializer.serialize_struct("$code", 1)?; - state.serialize_field("$code", c)?; - state.end() - } - RawBson::JavaScriptCodeWithScope(code_w_scope) => code_w_scope.serialize(serializer), - RawBson::DbPointer(dbp) => dbp.serialize(serializer), - RawBson::Symbol(s) => { - let mut state = serializer.serialize_struct("$symbol", 1)?; - state.serialize_field("$symbol", s)?; - state.end() - } - RawBson::RegularExpression(re) => re.serialize(serializer), - RawBson::Timestamp(t) => t.serialize(serializer), - RawBson::Decimal128(d) => d.serialize(serializer), - RawBson::Undefined => { - let mut state = serializer.serialize_struct("$undefined", 1)?; - state.serialize_field("$undefined", &true)?; - state.end() - } - RawBson::MaxKey => { - let mut state = serializer.serialize_struct("$maxKey", 1)?; - state.serialize_field("$maxKey", &1)?; - state.end() - } - RawBson::MinKey => { - let mut state = serializer.serialize_struct("$minKey", 1)?; - state.serialize_field("$minKey", &1)?; - state.end() - } - } - } -} - -impl<'a> TryFrom> for Bson { - type Error = Error; - - fn try_from(rawbson: RawBson<'a>) -> Result { - rawbson.to_owned_raw_bson().try_into() - } -} - -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(i: i32) -> Self { RawBson::Int32(i) } } -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(i: i64) -> Self { RawBson::Int64(i) } } -impl<'a> From<&'a str> for RawBson<'a> { - fn from(s: &'a str) -> Self { +impl From for RawBson { + fn from(s: String) -> Self { RawBson::String(s) } } -impl<'a> From for RawBson<'a> { +impl From<&str> for RawBson { + fn from(s: &str) -> Self { + RawBson::String(s.to_owned()) + } +} + +impl From for RawBson { fn from(f: f64) -> Self { RawBson::Double(f) } } -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(b: bool) -> Self { RawBson::Boolean(b) } } -impl<'a> From<&'a RawDocumentBuf> for RawBson<'a> { - fn from(d: &'a RawDocumentBuf) -> Self { - RawBson::Document(d.as_ref()) - } -} - -impl<'a> From<&'a RawDocument> for RawBson<'a> { - fn from(d: &'a RawDocument) -> Self { +impl From for RawBson { + fn from(d: RawDocumentBuf) -> Self { RawBson::Document(d) } } -impl<'a> From<&'a RawArray> for RawBson<'a> { - fn from(a: &'a RawArray) -> Self { +impl From for RawBson { + fn from(a: RawArrayBuf) -> Self { RawBson::Array(a) } } -impl<'a> From<&'a RawArrayBuf> for RawBson<'a> { - fn from(a: &'a RawArrayBuf) -> Self { - RawBson::Array(a) - } -} - -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(dt: crate::DateTime) -> Self { RawBson::DateTime(dt) } } -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(ts: Timestamp) -> Self { RawBson::Timestamp(ts) } } -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(oid: ObjectId) -> Self { RawBson::ObjectId(oid) } } -impl<'a> From for RawBson<'a> { +impl From for RawBson { fn from(d: Decimal128) -> Self { RawBson::Decimal128(d) } } -/// A BSON binary value referencing raw bytes stored elsewhere. -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct RawBinary<'a> { - /// The subtype of the binary value. - pub subtype: BinarySubtype, - - /// The binary bytes. - pub bytes: &'a [u8], -} - -impl<'a> RawBinary<'a> { - pub(crate) fn len(&self) -> i32 { - match self.subtype { - BinarySubtype::BinaryOld => self.bytes.len() as i32 + 4, - _ => self.bytes.len() as i32, - } - } -} - -impl<'de: 'a, 'a> Deserialize<'de> for RawBinary<'a> { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - match RawBson::deserialize(deserializer)? { - RawBson::Binary(b) => Ok(b), - c => Err(serde::de::Error::custom(format!( - "expected binary, but got {:?} instead", - c - ))), - } - } -} - -impl<'a> Serialize for RawBinary<'a> { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - if let BinarySubtype::Generic = self.subtype { - serializer.serialize_bytes(self.bytes) - } else if !serializer.is_human_readable() { - #[derive(Serialize)] - struct BorrowedBinary<'a> { - bytes: &'a Bytes, - - #[serde(rename = "subType")] - subtype: u8, - } - - let mut state = serializer.serialize_struct("$binary", 1)?; - let body = BorrowedBinary { - bytes: Bytes::new(self.bytes), - subtype: self.subtype.into(), - }; - state.serialize_field("$binary", &body)?; - state.end() - } else { - let mut state = serializer.serialize_struct("$binary", 1)?; - let body = extjson::models::BinaryBody { - base64: base64::encode(self.bytes), - subtype: hex::encode([self.subtype.into()]), - }; - state.serialize_field("$binary", &body)?; - state.end() - } +impl From for RawBson { + fn from(code_w_scope: RawJavaScriptCodeWithScope) -> Self { + RawBson::JavaScriptCodeWithScope(code_w_scope) } } -impl<'a> From> for RawBson<'a> { - fn from(b: RawBinary<'a>) -> Self { +impl From for RawBson { + fn from(b: Binary) -> Self { RawBson::Binary(b) } } -impl<'a> From<&'a Binary> for RawBson<'a> { - fn from(bin: &'a Binary) -> Self { - bin.as_raw_binary().into() +impl From for RawBson { + fn from(re: Regex) -> Self { + RawBson::RegularExpression(re) } } -/// A BSON regex referencing raw bytes stored elsewhere. -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct RawRegex<'a> { - pub(crate) pattern: &'a str, - pub(crate) options: &'a str, -} - -impl<'a> RawRegex<'a> { - /// Gets the pattern portion of the regex. - pub fn pattern(self) -> &'a str { - self.pattern - } - - /// Gets the options portion of the regex. - pub fn options(self) -> &'a str { - self.options +impl From for RawBson { + fn from(d: DbPointer) -> Self { + RawBson::DbPointer(d) } } -impl<'de: 'a, 'a> Deserialize<'de> for RawRegex<'a> { +impl<'de> Deserialize<'de> for RawBson { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { - match RawBson::deserialize(deserializer)? { - RawBson::RegularExpression(b) => Ok(b), - c => Err(serde::de::Error::custom(format!( - "expected Regex, but got {:?} instead", - c - ))), + match deserializer + .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Owned(o) => Ok(o), + OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_raw_bson()), } } } -impl<'a> Serialize for RawRegex<'a> { +impl Serialize for RawBson { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { - #[derive(Serialize)] - struct BorrowedRegexBody<'a> { - pattern: &'a str, - options: &'a str, - } - - let mut state = serializer.serialize_struct("$regularExpression", 1)?; - let body = BorrowedRegexBody { - pattern: self.pattern, - options: self.options, - }; - state.serialize_field("$regularExpression", &body)?; - state.end() - } -} - -impl<'a> From> for RawBson<'a> { - fn from(re: RawRegex<'a>) -> Self { - RawBson::RegularExpression(re) + self.as_raw_bson().serialize(serializer) } } -/// A BSON "code with scope" value referencing raw bytes stored elsewhere. -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct RawJavaScriptCodeWithScope<'a> { - pub(crate) code: &'a str, - - pub(crate) scope: &'a RawDocument, -} +impl<'a> TryFrom for Bson { + type Error = Error; -impl<'a> RawJavaScriptCodeWithScope<'a> { - /// Gets the code in the value. - pub fn code(self) -> &'a str { - self.code + fn try_from(rawbson: RawBson) -> Result { + Ok(match rawbson { + RawBson::Double(d) => Bson::Double(d), + RawBson::String(s) => Bson::String(s), + RawBson::Document(rawdoc) => Bson::Document(rawdoc.as_ref().try_into()?), + RawBson::Array(rawarray) => Bson::Array(rawarray.as_ref().try_into()?), + RawBson::Binary(rawbson) => Bson::Binary(rawbson), + RawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), + RawBson::Boolean(rawbson) => Bson::Boolean(rawbson), + RawBson::DateTime(rawbson) => Bson::DateTime(rawbson), + RawBson::Null => Bson::Null, + RawBson::RegularExpression(rawregex) => Bson::RegularExpression(rawregex), + RawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson), + RawBson::Int32(rawbson) => Bson::Int32(rawbson), + RawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), + RawBson::Int64(rawbson) => Bson::Int64(rawbson), + RawBson::Undefined => Bson::Undefined, + RawBson::DbPointer(rawbson) => Bson::DbPointer(rawbson), + RawBson::Symbol(rawbson) => Bson::Symbol(rawbson), + RawBson::JavaScriptCodeWithScope(rawbson) => { + Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope { + code: rawbson.code, + scope: rawbson.scope.try_into()?, + }) + } + RawBson::Decimal128(rawbson) => Bson::Decimal128(rawbson), + RawBson::MaxKey => Bson::MaxKey, + RawBson::MinKey => Bson::MinKey, + }) } +} - /// Gets the scope in the value. - pub fn scope(self) -> &'a RawDocument { - self.scope - } +/// A BSON "code with scope" value backed by owned raw BSON. +#[derive(Debug, Clone, PartialEq)] +pub struct RawJavaScriptCodeWithScope { + /// The code value. + pub code: String, - pub(crate) fn len(self) -> i32 { - 4 + 4 + self.code.len() as i32 + 1 + self.scope.as_bytes().len() as i32 - } + /// The scope document. + pub scope: RawDocumentBuf, } -impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScope<'a> { +impl<'de> Deserialize<'de> for RawJavaScriptCodeWithScope { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, @@ -630,66 +507,16 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScope<'a> { } } -impl<'a> Serialize for RawJavaScriptCodeWithScope<'a> { +impl Serialize for RawJavaScriptCodeWithScope { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { - let mut state = serializer.serialize_struct("$codeWithScope", 2)?; - state.serialize_field("$code", &self.code)?; - state.serialize_field("$scope", &self.scope)?; - state.end() - } -} - -impl<'a> From> for RawBson<'a> { - fn from(code_w_scope: RawJavaScriptCodeWithScope<'a>) -> Self { - RawBson::JavaScriptCodeWithScope(code_w_scope) - } -} - -/// A BSON DB pointer value referencing raw bytes stored elesewhere. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct RawDbPointer<'a> { - pub(crate) namespace: &'a str, - pub(crate) id: ObjectId, -} - -impl<'de: 'a, 'a> Deserialize<'de> for RawDbPointer<'a> { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - match RawBson::deserialize(deserializer)? { - RawBson::DbPointer(b) => Ok(b), - c => Err(serde::de::Error::custom(format!( - "expected DbPointer, but got {:?} instead", - c - ))), - } - } -} - -impl<'a> Serialize for RawDbPointer<'a> { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - #[derive(Serialize)] - struct BorrowedDbPointerBody<'a> { - #[serde(rename = "$ref")] - ref_ns: &'a str, - - #[serde(rename = "$id")] - id: ObjectId, - } - - let mut state = serializer.serialize_struct("$dbPointer", 1)?; - let body = BorrowedDbPointerBody { - ref_ns: self.namespace, - id: self.id, + let raw = RawJavaScriptCodeWithScopeRef { + code: self.code.as_str(), + scope: self.scope.as_ref(), }; - state.serialize_field("$dbPointer", &body)?; - state.end() + + raw.serialize(serializer) } } diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs new file mode 100644 index 00000000..c12405d3 --- /dev/null +++ b/src/raw/bson_ref.rs @@ -0,0 +1,695 @@ +use std::convert::{TryFrom, TryInto}; + +use serde::{ser::SerializeStruct, Deserialize, Serialize}; +use serde_bytes::Bytes; + +use super::{ + bson::RawBson, + serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, + Error, + RawArray, + RawDocument, + Result, +}; +use crate::{ + extjson, + oid::{self, ObjectId}, + raw::{RawJavaScriptCodeWithScope, RAW_BSON_NEWTYPE}, + spec::{BinarySubtype, ElementType}, + Binary, + Bson, + DbPointer, + Decimal128, + RawArrayBuf, + RawDocumentBuf, + Regex, + Timestamp, +}; + +/// A BSON value referencing raw bytes stored elsewhere. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RawBsonRef<'a> { + /// 64-bit binary floating point + Double(f64), + /// UTF-8 string + String(&'a str), + /// Array + Array(&'a RawArray), + /// Embedded document + Document(&'a RawDocument), + /// Boolean value + Boolean(bool), + /// Null value + Null, + /// Regular expression + RegularExpression(RawRegexRef<'a>), + /// JavaScript code + JavaScriptCode(&'a str), + /// JavaScript code w/ scope + JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef<'a>), + /// 32-bit signed integer + Int32(i32), + /// 64-bit signed integer + Int64(i64), + /// Timestamp + Timestamp(Timestamp), + /// Binary data + Binary(RawBinaryRef<'a>), + /// [ObjectId](http://dochub.mongodb.org/core/objectids) + ObjectId(oid::ObjectId), + /// UTC datetime + DateTime(crate::DateTime), + /// Symbol (Deprecated) + Symbol(&'a str), + /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) + Decimal128(Decimal128), + /// Undefined value (Deprecated) + Undefined, + /// Max key + MaxKey, + /// Min key + MinKey, + /// DBPointer (Deprecated) + DbPointer(RawDbPointerRef<'a>), +} + +impl<'a> RawBsonRef<'a> { + /// Get the [`ElementType`] of this value. + pub fn element_type(&self) -> ElementType { + match *self { + RawBsonRef::Double(..) => ElementType::Double, + RawBsonRef::String(..) => ElementType::String, + RawBsonRef::Array(..) => ElementType::Array, + RawBsonRef::Document(..) => ElementType::EmbeddedDocument, + RawBsonRef::Boolean(..) => ElementType::Boolean, + RawBsonRef::Null => ElementType::Null, + RawBsonRef::RegularExpression(..) => ElementType::RegularExpression, + RawBsonRef::JavaScriptCode(..) => ElementType::JavaScriptCode, + RawBsonRef::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope, + RawBsonRef::Int32(..) => ElementType::Int32, + RawBsonRef::Int64(..) => ElementType::Int64, + RawBsonRef::Timestamp(..) => ElementType::Timestamp, + RawBsonRef::Binary(..) => ElementType::Binary, + RawBsonRef::ObjectId(..) => ElementType::ObjectId, + RawBsonRef::DateTime(..) => ElementType::DateTime, + RawBsonRef::Symbol(..) => ElementType::Symbol, + RawBsonRef::Decimal128(..) => ElementType::Decimal128, + RawBsonRef::Undefined => ElementType::Undefined, + RawBsonRef::MaxKey => ElementType::MaxKey, + RawBsonRef::MinKey => ElementType::MinKey, + RawBsonRef::DbPointer(..) => ElementType::DbPointer, + } + } + + /// Gets the `f64` that's referenced or returns `None` if the referenced value isn't a BSON + /// double. + pub fn as_f64(self) -> Option { + match self { + RawBsonRef::Double(d) => Some(d), + _ => None, + } + } + + /// Gets the `&str` that's referenced or returns `None` if the referenced value isn't a BSON + /// String. + pub fn as_str(self) -> Option<&'a str> { + match self { + RawBsonRef::String(s) => Some(s), + _ => None, + } + } + + /// Gets the [`RawArray`] that's referenced or returns `None` if the referenced value + /// isn't a BSON array. + pub fn as_array(self) -> Option<&'a RawArray> { + match self { + RawBsonRef::Array(v) => Some(v), + _ => None, + } + } + + /// Gets the [`RawDocument`] that's referenced or returns `None` if the referenced value + /// isn't a BSON document. + pub fn as_document(self) -> Option<&'a RawDocument> { + match self { + RawBsonRef::Document(v) => Some(v), + _ => None, + } + } + + /// Gets the `bool` that's referenced or returns `None` if the referenced value isn't a BSON + /// boolean. + pub fn as_bool(self) -> Option { + match self { + RawBsonRef::Boolean(v) => Some(v), + _ => None, + } + } + + /// Gets the `i32` that's referenced or returns `None` if the referenced value isn't a BSON + /// Int32. + pub fn as_i32(self) -> Option { + match self { + RawBsonRef::Int32(v) => Some(v), + _ => None, + } + } + + /// Gets the `i64` that's referenced or returns `None` if the referenced value isn't a BSON + /// Int64. + pub fn as_i64(self) -> Option { + match self { + RawBsonRef::Int64(v) => Some(v), + _ => None, + } + } + + /// Gets the [`crate::oid::ObjectId`] that's referenced or returns `None` if the referenced + /// value isn't a BSON ObjectID. + pub fn as_object_id(self) -> Option { + match self { + RawBsonRef::ObjectId(v) => Some(v), + _ => None, + } + } + + /// Gets the [`RawBinaryRef`] that's referenced or returns `None` if the referenced value isn't + /// a BSON binary. + pub fn as_binary(self) -> Option> { + match self { + RawBsonRef::Binary(v) => Some(v), + _ => None, + } + } + + /// Gets the [`RawRegexRef`] that's referenced or returns `None` if the referenced value isn't a + /// BSON regular expression. + pub fn as_regex(self) -> Option> { + match self { + RawBsonRef::RegularExpression(v) => Some(v), + _ => None, + } + } + + /// Gets the [`crate::DateTime`] that's referenced or returns `None` if the referenced value + /// isn't a BSON datetime. + pub fn as_datetime(self) -> Option { + match self { + RawBsonRef::DateTime(v) => Some(v), + _ => None, + } + } + + /// Gets the symbol that's referenced or returns `None` if the referenced value isn't a BSON + /// symbol. + pub fn as_symbol(self) -> Option<&'a str> { + match self { + RawBsonRef::Symbol(v) => Some(v), + _ => None, + } + } + + /// Gets the [`crate::Timestamp`] that's referenced or returns `None` if the referenced value + /// isn't a BSON timestamp. + pub fn as_timestamp(self) -> Option { + match self { + RawBsonRef::Timestamp(timestamp) => Some(timestamp), + _ => None, + } + } + + /// Gets the null value that's referenced or returns `None` if the referenced value isn't a BSON + /// null. + pub fn as_null(self) -> Option<()> { + match self { + RawBsonRef::Null => Some(()), + _ => None, + } + } + + /// Gets the [`RawDbPointerRef`] that's referenced or returns `None` if the referenced value + /// isn't a BSON DB pointer. + pub fn as_db_pointer(self) -> Option> { + match self { + RawBsonRef::DbPointer(d) => Some(d), + _ => None, + } + } + + /// Gets the code that's referenced or returns `None` if the referenced value isn't a BSON + /// JavaScript. + pub fn as_javascript(self) -> Option<&'a str> { + match self { + RawBsonRef::JavaScriptCode(s) => Some(s), + _ => None, + } + } + + /// Gets the [`RawJavaScriptCodeWithScope`] that's referenced or returns `None` if the + /// referenced value isn't a BSON JavaScript with scope. + pub fn as_javascript_with_scope(self) -> Option> { + match self { + RawBsonRef::JavaScriptCodeWithScope(s) => Some(s), + _ => None, + } + } + + /// Convert this [`RawBsonRef`] to the equivalent [`RawBson`]. + pub fn to_raw_bson(self) -> RawBson { + match self { + RawBsonRef::Double(d) => RawBson::Double(d), + RawBsonRef::String(s) => RawBson::String(s.to_string()), + RawBsonRef::Array(a) => RawBson::Array(a.to_owned()), + RawBsonRef::Document(d) => RawBson::Document(d.to_owned()), + RawBsonRef::Boolean(b) => RawBson::Boolean(b), + RawBsonRef::Null => RawBson::Null, + RawBsonRef::RegularExpression(re) => { + RawBson::RegularExpression(Regex::new(re.pattern, re.options)) + } + RawBsonRef::JavaScriptCode(c) => RawBson::JavaScriptCode(c.to_owned()), + RawBsonRef::JavaScriptCodeWithScope(c_w_s) => { + RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { + code: c_w_s.code.to_string(), + scope: c_w_s.scope.to_owned(), + }) + } + RawBsonRef::Int32(i) => RawBson::Int32(i), + RawBsonRef::Int64(i) => RawBson::Int64(i), + RawBsonRef::Timestamp(t) => RawBson::Timestamp(t), + RawBsonRef::Binary(b) => RawBson::Binary(Binary { + bytes: b.bytes.to_vec(), + subtype: b.subtype, + }), + RawBsonRef::ObjectId(o) => RawBson::ObjectId(o), + RawBsonRef::DateTime(dt) => RawBson::DateTime(dt), + RawBsonRef::Symbol(s) => RawBson::Symbol(s.to_string()), + RawBsonRef::Decimal128(d) => RawBson::Decimal128(d), + RawBsonRef::Undefined => RawBson::Undefined, + RawBsonRef::MaxKey => RawBson::MaxKey, + RawBsonRef::MinKey => RawBson::MinKey, + RawBsonRef::DbPointer(d) => RawBson::DbPointer(DbPointer { + namespace: d.namespace.to_string(), + id: d.id, + }), + } + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for RawBsonRef<'a> { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match deserializer + .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? + { + OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b), + o => Err(serde::de::Error::custom(format!( + "RawBson must be deserialized from borrowed content, instead got {:?}", + o + ))), + } + } +} + +impl<'a> Serialize for RawBsonRef<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + match self { + RawBsonRef::Double(v) => serializer.serialize_f64(*v), + RawBsonRef::String(v) => serializer.serialize_str(v), + RawBsonRef::Array(v) => v.serialize(serializer), + RawBsonRef::Document(v) => v.serialize(serializer), + RawBsonRef::Boolean(v) => serializer.serialize_bool(*v), + RawBsonRef::Null => serializer.serialize_unit(), + RawBsonRef::Int32(v) => serializer.serialize_i32(*v), + RawBsonRef::Int64(v) => serializer.serialize_i64(*v), + RawBsonRef::ObjectId(oid) => oid.serialize(serializer), + RawBsonRef::DateTime(dt) => dt.serialize(serializer), + RawBsonRef::Binary(b) => b.serialize(serializer), + RawBsonRef::JavaScriptCode(c) => { + let mut state = serializer.serialize_struct("$code", 1)?; + state.serialize_field("$code", c)?; + state.end() + } + RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => code_w_scope.serialize(serializer), + RawBsonRef::DbPointer(dbp) => dbp.serialize(serializer), + RawBsonRef::Symbol(s) => { + let mut state = serializer.serialize_struct("$symbol", 1)?; + state.serialize_field("$symbol", s)?; + state.end() + } + RawBsonRef::RegularExpression(re) => re.serialize(serializer), + RawBsonRef::Timestamp(t) => t.serialize(serializer), + RawBsonRef::Decimal128(d) => d.serialize(serializer), + RawBsonRef::Undefined => { + let mut state = serializer.serialize_struct("$undefined", 1)?; + state.serialize_field("$undefined", &true)?; + state.end() + } + RawBsonRef::MaxKey => { + let mut state = serializer.serialize_struct("$maxKey", 1)?; + state.serialize_field("$maxKey", &1)?; + state.end() + } + RawBsonRef::MinKey => { + let mut state = serializer.serialize_struct("$minKey", 1)?; + state.serialize_field("$minKey", &1)?; + state.end() + } + } + } +} + +impl<'a> TryFrom> for Bson { + type Error = Error; + + fn try_from(rawbson: RawBsonRef<'a>) -> Result { + rawbson.to_raw_bson().try_into() + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(i: i32) -> Self { + RawBsonRef::Int32(i) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(i: i64) -> Self { + RawBsonRef::Int64(i) + } +} + +impl<'a> From<&'a str> for RawBsonRef<'a> { + fn from(s: &'a str) -> Self { + RawBsonRef::String(s) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(f: f64) -> Self { + RawBsonRef::Double(f) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(b: bool) -> Self { + RawBsonRef::Boolean(b) + } +} + +impl<'a> From<&'a RawDocumentBuf> for RawBsonRef<'a> { + fn from(d: &'a RawDocumentBuf) -> Self { + RawBsonRef::Document(d.as_ref()) + } +} + +impl<'a> From<&'a RawDocument> for RawBsonRef<'a> { + fn from(d: &'a RawDocument) -> Self { + RawBsonRef::Document(d) + } +} + +impl<'a> From<&'a RawArray> for RawBsonRef<'a> { + fn from(a: &'a RawArray) -> Self { + RawBsonRef::Array(a) + } +} + +impl<'a> From<&'a RawArrayBuf> for RawBsonRef<'a> { + fn from(a: &'a RawArrayBuf) -> Self { + RawBsonRef::Array(a) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(dt: crate::DateTime) -> Self { + RawBsonRef::DateTime(dt) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(ts: Timestamp) -> Self { + RawBsonRef::Timestamp(ts) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(oid: ObjectId) -> Self { + RawBsonRef::ObjectId(oid) + } +} + +impl<'a> From for RawBsonRef<'a> { + fn from(d: Decimal128) -> Self { + RawBsonRef::Decimal128(d) + } +} + +/// A BSON binary value referencing raw bytes stored elsewhere. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct RawBinaryRef<'a> { + /// The subtype of the binary value. + pub subtype: BinarySubtype, + + /// The binary bytes. + pub bytes: &'a [u8], +} + +impl<'a> RawBinaryRef<'a> { + pub(crate) fn len(&self) -> i32 { + match self.subtype { + BinarySubtype::BinaryOld => self.bytes.len() as i32 + 4, + _ => self.bytes.len() as i32, + } + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for RawBinaryRef<'a> { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match RawBsonRef::deserialize(deserializer)? { + RawBsonRef::Binary(b) => Ok(b), + c => Err(serde::de::Error::custom(format!( + "expected binary, but got {:?} instead", + c + ))), + } + } +} + +impl<'a> Serialize for RawBinaryRef<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + if let BinarySubtype::Generic = self.subtype { + serializer.serialize_bytes(self.bytes) + } else if !serializer.is_human_readable() { + #[derive(Serialize)] + struct BorrowedBinary<'a> { + bytes: &'a Bytes, + + #[serde(rename = "subType")] + subtype: u8, + } + + let mut state = serializer.serialize_struct("$binary", 1)?; + let body = BorrowedBinary { + bytes: Bytes::new(self.bytes), + subtype: self.subtype.into(), + }; + state.serialize_field("$binary", &body)?; + state.end() + } else { + let mut state = serializer.serialize_struct("$binary", 1)?; + let body = extjson::models::BinaryBody { + base64: base64::encode(self.bytes), + subtype: hex::encode([self.subtype.into()]), + }; + state.serialize_field("$binary", &body)?; + state.end() + } + } +} + +impl<'a> From> for RawBsonRef<'a> { + fn from(b: RawBinaryRef<'a>) -> Self { + RawBsonRef::Binary(b) + } +} + +impl<'a> From<&'a Binary> for RawBsonRef<'a> { + fn from(bin: &'a Binary) -> Self { + bin.as_raw_binary().into() + } +} + +/// A BSON regex referencing raw bytes stored elsewhere. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct RawRegexRef<'a> { + pub(crate) pattern: &'a str, + pub(crate) options: &'a str, +} + +impl<'a> RawRegexRef<'a> { + /// Gets the pattern portion of the regex. + pub fn pattern(self) -> &'a str { + self.pattern + } + + /// Gets the options portion of the regex. + pub fn options(self) -> &'a str { + self.options + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for RawRegexRef<'a> { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match RawBsonRef::deserialize(deserializer)? { + RawBsonRef::RegularExpression(b) => Ok(b), + c => Err(serde::de::Error::custom(format!( + "expected Regex, but got {:?} instead", + c + ))), + } + } +} + +impl<'a> Serialize for RawRegexRef<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + #[derive(Serialize)] + struct BorrowedRegexBody<'a> { + pattern: &'a str, + options: &'a str, + } + + let mut state = serializer.serialize_struct("$regularExpression", 1)?; + let body = BorrowedRegexBody { + pattern: self.pattern, + options: self.options, + }; + state.serialize_field("$regularExpression", &body)?; + state.end() + } +} + +impl<'a> From> for RawBsonRef<'a> { + fn from(re: RawRegexRef<'a>) -> Self { + RawBsonRef::RegularExpression(re) + } +} + +/// A BSON "code with scope" value referencing raw bytes stored elsewhere. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct RawJavaScriptCodeWithScopeRef<'a> { + pub(crate) code: &'a str, + + pub(crate) scope: &'a RawDocument, +} + +impl<'a> RawJavaScriptCodeWithScopeRef<'a> { + /// Gets the code in the value. + pub fn code(self) -> &'a str { + self.code + } + + /// Gets the scope in the value. + pub fn scope(self) -> &'a RawDocument { + self.scope + } + + pub(crate) fn len(self) -> i32 { + 4 + 4 + self.code.len() as i32 + 1 + self.scope.as_bytes().len() as i32 + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScopeRef<'a> { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match RawBsonRef::deserialize(deserializer)? { + RawBsonRef::JavaScriptCodeWithScope(b) => Ok(b), + c => Err(serde::de::Error::custom(format!( + "expected CodeWithScope, but got {:?} instead", + c + ))), + } + } +} + +impl<'a> Serialize for RawJavaScriptCodeWithScopeRef<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("$codeWithScope", 2)?; + state.serialize_field("$code", &self.code)?; + state.serialize_field("$scope", &self.scope)?; + state.end() + } +} + +impl<'a> From> for RawBsonRef<'a> { + fn from(code_w_scope: RawJavaScriptCodeWithScopeRef<'a>) -> Self { + RawBsonRef::JavaScriptCodeWithScope(code_w_scope) + } +} + +/// A BSON DB pointer value referencing raw bytes stored elesewhere. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct RawDbPointerRef<'a> { + pub(crate) namespace: &'a str, + pub(crate) id: ObjectId, +} + +impl<'de: 'a, 'a> Deserialize<'de> for RawDbPointerRef<'a> { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + match RawBsonRef::deserialize(deserializer)? { + RawBsonRef::DbPointer(b) => Ok(b), + c => Err(serde::de::Error::custom(format!( + "expected DbPointer, but got {:?} instead", + c + ))), + } + } +} + +impl<'a> Serialize for RawDbPointerRef<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + #[derive(Serialize)] + struct BorrowedDbPointerBody<'a> { + #[serde(rename = "$ref")] + ref_ns: &'a str, + + #[serde(rename = "$id")] + id: ObjectId, + } + + let mut state = serializer.serialize_struct("$dbPointer", 1)?; + let body = BorrowedDbPointerBody { + ref_ns: self.namespace, + id: self.id, + }; + state.serialize_field("$dbPointer", &body)?; + state.end() + } +} diff --git a/src/raw/document.rs b/src/raw/document.rs index b27b7fb8..3f3e4318 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -17,10 +17,10 @@ use super::{ Error, Iter, RawArray, - RawBinary, - RawBson, + RawBinaryRef, + RawBsonRef, RawDocumentBuf, - RawRegex, + RawRegexRef, Result, }; use crate::{oid::ObjectId, spec::ElementType, Document}; @@ -168,7 +168,7 @@ impl RawDocument { /// assert!(doc.get("unknown")?.is_none()); /// # Ok::<(), Error>(()) /// ``` - pub fn get(&self, key: impl AsRef) -> Result>> { + pub fn get(&self, key: impl AsRef) -> Result>> { for result in self.into_iter() { let (k, v) = result?; if key.as_ref() == k { @@ -182,7 +182,7 @@ impl RawDocument { &'a self, key: impl AsRef, expected_type: ElementType, - f: impl FnOnce(RawBson<'a>) -> Option, + f: impl FnOnce(RawBsonRef<'a>) -> Option, ) -> ValueAccessResult { let key = key.as_ref(); @@ -227,7 +227,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_f64(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::Double, RawBson::as_f64) + self.get_with(key, ElementType::Double, RawBsonRef::as_f64) } /// Gets a reference to the string value corresponding to a given key or returns an error if the @@ -247,7 +247,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_str(&self, key: impl AsRef) -> ValueAccessResult<&'_ str> { - self.get_with(key, ElementType::String, RawBson::as_str) + self.get_with(key, ElementType::String, RawBsonRef::as_str) } /// Gets a reference to the document value corresponding to a given key or returns an error if @@ -268,7 +268,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_document(&self, key: impl AsRef) -> ValueAccessResult<&'_ RawDocument> { - self.get_with(key, ElementType::EmbeddedDocument, RawBson::as_document) + self.get_with(key, ElementType::EmbeddedDocument, RawBsonRef::as_document) } /// Gets a reference to the array value corresponding to a given key or returns an error if @@ -292,7 +292,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_array(&self, key: impl AsRef) -> ValueAccessResult<&'_ RawArray> { - self.get_with(key, ElementType::Array, RawBson::as_array) + self.get_with(key, ElementType::Array, RawBsonRef::as_array) } /// Gets a reference to the BSON binary value corresponding to a given key or returns an error @@ -301,7 +301,7 @@ impl RawDocument { /// ``` /// use bson::{ /// doc, - /// raw::{ValueAccessErrorKind, RawDocumentBuf, RawBinary}, + /// raw::{ValueAccessErrorKind, RawDocumentBuf, RawBinaryRef}, /// spec::BinarySubtype, /// Binary, /// }; @@ -316,8 +316,8 @@ impl RawDocument { /// assert!(matches!(doc.get_binary("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` - pub fn get_binary(&self, key: impl AsRef) -> ValueAccessResult> { - self.get_with(key, ElementType::Binary, RawBson::as_binary) + pub fn get_binary(&self, key: impl AsRef) -> ValueAccessResult> { + self.get_with(key, ElementType::Binary, RawBsonRef::as_binary) } /// Gets a reference to the ObjectId value corresponding to a given key or returns an error if @@ -338,7 +338,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_object_id(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::ObjectId, RawBson::as_object_id) + self.get_with(key, ElementType::ObjectId, RawBsonRef::as_object_id) } /// Gets a reference to the boolean value corresponding to a given key or returns an error if @@ -359,7 +359,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_bool(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::Boolean, RawBson::as_bool) + self.get_with(key, ElementType::Boolean, RawBsonRef::as_bool) } /// Gets a reference to the BSON DateTime value corresponding to a given key or returns an @@ -381,7 +381,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_datetime(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::DateTime, RawBson::as_datetime) + self.get_with(key, ElementType::DateTime, RawBsonRef::as_datetime) } /// Gets a reference to the BSON regex value corresponding to a given key or returns an error if @@ -404,8 +404,8 @@ impl RawDocument { /// assert!(matches!(doc.get_regex("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` - pub fn get_regex(&self, key: impl AsRef) -> ValueAccessResult> { - self.get_with(key, ElementType::RegularExpression, RawBson::as_regex) + pub fn get_regex(&self, key: impl AsRef) -> ValueAccessResult> { + self.get_with(key, ElementType::RegularExpression, RawBsonRef::as_regex) } /// Gets a reference to the BSON timestamp value corresponding to a given key or returns an @@ -429,7 +429,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_timestamp(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::Timestamp, RawBson::as_timestamp) + self.get_with(key, ElementType::Timestamp, RawBsonRef::as_timestamp) } /// Gets a reference to the BSON int32 value corresponding to a given key or returns an error if @@ -450,7 +450,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_i32(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::Int32, RawBson::as_i32) + self.get_with(key, ElementType::Int32, RawBsonRef::as_i32) } /// Gets a reference to the BSON int64 value corresponding to a given key or returns an error if @@ -471,7 +471,7 @@ impl RawDocument { /// # Ok::<(), Box>(()) /// ``` pub fn get_i64(&self, key: impl AsRef) -> ValueAccessResult { - self.get_with(key, ElementType::Int64, RawBson::as_i64) + self.get_with(key, ElementType::Int64, RawBsonRef::as_i64) } /// Return a reference to the contained data as a `&[u8]` @@ -572,7 +572,7 @@ impl TryFrom<&RawDocument> for crate::Document { impl<'a> IntoIterator for &'a RawDocument { type IntoIter = Iter<'a>; - type Item = Result<(&'a str, RawBson<'a>)>; + type Item = Result<(&'a str, RawBsonRef<'a>)>; fn into_iter(self) -> Iter<'a> { Iter::new(self) diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 48adddae..b7742522 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -11,17 +11,17 @@ use crate::{ de::MIN_BSON_DOCUMENT_SIZE, spec::BinarySubtype, Document, - RawBinary, - RawJavaScriptCodeWithScope, + RawBinaryRef, + RawJavaScriptCodeWithScopeRef, }; use super::{ - owned_bson::OwnedRawBson, + bson::RawBson, serde::OwnedOrBorrowedRawDocument, Error, ErrorKind, Iter, - RawBson, + RawBsonRef, RawDocument, Result, }; @@ -192,7 +192,7 @@ impl RawDocumentBuf { /// assert_eq!(doc.to_document()?, expected); /// # Ok::<(), Error>(()) /// ``` - pub fn append(&mut self, key: impl Into, value: impl Into) { + pub fn append(&mut self, key: impl Into, value: impl Into) { fn append_string(doc: &mut RawDocumentBuf, value: String) { doc.data .extend(&((value.as_bytes().len() + 1) as i32).to_le_bytes()); @@ -218,20 +218,20 @@ impl RawDocumentBuf { let element_type = value.element_type(); match value { - OwnedRawBson::Int32(i) => { + RawBson::Int32(i) => { self.data.extend(&i.to_le_bytes()); } - OwnedRawBson::String(s) => { + RawBson::String(s) => { append_string(self, s); } - OwnedRawBson::Document(d) => { + RawBson::Document(d) => { self.data.extend(d.into_bytes()); } - OwnedRawBson::Array(a) => { + RawBson::Array(a) => { self.data.extend(a.into_vec()); } - OwnedRawBson::Binary(b) => { - let len = RawBinary { + RawBson::Binary(b) => { + let len = RawBinaryRef { bytes: b.bytes.as_slice(), subtype: b.subtype, } @@ -243,35 +243,35 @@ impl RawDocumentBuf { } self.data.extend(b.bytes); } - OwnedRawBson::Boolean(b) => { + RawBson::Boolean(b) => { let byte = if b { 1 } else { 0 }; self.data.push(byte); } - OwnedRawBson::DateTime(dt) => { + RawBson::DateTime(dt) => { self.data.extend(&dt.timestamp_millis().to_le_bytes()); } - OwnedRawBson::DbPointer(dbp) => { + RawBson::DbPointer(dbp) => { append_string(self, dbp.namespace); self.data.extend(&dbp.id.bytes()); } - OwnedRawBson::Decimal128(d) => { + RawBson::Decimal128(d) => { self.data.extend(&d.bytes()); } - OwnedRawBson::Double(d) => { + RawBson::Double(d) => { self.data.extend(&d.to_le_bytes()); } - OwnedRawBson::Int64(i) => { + RawBson::Int64(i) => { self.data.extend(&i.to_le_bytes()); } - OwnedRawBson::RegularExpression(re) => { + RawBson::RegularExpression(re) => { append_cstring(self, re.pattern); append_cstring(self, re.options); } - OwnedRawBson::JavaScriptCode(js) => { + RawBson::JavaScriptCode(js) => { append_string(self, js); } - OwnedRawBson::JavaScriptCodeWithScope(code_w_scope) => { - let len = RawJavaScriptCodeWithScope { + RawBson::JavaScriptCodeWithScope(code_w_scope) => { + let len = RawJavaScriptCodeWithScopeRef { code: code_w_scope.code.as_str(), scope: &code_w_scope.scope, } @@ -280,19 +280,16 @@ impl RawDocumentBuf { append_string(self, code_w_scope.code); self.data.extend(code_w_scope.scope.into_bytes()); } - OwnedRawBson::Timestamp(ts) => { + RawBson::Timestamp(ts) => { self.data.extend(&ts.to_le_i64().to_le_bytes()); } - OwnedRawBson::ObjectId(oid) => { + RawBson::ObjectId(oid) => { self.data.extend(&oid.bytes()); } - OwnedRawBson::Symbol(s) => { + RawBson::Symbol(s) => { append_string(self, s); } - OwnedRawBson::Null - | OwnedRawBson::Undefined - | OwnedRawBson::MinKey - | OwnedRawBson::MaxKey => {} + RawBson::Null | RawBson::Undefined | RawBson::MinKey | RawBson::MaxKey => {} } // update element type self.data[original_len - 1] = element_type as u8; @@ -365,7 +362,7 @@ impl TryFrom for Document { impl<'a> IntoIterator for &'a RawDocumentBuf { type IntoIter = Iter<'a>; - type Item = Result<(&'a str, RawBson<'a>)>; + type Item = Result<(&'a str, RawBsonRef<'a>)>; fn into_iter(self) -> Iter<'a> { Iter::new(self) @@ -392,7 +389,7 @@ impl Borrow for RawDocumentBuf { } } -impl, T: Into> FromIterator<(S, T)> for RawDocumentBuf { +impl, T: Into> FromIterator<(S, T)> for RawDocumentBuf { fn from_iter>(iter: I) -> Self { let mut buf = RawDocumentBuf::new(); for (k, v) in iter { diff --git a/src/raw/iter.rs b/src/raw/iter.rs index 8f0708d6..97b1c94c 100644 --- a/src/raw/iter.rs +++ b/src/raw/iter.rs @@ -11,7 +11,7 @@ use crate::{ }; use super::{ - bson::RawDbPointer, + bson_ref::RawDbPointerRef, checked_add, error::try_with_key, f64_from_slice, @@ -20,11 +20,11 @@ use super::{ read_lenencoded, read_nullterminated, RawArray, - RawBinary, - RawBson, + RawBinaryRef, + RawBsonRef, RawDocument, - RawJavaScriptCodeWithScope, - RawRegex, + RawJavaScriptCodeWithScopeRef, + RawRegexRef, }; /// An iterator over the document's entries. @@ -96,9 +96,9 @@ impl<'a> Iter<'a> { } impl<'a> Iterator for Iter<'a> { - type Item = Result<(&'a str, RawBson<'a>)>; + type Item = Result<(&'a str, RawBsonRef<'a>)>; - fn next(&mut self) -> Option)>> { + fn next(&mut self) -> Option)>> { if !self.valid { return None; } else if self.offset == self.doc.as_bytes().len() - 1 { @@ -147,28 +147,28 @@ impl<'a> Iterator for Iter<'a> { let (element, element_size) = match element_type { ElementType::Int32 => { let i = i32_from_slice(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::Int32(i), 4) + (RawBsonRef::Int32(i), 4) } ElementType::Int64 => { let i = i64_from_slice(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::Int64(i), 8) + (RawBsonRef::Int64(i), 8) } ElementType::Double => { let f = f64_from_slice(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::Double(f), 8) + (RawBsonRef::Double(f), 8) } ElementType::String => { let s = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::String(s), 4 + s.len() + 1) + (RawBsonRef::String(s), 4 + s.len() + 1) } ElementType::EmbeddedDocument => { let doc = self.next_document(valueoffset)?; - (RawBson::Document(doc), doc.as_bytes().len()) + (RawBsonRef::Document(doc), doc.as_bytes().len()) } ElementType::Array => { let doc = self.next_document(valueoffset)?; ( - RawBson::Array(RawArray::from_doc(doc)), + RawBsonRef::Array(RawArray::from_doc(doc)), doc.as_bytes().len(), ) } @@ -198,7 +198,7 @@ impl<'a> Iterator for Iter<'a> { _ => &self.doc.as_bytes()[data_start..(data_start + len)], }; ( - RawBson::Binary(RawBinary { + RawBsonRef::Binary(RawBinaryRef { subtype, bytes: data, }), @@ -207,7 +207,7 @@ impl<'a> Iterator for Iter<'a> { } ElementType::ObjectId => { let oid = self.next_oid(valueoffset)?; - (RawBson::ObjectId(oid), 12) + (RawBsonRef::ObjectId(oid), 12) } ElementType::Boolean => { let b = read_bool(&self.doc.as_bytes()[valueoffset..]).map_err(|e| { @@ -218,11 +218,11 @@ impl<'a> Iterator for Iter<'a> { }, ) })?; - (RawBson::Boolean(b), 1) + (RawBsonRef::Boolean(b), 1) } ElementType::DateTime => { let ms = i64_from_slice(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::DateTime(DateTime::from_millis(ms)), 8) + (RawBsonRef::DateTime(DateTime::from_millis(ms)), 8) } ElementType::RegularExpression => { let pattern = read_nullterminated(&self.doc.as_bytes()[valueoffset..])?; @@ -230,12 +230,12 @@ impl<'a> Iterator for Iter<'a> { &self.doc.as_bytes()[(valueoffset + pattern.len() + 1)..], )?; ( - RawBson::RegularExpression(RawRegex { pattern, options }), + RawBsonRef::RegularExpression(RawRegexRef { pattern, options }), pattern.len() + 1 + options.len() + 1, ) } - ElementType::Null => (RawBson::Null, 0), - ElementType::Undefined => (RawBson::Undefined, 0), + ElementType::Null => (RawBsonRef::Null, 0), + ElementType::Undefined => (RawBsonRef::Undefined, 0), ElementType::Timestamp => { let ts = Timestamp::from_reader(&self.doc.as_bytes()[valueoffset..]).map_err( |e| { @@ -244,11 +244,11 @@ impl<'a> Iterator for Iter<'a> { }) }, )?; - (RawBson::Timestamp(ts), 8) + (RawBsonRef::Timestamp(ts), 8) } ElementType::JavaScriptCode => { let code = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::JavaScriptCode(code), 4 + code.len() + 1) + (RawBsonRef::JavaScriptCode(code), 4 + code.len() + 1) } ElementType::JavaScriptCodeWithScope => { let length = i32_from_slice(&self.doc.as_bytes()[valueoffset..])? as usize; @@ -265,7 +265,7 @@ impl<'a> Iterator for Iter<'a> { let scope_start = 4 + 4 + code.len() + 1; let scope = RawDocument::from_bytes(&slice[scope_start..])?; ( - RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { + RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { code, scope, }), @@ -276,18 +276,18 @@ impl<'a> Iterator for Iter<'a> { let namespace = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?; let id = self.next_oid(valueoffset + 4 + namespace.len() + 1)?; ( - RawBson::DbPointer(RawDbPointer { namespace, id }), + RawBsonRef::DbPointer(RawDbPointerRef { namespace, id }), 4 + namespace.len() + 1 + 12, ) } ElementType::Symbol => { let s = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?; - (RawBson::Symbol(s), 4 + s.len() + 1) + (RawBsonRef::Symbol(s), 4 + s.len() + 1) } ElementType::Decimal128 => { self.verify_enough_bytes(valueoffset, 16)?; ( - RawBson::Decimal128(Decimal128::from_bytes( + RawBsonRef::Decimal128(Decimal128::from_bytes( self.doc.as_bytes()[valueoffset..(valueoffset + 16)] .try_into() .unwrap(), @@ -295,8 +295,8 @@ impl<'a> Iterator for Iter<'a> { 16, ) } - ElementType::MinKey => (RawBson::MinKey, 0), - ElementType::MaxKey => (RawBson::MaxKey, 0), + ElementType::MinKey => (RawBsonRef::MinKey, 0), + ElementType::MaxKey => (RawBsonRef::MaxKey, 0), }; self.offset = valueoffset + element_size; diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 970da631..a85a8a92 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -88,7 +88,7 @@ //! ```rust //! use bson::{ //! raw::{ -//! RawBson, +//! RawBsonRef, //! RawDocumentBuf, //! }, //! doc, @@ -102,11 +102,11 @@ //! let doc = RawDocumentBuf::from_document(&original_doc)?; //! let mut doc_iter = doc.iter(); //! -//! let (key, value): (&str, RawBson) = doc_iter.next().unwrap()?; +//! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?; //! assert_eq!(key, "crate"); //! assert_eq!(value.as_str(), Some("bson")); //! -//! let (key, value): (&str, RawBson) = doc_iter.next().unwrap()?; +//! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?; //! assert_eq!(key, "year"); //! assert_eq!(value.as_str(), Some("2021")); //! # Ok::<(), bson::raw::Error>(()) @@ -115,11 +115,11 @@ mod array; mod array_buf; mod bson; +mod bson_ref; mod document; mod document_buf; mod error; mod iter; -mod owned_bson; mod serde; #[cfg(test)] mod test; @@ -131,12 +131,18 @@ use crate::de::MIN_BSON_STRING_SIZE; pub use self::{ array::{RawArray, RawArrayIter}, array_buf::RawArrayBuf, - bson::{RawBinary, RawBson, RawDbPointer, RawJavaScriptCodeWithScope, RawRegex}, + bson::{RawBson, RawJavaScriptCodeWithScope}, + bson_ref::{ + RawBinaryRef, + RawBsonRef, + RawDbPointerRef, + RawJavaScriptCodeWithScopeRef, + RawRegexRef, + }, document::RawDocument, document_buf::RawDocumentBuf, error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, iter::Iter, - owned_bson::{OwnedRawBson, OwnedRawJavaScriptCodeWithScope}, }; /// Special newtype name indicating that the type being (de)serialized is a raw BSON document. diff --git a/src/raw/owned_bson.rs b/src/raw/owned_bson.rs deleted file mode 100644 index a1699fa4..00000000 --- a/src/raw/owned_bson.rs +++ /dev/null @@ -1,522 +0,0 @@ -use std::convert::{TryFrom, TryInto}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - oid::{self, ObjectId}, - raw::RAW_BSON_NEWTYPE, - spec::ElementType, - Binary, - Bson, - DbPointer, - Decimal128, - RawArray, - RawArrayBuf, - RawBinary, - RawBson, - RawDbPointer, - RawDocument, - RawDocumentBuf, - RawJavaScriptCodeWithScope, - RawRegex, - Regex, - Timestamp, -}; - -use super::{ - serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor}, - Error, - Result, -}; - -/// A BSON value backed by owned raw BSON bytes. -#[derive(Debug, Clone, PartialEq)] -pub enum OwnedRawBson { - /// 64-bit binary floating point - Double(f64), - /// UTF-8 string - String(String), - /// Array - Array(RawArrayBuf), - /// Embedded document - Document(RawDocumentBuf), - /// Boolean value - Boolean(bool), - /// Null value - Null, - /// Regular expression - RegularExpression(Regex), - /// JavaScript code - JavaScriptCode(String), - /// JavaScript code w/ scope - JavaScriptCodeWithScope(OwnedRawJavaScriptCodeWithScope), - /// 32-bit signed integer - Int32(i32), - /// 64-bit signed integer - Int64(i64), - /// Timestamp - Timestamp(Timestamp), - /// Binary data - Binary(Binary), - /// [ObjectId](http://dochub.mongodb.org/core/objectids) - ObjectId(oid::ObjectId), - /// UTC datetime - DateTime(crate::DateTime), - /// Symbol (Deprecated) - Symbol(String), - /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) - Decimal128(Decimal128), - /// Undefined value (Deprecated) - Undefined, - /// Max key - MaxKey, - /// Min key - MinKey, - /// DBPointer (Deprecated) - DbPointer(DbPointer), -} - -impl OwnedRawBson { - /// Get the [`ElementType`] of this value. - pub fn element_type(&self) -> ElementType { - match *self { - OwnedRawBson::Double(..) => ElementType::Double, - OwnedRawBson::String(..) => ElementType::String, - OwnedRawBson::Array(..) => ElementType::Array, - OwnedRawBson::Document(..) => ElementType::EmbeddedDocument, - OwnedRawBson::Boolean(..) => ElementType::Boolean, - OwnedRawBson::Null => ElementType::Null, - OwnedRawBson::RegularExpression(..) => ElementType::RegularExpression, - OwnedRawBson::JavaScriptCode(..) => ElementType::JavaScriptCode, - OwnedRawBson::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope, - OwnedRawBson::Int32(..) => ElementType::Int32, - OwnedRawBson::Int64(..) => ElementType::Int64, - OwnedRawBson::Timestamp(..) => ElementType::Timestamp, - OwnedRawBson::Binary(..) => ElementType::Binary, - OwnedRawBson::ObjectId(..) => ElementType::ObjectId, - OwnedRawBson::DateTime(..) => ElementType::DateTime, - OwnedRawBson::Symbol(..) => ElementType::Symbol, - OwnedRawBson::Decimal128(..) => ElementType::Decimal128, - OwnedRawBson::Undefined => ElementType::Undefined, - OwnedRawBson::MaxKey => ElementType::MaxKey, - OwnedRawBson::MinKey => ElementType::MinKey, - OwnedRawBson::DbPointer(..) => ElementType::DbPointer, - } - } - - /// Gets the wrapped `f64` value or returns `None` if the value isn't a BSON - /// double. - pub fn as_f64(&self) -> Option { - match self { - OwnedRawBson::Double(d) => Some(*d), - _ => None, - } - } - - /// Gets a reference to the `String` that's wrapped or returns `None` if the wrapped value isn't - /// a BSON String. - pub fn as_str(&self) -> Option<&'_ str> { - match self { - OwnedRawBson::String(s) => Some(s), - _ => None, - } - } - - /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the wrapped - /// value isn't a BSON array. - pub fn as_array(&self) -> Option<&'_ RawArray> { - match self { - OwnedRawBson::Array(v) => Some(v), - _ => None, - } - } - - /// Gets a mutable reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the - /// wrapped value isn't a BSON array. - pub fn as_array_mut(&mut self) -> Option<&mut RawArrayBuf> { - match self { - OwnedRawBson::Array(ref mut v) => Some(v), - _ => None, - } - } - - /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped - /// value isn't a BSON document. - pub fn as_document(&self) -> Option<&'_ RawDocument> { - match self { - OwnedRawBson::Document(v) => Some(v), - _ => None, - } - } - - /// Gets a mutable reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the - /// wrapped value isn't a BSON document. - pub fn as_document_mut(&mut self) -> Option<&mut RawDocumentBuf> { - match self { - OwnedRawBson::Document(ref mut v) => Some(v), - _ => None, - } - } - - /// Gets the wrapped `bool` value or returns `None` if the wrapped value isn't a BSON - /// boolean. - pub fn as_bool(&self) -> Option { - match self { - OwnedRawBson::Boolean(v) => Some(*v), - _ => None, - } - } - - /// Gets the wrapped `i32` value or returns `None` if the wrapped value isn't a BSON - /// Int32. - pub fn as_i32(&self) -> Option { - match self { - OwnedRawBson::Int32(v) => Some(*v), - _ => None, - } - } - - /// Gets the wrapped `i64` value or returns `None` if the wrapped value isn't a BSON - /// Int64. - pub fn as_i64(&self) -> Option { - match self { - OwnedRawBson::Int64(v) => Some(*v), - _ => None, - } - } - - /// Gets the wrapped [`crate::oid::ObjectId`] value or returns `None` if the wrapped value isn't - /// a BSON ObjectID. - pub fn as_object_id(&self) -> Option { - match self { - OwnedRawBson::ObjectId(v) => Some(*v), - _ => None, - } - } - - /// Gets a reference to the [`Binary`] that's wrapped or returns `None` if the wrapped value - /// isn't a BSON binary. - pub fn as_binary(&self) -> Option> { - match self { - OwnedRawBson::Binary(v) => Some(RawBinary { - bytes: v.bytes.as_slice(), - subtype: v.subtype, - }), - _ => None, - } - } - - /// Gets a reference to the [`Regex`] that's wrapped or returns `None` if the wrapped value - /// isn't a BSON regular expression. - pub fn as_regex(&self) -> Option> { - match self { - OwnedRawBson::RegularExpression(v) => Some(RawRegex { - pattern: v.pattern.as_str(), - options: v.options.as_str(), - }), - _ => None, - } - } - - /// Gets the wrapped [`crate::DateTime`] value or returns `None` if the wrapped value isn't a - /// BSON datetime. - pub fn as_datetime(&self) -> Option { - match self { - OwnedRawBson::DateTime(v) => Some(*v), - _ => None, - } - } - - /// Gets a reference to the symbol that's wrapped or returns `None` if the wrapped value isn't a - /// BSON Symbol. - pub fn as_symbol(&self) -> Option<&'_ str> { - match self { - OwnedRawBson::Symbol(v) => Some(v), - _ => None, - } - } - - /// Gets the wrapped [`crate::Timestamp`] value or returns `None` if the wrapped value isn't a - /// BSON datetime. - pub fn as_timestamp(&self) -> Option { - match self { - OwnedRawBson::Timestamp(timestamp) => Some(*timestamp), - _ => None, - } - } - - /// Returns `Some(())` if this value is null, otherwise returns `None`. - pub fn as_null(&self) -> Option<()> { - match self { - OwnedRawBson::Null => Some(()), - _ => None, - } - } - - /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns `None` if the wrapped - /// value isn't a BSON DbPointer. - pub fn as_db_pointer(&self) -> Option> { - match self { - OwnedRawBson::DbPointer(d) => Some(RawDbPointer { - namespace: d.namespace.as_str(), - id: d.id, - }), - _ => None, - } - } - - /// Gets a reference to the code that's wrapped or returns `None` if the wrapped value isn't a - /// BSON JavaScript code. - pub fn as_javascript(&self) -> Option<&'_ str> { - match self { - OwnedRawBson::JavaScriptCode(s) => Some(s), - _ => None, - } - } - - /// Gets a reference to the [`OwnedRawJavaScriptCodeWithScope`] that's wrapped or returns `None` - /// if the wrapped value isn't a BSON JavaScript code with scope value. - pub fn as_javascript_with_scope(&self) -> Option> { - match self { - OwnedRawBson::JavaScriptCodeWithScope(s) => Some(RawJavaScriptCodeWithScope { - code: s.code.as_str(), - scope: &s.scope, - }), - _ => None, - } - } - - /// Gets a [`RawBson`] value referencing this owned raw BSON value. - pub fn as_raw_bson(&self) -> RawBson<'_> { - match self { - OwnedRawBson::Double(d) => RawBson::Double(*d), - OwnedRawBson::String(s) => RawBson::String(s.as_str()), - OwnedRawBson::Array(a) => RawBson::Array(a), - OwnedRawBson::Document(d) => RawBson::Document(d), - OwnedRawBson::Boolean(b) => RawBson::Boolean(*b), - OwnedRawBson::Null => RawBson::Null, - OwnedRawBson::RegularExpression(re) => RawBson::RegularExpression(RawRegex { - options: re.options.as_str(), - pattern: re.pattern.as_str(), - }), - OwnedRawBson::JavaScriptCode(c) => RawBson::JavaScriptCode(c.as_str()), - OwnedRawBson::JavaScriptCodeWithScope(code_w_scope) => { - RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { - code: code_w_scope.code.as_str(), - scope: code_w_scope.scope.as_ref(), - }) - } - OwnedRawBson::Int32(i) => RawBson::Int32(*i), - OwnedRawBson::Int64(i) => RawBson::Int64(*i), - OwnedRawBson::Timestamp(ts) => RawBson::Timestamp(*ts), - OwnedRawBson::Binary(b) => RawBson::Binary(RawBinary { - bytes: b.bytes.as_slice(), - subtype: b.subtype, - }), - OwnedRawBson::ObjectId(oid) => RawBson::ObjectId(*oid), - OwnedRawBson::DateTime(dt) => RawBson::DateTime(*dt), - OwnedRawBson::Symbol(s) => RawBson::Symbol(s.as_str()), - OwnedRawBson::Decimal128(d) => RawBson::Decimal128(*d), - OwnedRawBson::Undefined => RawBson::Undefined, - OwnedRawBson::MaxKey => RawBson::MaxKey, - OwnedRawBson::MinKey => RawBson::MinKey, - OwnedRawBson::DbPointer(dbp) => RawBson::DbPointer(RawDbPointer { - namespace: dbp.namespace.as_str(), - id: dbp.id, - }), - } - } -} - -impl From for OwnedRawBson { - fn from(i: i32) -> Self { - OwnedRawBson::Int32(i) - } -} - -impl From for OwnedRawBson { - fn from(i: i64) -> Self { - OwnedRawBson::Int64(i) - } -} - -impl From for OwnedRawBson { - fn from(s: String) -> Self { - OwnedRawBson::String(s) - } -} - -impl From<&str> for OwnedRawBson { - fn from(s: &str) -> Self { - OwnedRawBson::String(s.to_owned()) - } -} - -impl From for OwnedRawBson { - fn from(f: f64) -> Self { - OwnedRawBson::Double(f) - } -} - -impl From for OwnedRawBson { - fn from(b: bool) -> Self { - OwnedRawBson::Boolean(b) - } -} - -impl From for OwnedRawBson { - fn from(d: RawDocumentBuf) -> Self { - OwnedRawBson::Document(d) - } -} - -impl From for OwnedRawBson { - fn from(a: RawArrayBuf) -> Self { - OwnedRawBson::Array(a) - } -} - -impl From for OwnedRawBson { - fn from(dt: crate::DateTime) -> Self { - OwnedRawBson::DateTime(dt) - } -} - -impl From for OwnedRawBson { - fn from(ts: Timestamp) -> Self { - OwnedRawBson::Timestamp(ts) - } -} - -impl From for OwnedRawBson { - fn from(oid: ObjectId) -> Self { - OwnedRawBson::ObjectId(oid) - } -} - -impl From for OwnedRawBson { - fn from(d: Decimal128) -> Self { - OwnedRawBson::Decimal128(d) - } -} - -impl From for OwnedRawBson { - fn from(code_w_scope: OwnedRawJavaScriptCodeWithScope) -> Self { - OwnedRawBson::JavaScriptCodeWithScope(code_w_scope) - } -} - -impl From for OwnedRawBson { - fn from(b: Binary) -> Self { - OwnedRawBson::Binary(b) - } -} - -impl From for OwnedRawBson { - fn from(re: Regex) -> Self { - OwnedRawBson::RegularExpression(re) - } -} - -impl From for OwnedRawBson { - fn from(d: DbPointer) -> Self { - OwnedRawBson::DbPointer(d) - } -} - -impl<'de> Deserialize<'de> for OwnedRawBson { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - match deserializer - .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? - { - OwnedOrBorrowedRawBson::Owned(o) => Ok(o), - OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_owned_raw_bson()), - } - } -} - -impl Serialize for OwnedRawBson { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - self.as_raw_bson().serialize(serializer) - } -} - -impl<'a> TryFrom for Bson { - type Error = Error; - - fn try_from(rawbson: OwnedRawBson) -> Result { - Ok(match rawbson { - OwnedRawBson::Double(d) => Bson::Double(d), - OwnedRawBson::String(s) => Bson::String(s), - OwnedRawBson::Document(rawdoc) => Bson::Document(rawdoc.as_ref().try_into()?), - OwnedRawBson::Array(rawarray) => Bson::Array(rawarray.as_ref().try_into()?), - OwnedRawBson::Binary(rawbson) => Bson::Binary(rawbson), - OwnedRawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), - OwnedRawBson::Boolean(rawbson) => Bson::Boolean(rawbson), - OwnedRawBson::DateTime(rawbson) => Bson::DateTime(rawbson), - OwnedRawBson::Null => Bson::Null, - OwnedRawBson::RegularExpression(rawregex) => Bson::RegularExpression(rawregex), - OwnedRawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson), - OwnedRawBson::Int32(rawbson) => Bson::Int32(rawbson), - OwnedRawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), - OwnedRawBson::Int64(rawbson) => Bson::Int64(rawbson), - OwnedRawBson::Undefined => Bson::Undefined, - OwnedRawBson::DbPointer(rawbson) => Bson::DbPointer(rawbson), - OwnedRawBson::Symbol(rawbson) => Bson::Symbol(rawbson), - OwnedRawBson::JavaScriptCodeWithScope(rawbson) => { - Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope { - code: rawbson.code, - scope: rawbson.scope.try_into()?, - }) - } - OwnedRawBson::Decimal128(rawbson) => Bson::Decimal128(rawbson), - OwnedRawBson::MaxKey => Bson::MaxKey, - OwnedRawBson::MinKey => Bson::MinKey, - }) - } -} - -/// A BSON "code with scope" value backed by owned raw BSON. -#[derive(Debug, Clone, PartialEq)] -pub struct OwnedRawJavaScriptCodeWithScope { - /// The code value. - pub code: String, - - /// The scope document. - pub scope: RawDocumentBuf, -} - -impl<'de> Deserialize<'de> for OwnedRawJavaScriptCodeWithScope { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - match OwnedRawBson::deserialize(deserializer)? { - OwnedRawBson::JavaScriptCodeWithScope(b) => Ok(b), - c => Err(serde::de::Error::custom(format!( - "expected CodeWithScope, but got {:?} instead", - c - ))), - } - } -} - -impl Serialize for OwnedRawJavaScriptCodeWithScope { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - let raw = RawJavaScriptCodeWithScope { - code: self.code.as_str(), - scope: self.scope.as_ref(), - }; - - raw.serialize(serializer) - } -} diff --git a/src/raw/serde.rs b/src/raw/serde.rs index 3439801c..246a422c 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -7,7 +7,7 @@ use crate::{ de::convert_unsigned_to_signed_raw, extjson, oid::ObjectId, - raw::{OwnedRawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, + raw::{RawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, Binary, DateTime, @@ -15,26 +15,26 @@ use crate::{ Decimal128, RawArray, RawArrayBuf, - RawBinary, - RawBson, - RawDbPointer, + RawBinaryRef, + RawBsonRef, + RawDbPointerRef, RawDocument, RawDocumentBuf, - RawJavaScriptCodeWithScope, - RawRegex, + RawJavaScriptCodeWithScopeRef, + RawRegexRef, Regex, Timestamp, }; -use super::{owned_bson::OwnedRawBson, RAW_BSON_NEWTYPE}; +use super::{bson::RawBson, RAW_BSON_NEWTYPE}; /// A raw BSON value that may either be borrowed or owned. /// /// This is used to consolidate the `Serialize` and `Deserialize` implementations for /// `RawBson` and `OwnedRawBson`. pub(crate) enum OwnedOrBorrowedRawBson<'a> { - Owned(OwnedRawBson), - Borrowed(RawBson<'a>), + Owned(RawBson), + Borrowed(RawBsonRef<'a>), } impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawBson<'a> { @@ -55,14 +55,14 @@ impl<'a> Debug for OwnedOrBorrowedRawBson<'a> { } } -impl<'a> From> for OwnedOrBorrowedRawBson<'a> { - fn from(b: RawBson<'a>) -> Self { +impl<'a> From> for OwnedOrBorrowedRawBson<'a> { + fn from(b: RawBsonRef<'a>) -> Self { OwnedOrBorrowedRawBson::Borrowed(b) } } -impl<'a> From for OwnedOrBorrowedRawBson<'a> { - fn from(b: OwnedRawBson) -> Self { +impl<'a> From for OwnedOrBorrowedRawBson<'a> { + fn from(b: RawBson) -> Self { OwnedOrBorrowedRawBson::Owned(b) } } @@ -96,20 +96,20 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> { match deserializer .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { - OwnedOrBorrowedRawBson::Borrowed(RawBson::Document(d)) => Ok(Self::Borrowed(d)), - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Document(d)) => Ok(Self::Owned(d)), + OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Document(d)) => Ok(Self::Borrowed(d)), + OwnedOrBorrowedRawBson::Owned(RawBson::Document(d)) => Ok(Self::Owned(d)), // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializier will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b)) if b.subtype == BinarySubtype::Generic => { Ok(Self::Borrowed( RawDocument::from_bytes(b.bytes).map_err(serde::de::Error::custom)?, )) } - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) + OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { Ok(Self::Owned( @@ -149,19 +149,19 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> { match deserializer .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { - OwnedOrBorrowedRawBson::Borrowed(RawBson::Array(d)) => Ok(Self::Borrowed(d)), - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Array(d)) => Ok(Self::Owned(d)), + OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Array(d)) => Ok(Self::Borrowed(d)), + OwnedOrBorrowedRawBson::Owned(RawBson::Array(d)) => Ok(Self::Owned(d)), // For non-BSON formats, RawArray gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializier will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. - OwnedOrBorrowedRawBson::Borrowed(RawBson::Binary(b)) + OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b)) if b.subtype == BinarySubtype::Generic => { let doc = RawDocument::from_bytes(b.bytes).map_err(serde::de::Error::custom)?; Ok(Self::Borrowed(RawArray::from_doc(doc))) } - OwnedOrBorrowedRawBson::Owned(OwnedRawBson::Binary(b)) + OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?; @@ -190,28 +190,28 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { where E: serde::de::Error, { - Ok(RawBson::String(v).into()) + Ok(RawBsonRef::String(v).into()) } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { - Ok(OwnedRawBson::String(v.to_string()).into()) + Ok(RawBson::String(v.to_string()).into()) } fn visit_string(self, v: String) -> Result where E: serde::de::Error, { - Ok(OwnedRawBson::String(v).into()) + Ok(RawBson::String(v).into()) } fn visit_borrowed_bytes(self, bytes: &'de [u8]) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Binary(RawBinary { + Ok(RawBsonRef::Binary(RawBinaryRef { bytes, subtype: BinarySubtype::Generic, }) @@ -222,28 +222,28 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { where E: serde::de::Error, { - Ok(RawBson::Int32(v.into()).into()) + Ok(RawBsonRef::Int32(v.into()).into()) } fn visit_i16(self, v: i16) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Int32(v.into()).into()) + Ok(RawBsonRef::Int32(v.into()).into()) } fn visit_i32(self, v: i32) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Int32(v).into()) + Ok(RawBsonRef::Int32(v).into()) } fn visit_i64(self, v: i64) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Int64(v).into()) + Ok(RawBsonRef::Int64(v).into()) } fn visit_u8(self, value: u8) -> std::result::Result @@ -278,28 +278,28 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { where E: serde::de::Error, { - Ok(RawBson::Boolean(v).into()) + Ok(RawBsonRef::Boolean(v).into()) } fn visit_f64(self, v: f64) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Double(v).into()) + Ok(RawBsonRef::Double(v).into()) } fn visit_none(self) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Null.into()) + Ok(RawBsonRef::Null.into()) } fn visit_unit(self) -> std::result::Result where E: serde::de::Error, { - Ok(RawBson::Null.into()) + Ok(RawBsonRef::Null.into()) } fn visit_newtype_struct(self, deserializer: D) -> std::result::Result @@ -313,7 +313,7 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { where E: serde::de::Error, { - Ok(OwnedRawBson::Binary(Binary { + Ok(RawBson::Binary(Binary { bytes: v, subtype: BinarySubtype::Generic, }) @@ -325,10 +325,10 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { A: serde::de::SeqAccess<'de>, { let mut array = RawArrayBuf::new(); - while let Some(v) = seq.next_element::()? { + while let Some(v) = seq.next_element::()? { array.push(v); } - Ok(OwnedRawBson::Array(array).into()) + Ok(RawBson::Array(array).into()) } fn visit_map(self, mut map: A) -> std::result::Result @@ -346,36 +346,38 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { A: serde::de::MapAccess<'de>, { let mut doc = RawDocumentBuf::new(); - let v: OwnedRawBson = map.next_value()?; + let v: RawBson = map.next_value()?; doc.append(first_key, v); - while let Some((k, v)) = map.next_entry::()? { + while let Some((k, v)) = map.next_entry::()? { doc.append(k, v); } - Ok(OwnedRawBson::Document(doc).into()) + Ok(RawBson::Document(doc).into()) } let k = match map.next_key::()? { Some(k) => k, - None => return Ok(OwnedRawBson::Document(RawDocumentBuf::new()).into()), + None => return Ok(RawBson::Document(RawDocumentBuf::new()).into()), }; match k.0.as_ref() { "$oid" => { let oid: ObjectId = map.next_value()?; - Ok(RawBson::ObjectId(oid).into()) + Ok(RawBsonRef::ObjectId(oid).into()) } "$symbol" => { let s: CowStr = map.next_value()?; match s.0 { - Cow::Borrowed(s) => Ok(RawBson::Symbol(s).into()), - Cow::Owned(s) => Ok(OwnedRawBson::Symbol(s).into()), + Cow::Borrowed(s) => Ok(RawBsonRef::Symbol(s).into()), + Cow::Owned(s) => Ok(RawBson::Symbol(s).into()), } } "$numberDecimalBytes" => { let bytes = map.next_value::()?; - return Ok(RawBson::Decimal128(Decimal128::deserialize_from_slice(&bytes)?).into()); + return Ok( + RawBsonRef::Decimal128(Decimal128::deserialize_from_slice(&bytes)?).into(), + ); } "$regularExpression" => { #[derive(Debug, Deserialize)] @@ -390,13 +392,13 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { match (body.pattern, body.options) { (Cow::Borrowed(p), Cow::Borrowed(o)) => { - Ok(RawBson::RegularExpression(RawRegex { + Ok(RawBsonRef::RegularExpression(RawRegexRef { pattern: p, options: o, }) .into()) } - (p, o) => Ok(OwnedRawBson::RegularExpression(Regex { + (p, o) => Ok(RawBson::RegularExpression(Regex { pattern: p.into_owned(), options: o.into_owned(), }) @@ -405,7 +407,7 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { } "$undefined" => { let _: bool = map.next_value()?; - Ok(RawBson::Undefined.into()) + Ok(RawBsonRef::Undefined.into()) } "$binary" => { #[derive(Debug, Deserialize)] @@ -420,13 +422,13 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let v = map.next_value::()?; if let Cow::Borrowed(bytes) = v.bytes { - Ok(RawBson::Binary(RawBinary { + Ok(RawBsonRef::Binary(RawBinaryRef { bytes, subtype: v.subtype.into(), }) .into()) } else { - Ok(OwnedRawBson::Binary(Binary { + Ok(RawBson::Binary(Binary { bytes: v.bytes.into_owned(), subtype: v.subtype.into(), }) @@ -435,11 +437,11 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { } "$date" => { let v = map.next_value::()?; - Ok(RawBson::DateTime(DateTime::from_millis(v)).into()) + Ok(RawBsonRef::DateTime(DateTime::from_millis(v)).into()) } "$timestamp" => { let v = map.next_value::()?; - Ok(RawBson::Timestamp(Timestamp { + Ok(RawBsonRef::Timestamp(Timestamp { time: v.t, increment: v.i, }) @@ -447,11 +449,11 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { } "$minKey" => { let _ = map.next_value::()?; - Ok(RawBson::MinKey.into()) + Ok(RawBsonRef::MinKey.into()) } "$maxKey" => { let _ = map.next_value::()?; - Ok(RawBson::MaxKey.into()) + Ok(RawBsonRef::MaxKey.into()) } "$code" => { let code = map.next_value::()?; @@ -460,16 +462,13 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let scope = map.next_value::()?; match (code.0, scope) { (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => { - Ok( - RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { - code, - scope, - }) - .into(), + Ok(RawBsonRef::JavaScriptCodeWithScope( + RawJavaScriptCodeWithScopeRef { code, scope }, ) + .into()) } - (code, scope) => Ok(OwnedRawBson::JavaScriptCodeWithScope( - OwnedRawJavaScriptCodeWithScope { + (code, scope) => Ok(RawBson::JavaScriptCodeWithScope( + RawJavaScriptCodeWithScope { code: code.into_owned(), scope: scope.into_owned(), }, @@ -480,9 +479,9 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { Err(serde::de::Error::unknown_field(&key.0, &["$scope"])) } } else if let Cow::Borrowed(code) = code.0 { - Ok(RawBson::JavaScriptCode(code).into()) + Ok(RawBsonRef::JavaScriptCode(code).into()) } else { - Ok(OwnedRawBson::JavaScriptCode(code.0.into_owned()).into()) + Ok(RawBson::JavaScriptCode(code.0.into_owned()).into()) } } "$dbPointer" => { @@ -498,13 +497,13 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let body: BorrowedDbPointerBody = map.next_value()?; if let Cow::Borrowed(ns) = body.ns.0 { - Ok(RawBson::DbPointer(RawDbPointer { + Ok(RawBsonRef::DbPointer(RawDbPointerRef { namespace: ns, id: body.id, }) .into()) } else { - Ok(OwnedRawBson::DbPointer(DbPointer { + Ok(RawBson::DbPointer(DbPointer { namespace: body.ns.0.into_owned(), id: body.id, }) @@ -514,12 +513,12 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { RAW_DOCUMENT_NEWTYPE => { let bson = map.next_value::<&[u8]>()?; let doc = RawDocument::from_bytes(bson).map_err(serde::de::Error::custom)?; - Ok(RawBson::Document(doc).into()) + Ok(RawBsonRef::Document(doc).into()) } RAW_ARRAY_NEWTYPE => { let bson = map.next_value::<&[u8]>()?; let doc = RawDocument::from_bytes(bson).map_err(serde::de::Error::custom)?; - Ok(RawBson::Array(RawArray::from_doc(doc)).into()) + Ok(RawBsonRef::Array(RawArray::from_doc(doc)).into()) } k => build_doc(k, map), } diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs index 3e27e88b..a8a0307b 100644 --- a/src/raw/test/append.rs +++ b/src/raw/test/append.rs @@ -2,7 +2,7 @@ use std::iter::FromIterator; use crate::{ oid::ObjectId, - raw::OwnedRawJavaScriptCodeWithScope, + raw::RawJavaScriptCodeWithScope, spec::BinarySubtype, tests::LOCK, Binary, @@ -12,8 +12,8 @@ use crate::{ Decimal128, Document, JavaScriptCodeWithScope, - OwnedRawBson, RawArrayBuf, + RawBson, RawDocumentBuf, Regex, Timestamp, @@ -108,7 +108,7 @@ fn null() { "null": null, }; append_test(expected, |doc| { - doc.append("null", OwnedRawBson::Null); + doc.append("null", RawBson::Null); }); } @@ -230,8 +230,8 @@ fn min_max_key() { }; append_test(expected, |doc| { - doc.append("min", OwnedRawBson::MinKey); - doc.append("max", OwnedRawBson::MaxKey); + doc.append("min", RawBson::MinKey); + doc.append("max", RawBson::MaxKey); }); } @@ -242,7 +242,7 @@ fn undefined() { }; append_test(expected, |doc| { - doc.append("undefined", OwnedRawBson::Undefined); + doc.append("undefined", RawBson::Undefined); }); } @@ -270,17 +270,14 @@ fn code() { }; append_test(expected, |doc| { - doc.append( - "code", - OwnedRawBson::JavaScriptCode("some code".to_string()), - ); + doc.append("code", RawBson::JavaScriptCode("some code".to_string())); let mut scope = RawDocumentBuf::new(); scope.append("a", 1_i32); scope.append("b", true); doc.append( "code_w_scope", - OwnedRawJavaScriptCodeWithScope { + RawJavaScriptCodeWithScope { code: "some code".to_string(), scope, }, @@ -295,7 +292,7 @@ fn symbol() { }; append_test(expected, |doc| { - doc.append("symbol", OwnedRawBson::Symbol("symbol".to_string())); + doc.append("symbol", RawBson::Symbol("symbol".to_string())); }); } @@ -315,7 +312,7 @@ fn dbpointer() { append_test(expected, |doc| { doc.append( "symbol", - OwnedRawBson::DbPointer(DbPointer { + RawBson::DbPointer(DbPointer { namespace: "ns".to_string(), id, }), @@ -386,16 +383,16 @@ fn from_iter() { let doc_buf = RawDocumentBuf::from_iter([ ( "array", - OwnedRawBson::Array(RawArrayBuf::from_iter([ - OwnedRawBson::Boolean(true), - OwnedRawBson::Document(RawDocumentBuf::from_iter([ - ("ok", OwnedRawBson::Boolean(false)), - ("other", OwnedRawBson::String("hello".to_string())), + RawBson::Array(RawArrayBuf::from_iter([ + RawBson::Boolean(true), + RawBson::Document(RawDocumentBuf::from_iter([ + ("ok", RawBson::Boolean(false)), + ("other", RawBson::String("hello".to_string())), ])), ])), ), - ("bool", OwnedRawBson::Boolean(true)), - ("string", OwnedRawBson::String("some string".to_string())), + ("bool", RawBson::Boolean(true)), + ("string", RawBson::String("some string".to_string())), ]); let doc = doc! { diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index 40b64617..d9460fde 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -198,7 +198,7 @@ fn binary() { "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] } }) .unwrap(); - let binary: bson::RawBinary<'_> = rawdoc + let binary: bson_ref::RawBinaryRef<'_> = rawdoc .get("binary") .expect("error finding key binary") .expect("no key binary") @@ -440,7 +440,7 @@ fn into_bson_conversion() { "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] }, "boolean": false, }); - let rawbson = RawBson::Document(RawDocument::from_bytes(docbytes.as_slice()).unwrap()); + let rawbson = RawBsonRef::Document(RawDocument::from_bytes(docbytes.as_slice()).unwrap()); let b: Bson = rawbson.try_into().expect("invalid bson"); let doc = b.as_document().expect("not a document"); assert_eq!(*doc.get("f64").expect("f64 not found"), Bson::Double(2.5)); diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs index be120cc4..ad4d0812 100644 --- a/src/ser/raw/value_serializer.rs +++ b/src/ser/raw/value_serializer.rs @@ -11,7 +11,7 @@ use crate::{ ser::{write_binary, write_cstring, write_i32, write_i64, write_string, Error, Result}, spec::{BinarySubtype, ElementType}, RawDocument, - RawJavaScriptCodeWithScope, + RawJavaScriptCodeWithScopeRef, }; use super::{document_serializer::DocumentSerializer, Serializer}; @@ -308,7 +308,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> { Ok(()) } SerializationStep::CodeWithScopeScope { ref code, raw } if raw => { - let raw = RawJavaScriptCodeWithScope { + let raw = RawJavaScriptCodeWithScopeRef { code, scope: RawDocument::from_bytes(v).map_err(Error::custom)?, }; diff --git a/src/ser/serde.rs b/src/ser/serde.rs index b8452e60..1b4b5b43 100644 --- a/src/ser/serde.rs +++ b/src/ser/serde.rs @@ -17,7 +17,7 @@ use crate::{ datetime::DateTime, extjson, oid::ObjectId, - raw::{RawDbPointer, RawRegex, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, + raw::{RawDbPointerRef, RawRegexRef, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, uuid::UUID_NEWTYPE_NAME, Binary, @@ -648,7 +648,7 @@ impl Serialize for Regex { where S: ser::Serializer, { - let raw = RawRegex { + let raw = RawRegexRef { pattern: self.pattern.as_str(), options: self.options.as_str(), }; @@ -720,7 +720,7 @@ impl Serialize for DbPointer { where S: ser::Serializer, { - let raw = RawDbPointer { + let raw = RawDbPointerRef { namespace: self.namespace.as_str(), id: self.id, }; diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs index 0a555226..41159cd6 100644 --- a/src/tests/spec/corpus.rs +++ b/src/tests/spec/corpus.rs @@ -6,11 +6,11 @@ use std::{ }; use crate::{ - raw::{RawBson, RawDocument}, + raw::{RawBsonRef, RawDocument}, tests::LOCK, Bson, Document, - OwnedRawBson, + RawBson, RawDocumentBuf, }; use pretty_assertions::assert_eq; @@ -121,13 +121,14 @@ fn run_test(test: TestFile) { let document_from_raw_document: Document = canonical_raw_document.try_into().expect(&description); - let canonical_raw_bson_from_slice = crate::from_slice::(canonical_bson.as_slice()) - .expect(&description) - .as_document() - .expect(&description); + let canonical_raw_bson_from_slice = + crate::from_slice::(canonical_bson.as_slice()) + .expect(&description) + .as_document() + .expect(&description); let canonical_owned_raw_bson_from_slice = - crate::from_slice::(canonical_bson.as_slice()).expect(&description); + crate::from_slice::(canonical_bson.as_slice()).expect(&description); let canonical_raw_document_from_slice = crate::from_slice::<&RawDocument>(canonical_bson.as_slice()).expect(&description); @@ -177,7 +178,7 @@ fn run_test(test: TestFile) { let mut deserializer_raw = crate::de::RawDeserializer::new(canonical_bson.as_slice(), false); let raw_bson_field = deserializer_raw - .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) + .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) .expect(&description); // convert to an owned Bson and put into a Document let bson: Bson = raw_bson_field.try_into().expect(&description); @@ -189,7 +190,7 @@ fn run_test(test: TestFile) { let mut deserializer_raw = crate::de::RawDeserializer::new(canonical_bson.as_slice(), false); let owned_raw_bson_field = deserializer_raw - .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) + .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::)) .expect(&description); let from_slice_owned_vec = RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_bytes(); From 426192222c0567ed6864f1717d6ecbc21e11124f Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Tue, 30 Nov 2021 17:47:51 -0500 Subject: [PATCH 21/21] refactor `as_raw_bson` -> `as_raw_bson_ref` --- src/raw/bson.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/raw/bson.rs b/src/raw/bson.rs index abe896d4..05f4dfc6 100644 --- a/src/raw/bson.rs +++ b/src/raw/bson.rs @@ -286,8 +286,8 @@ impl RawBson { } } - /// Gets a [`RawBson`] value referencing this owned raw BSON value. - pub fn as_raw_bson(&self) -> RawBsonRef<'_> { + /// Gets a [`RawBsonRef`] value referencing this owned raw BSON value. + pub fn as_raw_bson_ref(&self) -> RawBsonRef<'_> { match self { RawBson::Double(d) => RawBsonRef::Double(*d), RawBson::String(s) => RawBsonRef::String(s.as_str()), @@ -443,7 +443,7 @@ impl Serialize for RawBson { where S: serde::Serializer, { - self.as_raw_bson().serialize(serializer) + self.as_raw_bson_ref().serialize(serializer) } }