diff --git a/src/bson.rs b/src/bson.rs index 28799103..bc9f2156 100644 --- a/src/bson.rs +++ b/src/bson.rs @@ -1050,7 +1050,10 @@ impl Display for Regex { /// Represents a BSON code with scope value. #[derive(Debug, Clone, PartialEq)] pub struct JavaScriptCodeWithScope { + /// The JavaScript code. pub code: String, + + /// The scope document containing variable bindings. pub scope: Document, } diff --git a/src/raw/array.rs b/src/raw/array.rs index 22c04251..a77002ec 100644 --- a/src/raw/array.rs +++ b/src/raw/array.rs @@ -212,6 +212,11 @@ impl RawArray { pub fn as_bytes(&self) -> &[u8] { self.doc.as_bytes() } + + /// Whether this array contains any elements or not. + pub fn is_empty(&self) -> bool { + self.doc.is_empty() + } } impl std::fmt::Debug for RawArray { diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs index c12405d3..c27ff939 100644 --- a/src/raw/bson_ref.rs +++ b/src/raw/bson_ref.rs @@ -533,20 +533,17 @@ impl<'a> From<&'a Binary> for RawBsonRef<'a> { /// 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 - } + /// The regex pattern to match. + pub pattern: &'a str, - /// Gets the options portion of the regex. - pub fn options(self) -> &'a str { - self.options - } + /// The options for the regex. + /// + /// Options are identified by characters, which must be stored in + /// alphabetical order. Valid options are 'i' for case insensitive matching, 'm' for + /// multiline matching, 'x' for verbose mode, 'l' to make \w, \W, etc. locale dependent, + /// 's' for dotall mode ('.' matches everything), and 'u' to make \w, \W, etc. match + /// unicode. + pub options: &'a str, } impl<'de: 'a, 'a> Deserialize<'de> for RawRegexRef<'a> { @@ -594,22 +591,14 @@ impl<'a> From> for RawBsonRef<'a> { /// 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, + /// The JavaScript code. + pub code: &'a str, - pub(crate) scope: &'a RawDocument, + /// The scope document containing variable bindings. + pub 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 } diff --git a/src/raw/document.rs b/src/raw/document.rs index 3bc6f2ab..fb5f86dc 100644 --- a/src/raw/document.rs +++ b/src/raw/document.rs @@ -6,6 +6,7 @@ use std::{ use serde::{ser::SerializeMap, Deserialize, Serialize}; use crate::{ + de::MIN_BSON_DOCUMENT_SIZE, raw::{error::ErrorKind, serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE}, DateTime, Timestamp, @@ -398,8 +399,8 @@ impl RawDocument { /// "bool": true, /// }; /// - /// assert_eq!(doc.get_regex("regex")?.pattern(), r"end\s*$"); - /// assert_eq!(doc.get_regex("regex")?.options(), "i"); + /// assert_eq!(doc.get_regex("regex")?.pattern, r"end\s*$"); + /// assert_eq!(doc.get_regex("regex")?.options, "i"); /// assert!(matches!(doc.get_regex("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_regex("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) @@ -486,6 +487,11 @@ impl RawDocument { pub fn as_bytes(&self) -> &[u8] { &self.data } + + /// Returns whether this document contains any elements or not. + pub fn is_empty(&self) -> bool { + self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize + } } impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index b7742522..5c25afe8 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -70,7 +70,8 @@ pub struct RawDocumentBuf { impl RawDocumentBuf { /// Creates a new, empty [`RawDocumentBuf`]. pub fn new() -> RawDocumentBuf { - let mut data: Vec = MIN_BSON_DOCUMENT_SIZE.to_le_bytes().to_vec(); + let mut data = Vec::new(); + data.extend(&MIN_BSON_DOCUMENT_SIZE.to_le_bytes()); data.push(0); Self { data } } @@ -192,19 +193,19 @@ impl RawDocumentBuf { /// 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) { + pub fn append(&mut self, key: impl AsRef, value: impl Into) { + fn append_string(doc: &mut RawDocumentBuf, value: &str) { doc.data .extend(&((value.as_bytes().len() + 1) as i32).to_le_bytes()); - doc.data.extend(value.into_bytes()); + doc.data.extend(value.as_bytes()); doc.data.push(0); } - fn append_cstring(doc: &mut RawDocumentBuf, value: String) { + fn append_cstring(doc: &mut RawDocumentBuf, value: &str) { if value.contains('\0') { panic!("cstr includes interior null byte: {}", value) } - doc.data.extend(value.into_bytes()); + doc.data.extend(value.as_bytes()); doc.data.push(0); } @@ -212,7 +213,7 @@ 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_cstring(self, key.into()); + append_cstring(self, key.as_ref()); let value = value.into(); let element_type = value.element_type(); @@ -222,7 +223,7 @@ impl RawDocumentBuf { self.data.extend(&i.to_le_bytes()); } RawBson::String(s) => { - append_string(self, s); + append_string(self, s.as_str()); } RawBson::Document(d) => { self.data.extend(d.into_bytes()); @@ -251,7 +252,7 @@ impl RawDocumentBuf { self.data.extend(&dt.timestamp_millis().to_le_bytes()); } RawBson::DbPointer(dbp) => { - append_string(self, dbp.namespace); + append_string(self, dbp.namespace.as_str()); self.data.extend(&dbp.id.bytes()); } RawBson::Decimal128(d) => { @@ -264,11 +265,11 @@ impl RawDocumentBuf { self.data.extend(&i.to_le_bytes()); } RawBson::RegularExpression(re) => { - append_cstring(self, re.pattern); - append_cstring(self, re.options); + append_cstring(self, re.pattern.as_str()); + append_cstring(self, re.options.as_str()); } RawBson::JavaScriptCode(js) => { - append_string(self, js); + append_string(self, js.as_str()); } RawBson::JavaScriptCodeWithScope(code_w_scope) => { let len = RawJavaScriptCodeWithScopeRef { @@ -277,7 +278,7 @@ impl RawDocumentBuf { } .len(); self.data.extend(&len.to_le_bytes()); - append_string(self, code_w_scope.code); + append_string(self, code_w_scope.code.as_str()); self.data.extend(code_w_scope.scope.into_bytes()); } RawBson::Timestamp(ts) => { @@ -287,7 +288,7 @@ impl RawDocumentBuf { self.data.extend(&oid.bytes()); } RawBson::Symbol(s) => { - append_string(self, s); + append_string(self, s.as_str()); } RawBson::Null | RawBson::Undefined | RawBson::MinKey | RawBson::MaxKey => {} } @@ -296,8 +297,8 @@ impl RawDocumentBuf { // append trailing null byte self.data.push(0); // update length - self.data - .splice(0..4, (self.data.len() as i32).to_le_bytes().iter().cloned()); + let new_len = (self.data.len() as i32).to_le_bytes(); + self.data[0..4].copy_from_slice(&new_len); } /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error @@ -389,7 +390,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/serde.rs b/src/raw/serde.rs index 246a422c..e13ffdd7 100644 --- a/src/raw/serde.rs +++ b/src/raw/serde.rs @@ -349,8 +349,8 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { let v: RawBson = map.next_value()?; doc.append(first_key, v); - while let Some((k, v)) = map.next_entry::()? { - doc.append(k, v); + while let Some((k, v)) = map.next_entry::()? { + doc.append(k.0, v); } Ok(RawBson::Document(doc).into()) diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs index 0042b6e2..22a065c4 100644 --- a/src/raw/test/mod.rs +++ b/src/raw/test/mod.rs @@ -310,9 +310,9 @@ fn javascript_with_scope() { .expect("no key javascript_with_scope") .as_javascript_with_scope() .expect("was not javascript with scope"); - assert_eq!(js_with_scope.code(), "console.log(msg);"); + assert_eq!(js_with_scope.code, "console.log(msg);"); let (scope_key, scope_value_bson) = js_with_scope - .scope() + .scope .into_iter() .next() .expect("no next value in scope") diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs index bc178f76..64829d4a 100644 --- a/src/ser/raw/mod.rs +++ b/src/ser/raw/mod.rs @@ -97,8 +97,8 @@ impl Serializer { /// Replace an i32 value at the given index with the given value. #[inline] fn replace_i32(&mut self, at: usize, with: i32) { - self.bytes - .splice(at..at + 4, with.to_le_bytes().iter().cloned()); + let portion = &mut self.bytes[at..at + 4]; + portion.copy_from_slice(&with.to_le_bytes()); } }