From bd21803de415ff816c48990d31a809c7d5d26a8d Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Fri, 3 Jun 2022 16:06:11 -0400
Subject: [PATCH 001/156] release v2.3.0

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 04579c38..965a507d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.0.0"
+version = "2.3.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index 64537d64..e7836902 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.0.0"
+bson = "2.3.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 425c5422..8d856fee 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.0.0"
+//! bson = "2.3.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in
@@ -264,7 +264,7 @@
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity)]
-#![doc(html_root_url = "https://docs.rs/bson/2.0.0")]
+#![doc(html_root_url = "https://docs.rs/bson/2.3.0")]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 
 #[doc(inline)]

From 90c4e24219bff31aac2224eaf82c7ef6a70ea44d Mon Sep 17 00:00:00 2001
From: Sana Verma <sanyaverma0303@gmail.com>
Date: Fri, 10 Jun 2022 14:47:44 -0400
Subject: [PATCH 002/156] RUST-1252 change docs.mongodb.com links for seo
 (#360)

---
 src/bson.rs        |  8 ++++----
 src/datetime.rs    |  2 +-
 src/extjson/de.rs  | 10 +++++-----
 src/extjson/mod.rs |  4 ++--
 src/oid.rs         |  2 +-
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/bson.rs b/src/bson.rs
index 0bb825e0..e22b08bd 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -364,7 +364,7 @@ where
     }
 }
 
-/// This will create the [relaxed Extended JSON v2](https://docs.mongodb.com/manual/reference/mongodb-extended-json/) representation of the provided [`Bson`](../enum.Bson.html).
+/// This will create the [relaxed Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) representation of the provided [`Bson`](../enum.Bson.html).
 impl From<Bson> for Value {
     fn from(bson: Bson) -> Self {
         bson.into_relaxed_extjson()
@@ -372,7 +372,7 @@ impl From<Bson> for Value {
 }
 
 impl Bson {
-    /// Converts the Bson value into its [relaxed extended JSON representation](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+    /// Converts the Bson value into its [relaxed extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
     ///
     /// Note: If this method is called on a case which contains a `Decimal128` value, it will panic.
     pub fn into_relaxed_extjson(self) -> Value {
@@ -465,7 +465,7 @@ impl Bson {
         }
     }
 
-    /// Converts the Bson value into its [canonical extended JSON representation](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+    /// Converts the Bson value into its [canonical extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
     ///
     /// Note: extended json encoding for `Decimal128` values is not supported. If this method is
     /// called on a case which contains a `Decimal128` value, it will panic.
@@ -534,7 +534,7 @@ impl Bson {
     }
 
     /// Converts to extended format.
-    /// This function mainly used for [extended JSON format](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+    /// This function mainly used for [extended JSON format](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
     // TODO RUST-426: Investigate either removing this from the serde implementation or unifying
     // with the extended JSON implementation.
     pub(crate) fn into_extended_document(self, rawbson: bool) -> Document {
diff --git a/src/datetime.rs b/src/datetime.rs
index 33cb55db..b6419de8 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -44,7 +44,7 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
 /// BSON datetime rather than an RFC 3339 formatted string. Additionally, in non-BSON formats, it
 /// will serialize to and deserialize from that format's equivalent of the
-/// [extended JSON representation](https://docs.mongodb.com/manual/reference/mongodb-extended-json/) of a datetime.
+/// [extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) of a datetime.
 /// To serialize a [`chrono::DateTime`] as a BSON datetime, you can use
 /// [`crate::serde_helpers::chrono_datetime_as_bson_datetime`].
 ///
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
index 90fc07df..0b97dd42 100644
--- a/src/extjson/de.rs
+++ b/src/extjson/de.rs
@@ -1,4 +1,4 @@
-//! Deserializing [MongoDB Extended JSON v2](https://docs.mongodb.com/manual/reference/mongodb-extended-json/)
+//! Deserializing [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
 //!
 //! ## Usage
 //!
@@ -29,7 +29,7 @@ use crate::{extjson::models, oid, Bson, Document};
 
 #[derive(Clone, Debug)]
 #[non_exhaustive]
-/// Error cases that can occur during deserialization from [extended JSON](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+/// Error cases that can occur during deserialization from [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 pub enum Error {
     /// Errors that can occur during OID construction and generation from the input data.
     InvalidObjectId(oid::Error),
@@ -77,7 +77,7 @@ impl From<oid::Error> for Error {
 
 pub type Result<T> = std::result::Result<T, Error>;
 
-/// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+/// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
     type Error = Error;
 
@@ -172,7 +172,7 @@ impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
     }
 }
 
-/// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+/// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 impl TryFrom<serde_json::Value> for Bson {
     type Error = Error;
 
@@ -207,7 +207,7 @@ impl TryFrom<serde_json::Value> for Bson {
     }
 }
 
-/// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+/// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 impl TryFrom<serde_json::Map<String, serde_json::Value>> for Document {
     type Error = Error;
 
diff --git a/src/extjson/mod.rs b/src/extjson/mod.rs
index 1ad322cd..32e94455 100644
--- a/src/extjson/mod.rs
+++ b/src/extjson/mod.rs
@@ -1,4 +1,4 @@
-//! Deserialization and serialization of [MongoDB Extended JSON v2](https://docs.mongodb.com/manual/reference/mongodb-extended-json/)
+//! Deserialization and serialization of [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
 //!
 //! ## Overview of Extended JSON
 //!
@@ -15,7 +15,7 @@
 //!    }
 //! }
 //! ```
-//! For more information on extJSON and the complete list of translations, see the [official MongoDB documentation](https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
+//! For more information on extJSON and the complete list of translations, see the [official MongoDB documentation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 //!
 //! All MongoDB drivers and BSON libraries interpret and produce extJSON, so it can serve as a
 //! useful tool for communicating between applications where raw BSON bytes cannot be used (e.g. via
diff --git a/src/oid.rs b/src/oid.rs
index 8a884792..037eac86 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -100,7 +100,7 @@ impl From<[u8; 12]> for ObjectId {
 
 impl ObjectId {
     /// Generates a new [`ObjectId`], represented in bytes.
-    /// See the [docs](http://docs.mongodb.org/manual/reference/object-id/)
+    /// See the [docs](http://www.mongodb.com/docs/manual/reference/object-id/)
     /// for more information.
     pub fn new() -> ObjectId {
         let timestamp = ObjectId::gen_timestamp();

From 34dd74f07fc1b20d8cc536f609aab57475082b9e Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 29 Jun 2022 12:05:53 -0400
Subject: [PATCH 003/156] RUST-1374 Pin all dependencies when checking MSRV
 compilation (#364)

---
 .evergreen/Cargo.lock.msrv | 1057 ++++++++++++++++++++++++++++++++++++
 .evergreen/compile-only.sh |    5 +
 .evergreen/config.yml      |    3 +-
 3 files changed, 1064 insertions(+), 1 deletion(-)
 create mode 100644 .evergreen/Cargo.lock.msrv

diff --git a/.evergreen/Cargo.lock.msrv b/.evergreen/Cargo.lock.msrv
new file mode 100644
index 00000000..39a9f2e1
--- /dev/null
+++ b/.evergreen/Cargo.lock.msrv
@@ -0,0 +1,1057 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ahash"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bit-set"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bson"
+version = "2.3.0"
+dependencies = [
+ "ahash",
+ "assert_matches",
+ "base64",
+ "chrono",
+ "criterion",
+ "hex",
+ "indexmap",
+ "lazy_static",
+ "pretty_assertions",
+ "proptest",
+ "rand",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "serde_with",
+ "time",
+ "uuid",
+]
+
+[[package]]
+name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "lazy_static",
+ "memchr",
+ "regex-automata",
+ "serde",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cast"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "libc",
+ "num-integer",
+ "num-traits",
+ "serde",
+ "winapi",
+]
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "bitflags",
+ "textwrap",
+ "unicode-width",
+]
+
+[[package]]
+name = "criterion"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
+dependencies = [
+ "atty",
+ "cast",
+ "clap",
+ "criterion-plot",
+ "csv",
+ "itertools",
+ "lazy_static",
+ "num-traits",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_cbor",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
+dependencies = [
+ "cast",
+ "itertools",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "lazy_static",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
+dependencies = [
+ "cfg-if",
+ "lazy_static",
+]
+
+[[package]]
+name = "csv"
+version = "1.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
+dependencies = [
+ "bstr",
+ "csv-core",
+ "itoa 0.4.7",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ctor"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "darling"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "half"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+
+[[package]]
+name = "hashbrown"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indexmap"
+version = "1.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+
+[[package]]
+name = "itoa"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+
+[[package]]
+name = "js-sys"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.121"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "memoffset"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+
+[[package]]
+name = "oorandom"
+version = "11.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
+
+[[package]]
+name = "output_vt100"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "plotters"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
+dependencies = [
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "plotters-backend"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
+
+[[package]]
+name = "plotters-svg"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
+dependencies = [
+ "plotters-backend",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "pretty_assertions"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
+dependencies = [
+ "ansi_term",
+ "ctor",
+ "difference",
+ "output_vt100",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "proptest"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
+dependencies = [
+ "bit-set",
+ "bitflags",
+ "byteorder",
+ "lazy_static",
+ "num-traits",
+ "quick-error 2.0.1",
+ "rand",
+ "rand_chacha",
+ "rand_xorshift",
+ "regex-syntax",
+ "rusty-fork",
+ "tempfile",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quick-error"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rayon"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+dependencies = [
+ "autocfg",
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
+
+[[package]]
+name = "rusty-fork"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
+dependencies = [
+ "fnv",
+ "quick-error 1.2.3",
+ "tempfile",
+ "wait-timeout",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "semver"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
+
+[[package]]
+name = "serde"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_cbor"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
+dependencies = [
+ "half",
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+dependencies = [
+ "indexmap",
+ "itoa 0.4.7",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3"
+dependencies = [
+ "rustversion",
+ "serde",
+ "serde_with_macros",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "time"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
+dependencies = [
+ "itoa 1.0.2",
+ "libc",
+ "num_threads",
+ "time-macros",
+]
+
+[[package]]
+name = "time-macros"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom",
+ "serde",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
+
+[[package]]
+name = "web-sys"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index d3798d13..bcf17ec4 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -5,4 +5,9 @@ set -o errexit
 . ~/.cargo/env
 rustup update $RUST_VERSION
 
+# pin all dependencies when checking msrv compilation
+if [  "$MSRV" = "true" ]; then
+    cp .evergreen/Cargo.lock.msrv Cargo.lock
+fi
+
 rustup run $RUST_VERSION cargo build
diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index c11f96c8..fc992e4f 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -90,7 +90,7 @@ functions:
         working_dir: "src"
         script: |
           ${PREPARE_SHELL}
-          RUST_VERSION=${RUST_VERSION} .evergreen/compile-only.sh
+          RUST_VERSION=${RUST_VERSION} MSRV=${MSRV} .evergreen/compile-only.sh
 
   "check rustfmt":
     - command: shell.exec
@@ -184,6 +184,7 @@ axes:
         display_name: "1.53 (minimum supported version)"
         variables:
           RUST_VERSION: "1.53.0"
+          MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
         variables:

From 2944e7750d965160a7719162007f58eef0c14a9b Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 1 Jul 2022 15:52:42 -0400
Subject: [PATCH 004/156] RUST-1305 Add support for version 1.x of the `uuid`
 crate to the `bson` crate (#362)

---
 .evergreen/check-clippy.sh         |   6 +-
 .evergreen/check-rustdoc.sh        |   5 +-
 .evergreen/check-rustfmt.sh        |   2 +-
 .evergreen/compile-only.sh         |   2 +-
 .evergreen/install-dependencies.sh |   2 +-
 .evergreen/install-fuzzer.sh       |   2 +-
 .evergreen/run-fuzzer.sh           |   2 +-
 .evergreen/run-tests.sh            |   3 +-
 Cargo.toml                         |   9 +-
 README.md                          |   1 +
 src/bson.rs                        |   8 +
 src/serde_helpers.rs               | 340 +++++++++++++++++++----------
 src/tests/serde.rs                 |  84 ++++++-
 src/uuid/mod.rs                    | 137 ++++++++----
 src/uuid/test.rs                   |  18 +-
 15 files changed, 441 insertions(+), 180 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index 292ba8c5..43699eb4 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -1,8 +1,10 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
 . ~/.cargo/env
+
 cargo clippy --all-targets --all-features -p bson -- -D warnings
 
-cd serde-tests && cargo clippy --all-targets --all-features -p serde-tests -- -D warnings
+cd serde-tests
+cargo clippy --all-targets --all-features -p serde-tests -- -D warnings
diff --git a/.evergreen/check-rustdoc.sh b/.evergreen/check-rustdoc.sh
index 8667cf23..4a5ddd03 100755
--- a/.evergreen/check-rustdoc.sh
+++ b/.evergreen/check-rustdoc.sh
@@ -1,6 +1,7 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
 . ~/.cargo/env
-cargo +nightly rustdoc -p bson --all-features -- --cfg docsrs -D warnings
+
+cargo +nightly rustdoc -p bson --all-features -- --cfg docsrs -D warnings
\ No newline at end of file
diff --git a/.evergreen/check-rustfmt.sh b/.evergreen/check-rustfmt.sh
index 2c8981da..fe7b032c 100755
--- a/.evergreen/check-rustfmt.sh
+++ b/.evergreen/check-rustfmt.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index bcf17ec4..babe64f4 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
diff --git a/.evergreen/install-dependencies.sh b/.evergreen/install-dependencies.sh
index a6b4f669..69b88478 100755
--- a/.evergreen/install-dependencies.sh
+++ b/.evergreen/install-dependencies.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 rm -rf ~/.rustup
 curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path
diff --git a/.evergreen/install-fuzzer.sh b/.evergreen/install-fuzzer.sh
index f798dee6..970e13af 100755
--- a/.evergreen/install-fuzzer.sh
+++ b/.evergreen/install-fuzzer.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
diff --git a/.evergreen/run-fuzzer.sh b/.evergreen/run-fuzzer.sh
index a8f4ce1b..511799cb 100755
--- a/.evergreen/run-fuzzer.sh
+++ b/.evergreen/run-fuzzer.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh
index f4991f6b..56c57f23 100755
--- a/.evergreen/run-tests.sh
+++ b/.evergreen/run-tests.sh
@@ -1,8 +1,9 @@
-#!/bin/sh
+#!/bin/bash
 
 set -o errexit
 
 . ~/.cargo/env
+
 RUST_BACKTRACE=1 cargo test
 RUST_BACKTRACE=1 cargo test --all-features
 
diff --git a/Cargo.toml b/Cargo.toml
index 965a507d..aedea92c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -35,7 +35,11 @@ default = []
 # if enabled, include API for interfacing with chrono 0.4
 chrono-0_4 = ["chrono"]
 # if enabled, include API for interfacing with uuid 0.8
-uuid-0_8 = []
+# This is commented out because Cargo implicitly adds this feature since
+# uuid-0_8 is also an optional dependency.
+# uuid-0_8 = []
+# if enabled, include API for interfacing with uuid 1.x
+uuid-1 = []
 # if enabled, include API for interfacing with time 0.3
 time-0_3 = []
 # if enabled, include serde_with interop.
@@ -57,7 +61,8 @@ indexmap = "1.6.2"
 hex = "0.4.2"
 base64 = "0.13.0"
 lazy_static = "1.4.0"
-uuid = { version = "0.8.1", features = ["serde", "v4"] }
+uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true }
+uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
 serde_with = { version = "1", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
diff --git a/README.md b/README.md
index e7836902..60067634 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,7 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 |:-------------|:----------------------------------------------------------------------------------------------------|:-------------------|:--------|
 | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
 | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
+| `uuid-1`     | Enable support for v1.x of the [`uuid`](docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
 | `serde_with` | Enable [`serde_with`](docs.rs/serde_with/latest) integrations for `bson::DateTime` and `bson::Uuid` | serde_with         | no      |
 
 ## Overview of the BSON Format
diff --git a/src/bson.rs b/src/bson.rs
index e22b08bd..2004adfd 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -328,6 +328,14 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for Bson {
 
 #[cfg(feature = "uuid-0_8")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
+impl From<uuid_0_8::Uuid> for Bson {
+    fn from(uuid: uuid_0_8::Uuid) -> Self {
+        Bson::Binary(uuid.into())
+    }
+}
+
+#[cfg(feature = "uuid-1")]
+#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
 impl From<uuid::Uuid> for Bson {
     fn from(uuid: uuid::Uuid) -> Self {
         Bson::Binary(uuid.into())
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 29ce15d8..b015c3ea 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -48,6 +48,30 @@ pub use u32_as_timestamp::{
 #[doc(inline)]
 pub use u64_as_f64::{deserialize as deserialize_u64_from_f64, serialize as serialize_u64_as_f64};
 
+#[cfg(feature = "uuid-1")]
+#[doc(inline)]
+pub use uuid_1_as_binary::{
+    deserialize as deserialize_uuid_1_from_binary,
+    serialize as serialize_uuid_1_as_binary,
+};
+#[cfg(feature = "uuid-1")]
+#[doc(inline)]
+pub use uuid_1_as_c_sharp_legacy_binary::{
+    deserialize as deserialize_uuid_1_from_c_sharp_legacy_binary,
+    serialize as serialize_uuid_1_as_c_sharp_legacy_binary,
+};
+#[cfg(feature = "uuid-1")]
+#[doc(inline)]
+pub use uuid_1_as_java_legacy_binary::{
+    deserialize as deserialize_uuid_1_from_java_legacy_binary,
+    serialize as serialize_uuid_1_as_java_legacy_binary,
+};
+#[cfg(feature = "uuid-1")]
+#[doc(inline)]
+pub use uuid_1_as_python_legacy_binary::{
+    deserialize as deserialize_uuid_1_from_python_legacy_binary,
+    serialize as serialize_uuid_1_as_python_legacy_binary,
+};
 #[cfg(feature = "uuid-0_8")]
 #[doc(inline)]
 pub use uuid_as_binary::{
@@ -388,12 +412,39 @@ pub mod hex_string_as_object_id {
     }
 }
 
-/// Contains functions to serialize a [`uuid::Uuid`] as a [`crate::Binary`] and deserialize a
-/// [`uuid::Uuid`] from a [`crate::Binary`]. This only works with version 0.8 of the [`uuid`] crate.
+#[allow(unused_macros)]
+macro_rules! as_binary_mod {
+    ($feat:meta, $uu:path) => {
+        use serde::{Deserialize, Deserializer, Serialize, Serializer};
+        use std::result::Result;
+        use $uu;
+
+        /// Serializes a Uuid as a Binary.
+        #[cfg_attr(docsrs, doc($feat))]
+        pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
+            crate::uuid::Uuid::from(*val).serialize(serializer)
+        }
+
+        /// Deserializes a Uuid from a Binary.
+        #[cfg_attr(docsrs, doc($feat))]
+        pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let bson_uuid = crate::uuid::Uuid::deserialize(deserializer)?;
+            Ok(bson_uuid.into())
+        }
+    };
+}
+
+/// Contains functions to serialize a [`uuid_0_8::Uuid`] as a [`crate::Binary`] and deserialize a
+/// [`uuid_0_8::Uuid`] from a [`crate::Binary`].
 ///
 /// ```rust
+/// # #[cfg(feature = "uuid-0_8")]
+/// # {
 /// use serde::{Serialize, Deserialize};
-/// use uuid::Uuid;
+/// use uuid_0_8::Uuid;
 /// use bson::serde_helpers::uuid_as_binary;
 ///
 /// #[derive(Serialize, Deserialize)]
@@ -401,40 +452,76 @@ pub mod hex_string_as_object_id {
 ///     #[serde(with = "uuid_as_binary")]
 ///     pub id: Uuid,
 /// }
+/// # }
 /// ```
 #[cfg(feature = "uuid-0_8")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
 pub mod uuid_as_binary {
-    use serde::{Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-    use uuid::Uuid;
+    as_binary_mod!(cfg(feature = "uuid-0_8"), uuid_0_8::Uuid);
+}
 
-    /// Serializes a Uuid as a Binary.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
-        crate::uuid::Uuid::from_external_uuid(*val).serialize(serializer)
-    }
+/// Contains functions to serialize a [`uuid::Uuid`] as a [`crate::Binary`] and deserialize a
+/// [`uuid::Uuid`] from a [`crate::Binary`].
+///
+/// ```rust
+/// # #[cfg(feature = "uuid-1")]
+/// # {
+/// use serde::{Serialize, Deserialize};
+/// use uuid::Uuid;
+/// use bson::serde_helpers::uuid_1_as_binary;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Item {
+///     #[serde(with = "uuid_1_as_binary")]
+///     pub id: Uuid,
+/// }
+/// # }
+/// ```
+#[cfg(feature = "uuid-1")]
+#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
+pub mod uuid_1_as_binary {
+    as_binary_mod!(cfg(feature = "uuid-1"), uuid::Uuid);
+}
 
-    /// Deserializes a Uuid from a Binary.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let bson_uuid = crate::uuid::Uuid::deserialize(deserializer)?;
-        Ok(bson_uuid.into())
-    }
+#[allow(unused_macros)]
+macro_rules! as_legacy_binary_mod {
+    ($feat:meta, $uu:path, $rep:path) => {
+        use crate::{uuid::UuidRepresentation, Binary};
+        use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+        use std::result::Result;
+        use $uu;
+
+        /// Serializes a Uuid as a Binary in the legacy UUID format.
+        #[cfg_attr(docsrs, doc($feat))]
+        pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
+            let binary = Binary::from_uuid_with_representation(crate::uuid::Uuid::from(*val), $rep);
+            binary.serialize(serializer)
+        }
+
+        /// Deserializes a Uuid from a Binary in the legacy UUID format.
+        #[cfg_attr(docsrs, doc($feat))]
+        pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let binary = Binary::deserialize(deserializer)?;
+            let uuid = binary
+                .to_uuid_with_representation($rep)
+                .map_err(de::Error::custom)?;
+            Ok(uuid.into())
+        }
+    };
 }
 
-/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy
-/// Java driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy
-/// Java driver format.
-///
-/// Note: the `"uuid-0_8"` feature must be enabled to use this helper.
+/// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy
+/// Java driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the
+/// legacy Java driver format.
 ///
 /// ```rust
+/// #[cfg(feature = "uuid-0_8")]
+/// # {
 /// use serde::{Serialize, Deserialize};
-/// use uuid::Uuid;
+/// use uuid_0_8::Uuid;
 /// use bson::serde_helpers::uuid_as_java_legacy_binary;
 ///
 /// #[derive(Serialize, Deserialize)]
@@ -442,48 +529,55 @@ pub mod uuid_as_binary {
 ///     #[serde(with = "uuid_as_java_legacy_binary")]
 ///     pub id: Uuid,
 /// }
+/// # }
 /// ```
 #[cfg(feature = "uuid-0_8")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
 pub mod uuid_as_java_legacy_binary {
-    use crate::{uuid::UuidRepresentation, Binary};
-    use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-    use uuid::Uuid;
-
-    /// Serializes a Uuid as a Binary in a Java Legacy UUID format.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
-        let binary = Binary::from_uuid_with_representation(
-            crate::uuid::Uuid::from_external_uuid(*val),
-            UuidRepresentation::JavaLegacy,
-        );
-        binary.serialize(serializer)
-    }
-
-    /// Deserializes a Uuid from a Binary in a Java Legacy UUID format.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let binary = Binary::deserialize(deserializer)?;
-        let uuid = binary
-            .to_uuid_with_representation(UuidRepresentation::JavaLegacy)
-            .map_err(de::Error::custom)?;
-        Ok(uuid.to_uuid_0_8())
-    }
+    as_legacy_binary_mod!(
+        cfg(feature = "uuid-0_8"),
+        uuid_0_8::Uuid,
+        UuidRepresentation::JavaLegacy
+    );
 }
 
-/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy Python
-/// driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy Python
-/// driver format.
-///
-/// Note: the `"uuid-0_8"` feature must be enabled to use this helper.
+/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy
+/// Java driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy
+/// Java driver format.
 ///
 /// ```rust
+/// #[cfg(feature = "uuid-1")]
+/// # {
 /// use serde::{Serialize, Deserialize};
 /// use uuid::Uuid;
+/// use bson::serde_helpers::uuid_1_as_java_legacy_binary;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Item {
+///     #[serde(with = "uuid_1_as_java_legacy_binary")]
+///     pub id: Uuid,
+/// }
+/// # }
+/// ```
+#[cfg(feature = "uuid-1")]
+#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
+pub mod uuid_1_as_java_legacy_binary {
+    as_legacy_binary_mod!(
+        cfg(feature = "uuid-1"),
+        uuid::Uuid,
+        UuidRepresentation::JavaLegacy
+    );
+}
+
+/// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy Python
+/// driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the legacy
+/// Python driver format.
+///
+/// ```rust
+/// # #[cfg(feature = "uuid-0_8")]
+/// # {
+/// use serde::{Serialize, Deserialize};
+/// use uuid_0_8::Uuid;
 /// use bson::serde_helpers::uuid_as_python_legacy_binary;
 ///
 /// #[derive(Serialize, Deserialize)]
@@ -491,48 +585,55 @@ pub mod uuid_as_java_legacy_binary {
 ///     #[serde(with = "uuid_as_python_legacy_binary")]
 ///     pub id: Uuid,
 /// }
+/// # }
 /// ```
 #[cfg(feature = "uuid-0_8")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
 pub mod uuid_as_python_legacy_binary {
-    use crate::{uuid::UuidRepresentation, Binary};
-    use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-    use uuid::Uuid;
-
-    /// Serializes a Uuid as a Binary in a Python Legacy UUID format.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
-        let binary = Binary::from_uuid_with_representation(
-            crate::uuid::Uuid::from_external_uuid(*val),
-            UuidRepresentation::PythonLegacy,
-        );
-        binary.serialize(serializer)
-    }
-
-    /// Deserializes a Uuid from a Binary in a Python Legacy UUID format.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let binary = Binary::deserialize(deserializer)?;
-        let uuid = binary
-            .to_uuid_with_representation(UuidRepresentation::PythonLegacy)
-            .map_err(de::Error::custom)?;
-        Ok(uuid.into())
-    }
+    as_legacy_binary_mod!(
+        cfg(feature = "uuid-0_8"),
+        uuid_0_8::Uuid,
+        UuidRepresentation::PythonLegacy
+    );
 }
 
-/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy C# driver
-/// UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy C# driver
-/// format.
-///
-/// Note: the `"uuid-0_8"` feature must be enabled to use this helper.
+/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy Python
+/// driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy Python
+/// driver format.
 ///
 /// ```rust
+/// # #[cfg(feature = "uuid-1")]
+/// # {
 /// use serde::{Serialize, Deserialize};
 /// use uuid::Uuid;
+/// use bson::serde_helpers::uuid_1_as_python_legacy_binary;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Item {
+///     #[serde(with = "uuid_1_as_python_legacy_binary")]
+///     pub id: Uuid,
+/// }
+/// # }
+/// ```
+#[cfg(feature = "uuid-1")]
+#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
+pub mod uuid_1_as_python_legacy_binary {
+    as_legacy_binary_mod!(
+        cfg(feature = "uuid-1"),
+        uuid::Uuid,
+        UuidRepresentation::PythonLegacy
+    );
+}
+
+/// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy C#
+/// driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the legacy C#
+/// driver format.
+///
+/// ```rust
+/// # #[cfg(feature = "uuid-0_8")]
+/// # {
+/// use serde::{Serialize, Deserialize};
+/// use uuid_0_8::Uuid;
 /// use bson::serde_helpers::uuid_as_c_sharp_legacy_binary;
 ///
 /// #[derive(Serialize, Deserialize)]
@@ -540,37 +641,44 @@ pub mod uuid_as_python_legacy_binary {
 ///     #[serde(with = "uuid_as_c_sharp_legacy_binary")]
 ///     pub id: Uuid,
 /// }
+/// # }
 /// ```
 #[cfg(feature = "uuid-0_8")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
 pub mod uuid_as_c_sharp_legacy_binary {
-    use crate::{uuid::UuidRepresentation, Binary};
-    use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-    use uuid::Uuid;
-
-    /// Serializes a Uuid as a Binary in a C# Legacy UUID format.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
-        let binary = Binary::from_uuid_with_representation(
-            crate::uuid::Uuid::from_external_uuid(*val),
-            UuidRepresentation::CSharpLegacy,
-        );
-        binary.serialize(serializer)
-    }
+    as_legacy_binary_mod!(
+        cfg(feature = "uuid-0_8"),
+        uuid_0_8::Uuid,
+        UuidRepresentation::CSharpLegacy
+    );
+}
 
-    /// Deserializes a Uuid from a Binary in a C# Legacy UUID format.
-    #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let binary = Binary::deserialize(deserializer)?;
-        let uuid = binary
-            .to_uuid_with_representation(UuidRepresentation::CSharpLegacy)
-            .map_err(de::Error::custom)?;
-        Ok(uuid.into())
-    }
+/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy C# driver
+/// UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy C# driver
+/// format.
+///
+/// ```rust
+/// # #[cfg(feature = "uuid-1")]
+/// # {
+/// use serde::{Serialize, Deserialize};
+/// use uuid::Uuid;
+/// use bson::serde_helpers::uuid_1_as_c_sharp_legacy_binary;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Item {
+///     #[serde(with = "uuid_1_as_c_sharp_legacy_binary")]
+///     pub id: Uuid,
+/// }
+/// # }
+/// ```
+#[cfg(feature = "uuid-1")]
+#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
+pub mod uuid_1_as_c_sharp_legacy_binary {
+    as_legacy_binary_mod!(
+        cfg(feature = "uuid-1"),
+        uuid::Uuid,
+        UuidRepresentation::CSharpLegacy
+    );
 }
 
 /// Contains functions to serialize a u32 as a bson::Timestamp and deserialize a u32 from a
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 13a716d0..362587a8 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -555,8 +555,8 @@ fn test_de_db_pointer() {
 
 #[cfg(feature = "uuid-0_8")]
 #[test]
-fn test_serde_legacy_uuid() {
-    use uuid::Uuid;
+fn test_serde_legacy_uuid_0_8() {
+    use uuid_0_8::Uuid;
 
     let _guard = LOCK.run_concurrently();
 
@@ -601,6 +601,54 @@ fn test_serde_legacy_uuid() {
     assert_eq!(foo.csharp_legacy, uuid);
 }
 
+#[cfg(feature = "uuid-1")]
+#[test]
+fn test_serde_legacy_uuid_1() {
+    use uuid::Uuid;
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct Foo {
+        #[serde(with = "serde_helpers::uuid_1_as_java_legacy_binary")]
+        java_legacy: Uuid,
+        #[serde(with = "serde_helpers::uuid_1_as_python_legacy_binary")]
+        python_legacy: Uuid,
+        #[serde(with = "serde_helpers::uuid_1_as_c_sharp_legacy_binary")]
+        csharp_legacy: Uuid,
+    }
+    let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap();
+    let foo = Foo {
+        java_legacy: uuid,
+        python_legacy: uuid,
+        csharp_legacy: uuid,
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! {
+            "java_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("7766554433221100FFEEDDCCBBAA9988").unwrap(),
+            }),
+            "python_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("00112233445566778899AABBCCDDEEFF").unwrap(),
+            }),
+            "csharp_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("33221100554477668899AABBCCDDEEFF").unwrap(),
+            })
+        }
+    );
+
+    let foo: Foo = from_bson(x).unwrap();
+    assert_eq!(foo.java_legacy, uuid);
+    assert_eq!(foo.python_legacy, uuid);
+    assert_eq!(foo.csharp_legacy, uuid);
+}
+
 #[test]
 fn test_de_oid_string() {
     let _guard = LOCK.run_concurrently();
@@ -840,9 +888,9 @@ fn test_oid_helpers() {
 
 #[test]
 #[cfg(feature = "uuid-0_8")]
-fn test_uuid_helpers() {
+fn test_uuid_0_8_helpers() {
     use serde_helpers::uuid_as_binary;
-    use uuid::Uuid;
+    use uuid_0_8::Uuid;
 
     let _guard = LOCK.run_concurrently();
 
@@ -866,6 +914,34 @@ fn test_uuid_helpers() {
     assert_eq!(a.uuid, uuid);
 }
 
+#[test]
+#[cfg(feature = "uuid-1")]
+fn test_uuid_1_helpers() {
+    use serde_helpers::uuid_1_as_binary;
+    use uuid::Uuid;
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct A {
+        #[serde(with = "uuid_1_as_binary")]
+        uuid: Uuid,
+    }
+
+    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
+    let a = A { uuid };
+    let doc = to_document(&a).unwrap();
+    match doc.get("uuid").unwrap() {
+        Bson::Binary(bin) => {
+            assert_eq!(bin.subtype, BinarySubtype::Uuid);
+            assert_eq!(bin.bytes, uuid.as_bytes());
+        }
+        _ => panic!("expected Bson::Binary"),
+    }
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.uuid, uuid);
+}
+
 #[test]
 fn test_timestamp_helpers() {
     let _guard = LOCK.run_concurrently();
diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs
index 7c41a741..fe658b60 100644
--- a/src/uuid/mod.rs
+++ b/src/uuid/mod.rs
@@ -19,8 +19,9 @@
 //! e.g.
 //!
 //! ``` rust
-//! # #[cfg(feature = "uuid-0_8")]
+//! # #[cfg(feature = "uuid-1")]
 //! # {
+//! # use uuid as uuid;
 //! use serde::{Serialize, Deserialize};
 //! use bson::doc;
 //!
@@ -34,24 +35,25 @@
 //!     bson_uuid: bson::Uuid,
 //!
 //!     /// serializes as a BSON binary with subtype 4 when either is used.
-//!     /// this requires the "uuid-0_8" feature flag
-//!     #[serde(with = "bson::serde_helpers::uuid_as_binary")]
+//!     /// this requires the "uuid-1" feature flag
+//!     #[serde(with = "bson::serde_helpers::uuid_1_as_binary")]
 //!     uuid_as_bson: uuid::Uuid,
 //! }
 //! # };
 //! ```
 //!
-//! ## The `uuid-0_8` feature flag
+//! ## The `uuid-1` feature flag
 //!
 //! To facilitate the conversion between [`crate::Uuid`] values and the `uuid` crate's `Uuid`
-//! values, the `uuid-0_8` feature flag can be enabled. This flag exposes a number of convenient
-//! conversions, including the [`crate::Uuid::to_uuid_0_8`] method and the `From<uuid::Uuid>`
+//! values, the `uuid-1` feature flag can be enabled. This flag exposes a number of convenient
+//! conversions, including the `crate::Uuid::to_uuid_1` method and the `From<uuid::Uuid>`
 //! implementation for `Bson`, which allows the `uuid` crate's `Uuid` values to be used in the
 //! `doc!` and `bson!` macros.
 //!
 //! ```
-//! # #[cfg(feature = "uuid-0_8")]
+//! # #[cfg(feature = "uuid-1")]
 //! # {
+//! # use uuid as uuid;
 //! use bson::doc;
 //!
 //! // this automatic conversion does not require any feature flags
@@ -59,16 +61,19 @@
 //!     "uuid": bson::Uuid::new(),
 //! };
 //!
-//! // but this automatic conversion requires the "uuid-0_8" feature flag
+//! // but this automatic conversion requires the "uuid-1" feature flag
 //! let query = doc! {
 //!     "uuid": uuid::Uuid::new_v4(),
 //! };
 //!
-//! // this also requires the "uuid-0_8" feature flag.
-//! let uuid = bson::Uuid::new().to_uuid_0_8();
+//! // this also requires the "uuid-1" feature flag.
+//! let uuid = bson::Uuid::new().to_uuid_1();
 //! # };
 //! ```
 //!
+//! For backwards compatibility, a `uuid-0_8` feature flag can be enabled, which provides the same
+//! API for interoperation with version 0.8 of the `uuid` crate.
+//!
 //! ## The `serde_with` feature flag
 //!
 //! The `serde_with` feature can be enabled to support more ergonomic serde attributes for
@@ -77,8 +82,9 @@
 //! handle nested `uuid::Uuid` values (e.g. in `Option`), whereas the former only works on fields
 //! that are exactly `uuid::Uuid`.
 //! ```
-//! # #[cfg(all(feature = "uuid-0_8", feature = "serde_with"))]
+//! # #[cfg(all(feature = "uuid-1", feature = "serde_with"))]
 //! # {
+//! # use uuid as uuid;
 //! use serde::{Deserialize, Serialize};
 //! use bson::doc;
 //!
@@ -109,8 +115,9 @@
 //! for non-BSON formats such as JSON:
 //!
 //! ``` rust
-//! # #[cfg(feature = "uuid-0_8")]
+//! # #[cfg(feature = "uuid-1")]
 //! # {
+//! # use uuid as uuid;
 //! # use serde::{Serialize, Deserialize};
 //! # #[derive(Serialize, Deserialize)]
 //! # struct Foo {
@@ -212,13 +219,29 @@ impl Default for Uuid {
 impl Uuid {
     /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
     /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
-    pub fn from_uuid_0_8(uuid: uuid::Uuid) -> Self {
+    pub fn from_uuid_0_8(uuid: uuid_0_8::Uuid) -> Self {
+        Self::from_external_uuid(uuid::Uuid::from_u128(uuid.as_u128()))
+    }
+
+    /// Convert this [`Uuid`] to a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
+    /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
+    pub fn to_uuid_0_8(self) -> uuid_0_8::Uuid {
+        uuid_0_8::Uuid::from_bytes(self.uuid.into_bytes())
+    }
+}
+
+#[cfg(feature = "uuid-1")]
+#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
+impl Uuid {
+    /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
+    /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
+    pub fn from_uuid_1(uuid: uuid::Uuid) -> Self {
         Self::from_external_uuid(uuid)
     }
 
     /// Convert this [`Uuid`] to a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
     /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
-    pub fn to_uuid_0_8(self) -> uuid::Uuid {
+    pub fn to_uuid_1(self) -> uuid::Uuid {
         self.uuid
     }
 }
@@ -290,16 +313,30 @@ impl From<Uuid> for Bson {
 }
 
 #[cfg(feature = "uuid-0_8")]
+impl From<uuid_0_8::Uuid> for Uuid {
+    fn from(u: uuid_0_8::Uuid) -> Self {
+        Self::from_uuid_0_8(u)
+    }
+}
+
+#[cfg(feature = "uuid-0_8")]
+impl From<Uuid> for uuid_0_8::Uuid {
+    fn from(s: Uuid) -> Self {
+        s.to_uuid_0_8()
+    }
+}
+
+#[cfg(feature = "uuid-1")]
 impl From<uuid::Uuid> for Uuid {
     fn from(u: uuid::Uuid) -> Self {
-        Self::from_external_uuid(u)
+        Self::from_uuid_1(u)
     }
 }
 
-#[cfg(feature = "uuid-0_8")]
+#[cfg(feature = "uuid-1")]
 impl From<Uuid> for uuid::Uuid {
     fn from(s: Uuid) -> Self {
-        s.to_uuid_0_8()
+        s.to_uuid_1()
     }
 }
 
@@ -436,40 +473,46 @@ impl Binary {
     }
 }
 
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-impl From<uuid::Uuid> for Binary {
-    fn from(uuid: uuid::Uuid) -> Self {
-        Binary {
-            subtype: BinarySubtype::Uuid,
-            bytes: uuid.as_bytes().to_vec(),
+macro_rules! trait_impls {
+    ($feat:meta, $u:ty) => {
+        #[cfg($feat)]
+        #[cfg_attr(docsrs, doc(cfg($feat)))]
+        impl From<$u> for Binary {
+            fn from(uuid: $u) -> Self {
+                Binary {
+                    subtype: BinarySubtype::Uuid,
+                    bytes: uuid.as_bytes().to_vec(),
+                }
+            }
         }
-    }
-}
 
-#[cfg(all(feature = "uuid-0_8", feature = "serde_with"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-0_8", feature = "serde_with"))))]
-impl<'de> serde_with::DeserializeAs<'de, uuid::Uuid> for crate::Uuid {
-    fn deserialize_as<D>(deserializer: D) -> std::result::Result<uuid::Uuid, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        let uuid = Uuid::deserialize(deserializer)?;
-        Ok(uuid.into())
-    }
-}
+        #[cfg(all($feat, feature = "serde_with"))]
+        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with"))))]
+        impl<'de> serde_with::DeserializeAs<'de, $u> for crate::Uuid {
+            fn deserialize_as<D>(deserializer: D) -> std::result::Result<$u, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                let uuid = Uuid::deserialize(deserializer)?;
+                Ok(uuid.into())
+            }
+        }
 
-#[cfg(all(feature = "uuid-0_8", feature = "serde_with"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-0_8", feature = "sere_with"))))]
-impl serde_with::SerializeAs<uuid::Uuid> for crate::Uuid {
-    fn serialize_as<S>(source: &uuid::Uuid, serializer: S) -> std::result::Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        let uuid = Uuid::from_external_uuid(*source);
-        uuid.serialize(serializer)
-    }
+        #[cfg(all($feat, feature = "serde_with"))]
+        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with"))))]
+        impl serde_with::SerializeAs<$u> for crate::Uuid {
+            fn serialize_as<S>(source: &$u, serializer: S) -> std::result::Result<S::Ok, S::Error>
+            where
+                S: serde::Serializer,
+            {
+                let uuid = Uuid::from(*source);
+                uuid.serialize(serializer)
+            }
+        }
+    };
 }
+trait_impls!(feature = "uuid-0_8", uuid_0_8::Uuid);
+trait_impls!(feature = "uuid-1", uuid::Uuid);
 
 /// Errors that can occur during [`Uuid`] construction and generation.
 #[derive(Clone, Debug)]
diff --git a/src/uuid/test.rs b/src/uuid/test.rs
index f4d429bd..d33c02db 100644
--- a/src/uuid/test.rs
+++ b/src/uuid/test.rs
@@ -240,7 +240,7 @@ fn test_binary_to_uuid_python_legacy_rep() {
 
 #[cfg(feature = "uuid-0_8")]
 #[test]
-fn interop() {
+fn interop_0_8() {
     let uuid = crate::Uuid::new();
     let uuid_uuid = uuid.to_uuid_0_8();
     assert_eq!(uuid.to_string(), uuid_uuid.to_string());
@@ -253,3 +253,19 @@ fn interop() {
     let d_uuid = doc! { "uuid": uuid_uuid };
     assert_eq!(d_bson, d_uuid);
 }
+
+#[cfg(feature = "uuid-1")]
+#[test]
+fn interop_1() {
+    let uuid = crate::Uuid::new();
+    let uuid_uuid = uuid.to_uuid_1();
+    assert_eq!(uuid.to_string(), uuid_uuid.to_string());
+    assert_eq!(&uuid.bytes(), uuid_uuid.as_bytes());
+
+    let back: crate::Uuid = uuid_uuid.into();
+    assert_eq!(back, uuid);
+
+    let d_bson = doc! { "uuid": uuid };
+    let d_uuid = doc! { "uuid": uuid_uuid };
+    assert_eq!(d_bson, d_uuid);
+}

From e2c925e29515eb3179d85fe277affd8365b93620 Mon Sep 17 00:00:00 2001
From: Sana Verma <sanyaverma0303@gmail.com>
Date: Tue, 5 Jul 2022 11:49:21 -0400
Subject: [PATCH 005/156] RUST-1198 Support creating bson::DateTime from a
 given year/month/date/hour/minute/second/millisecond (#361)

Added a builder to support creating a `DateTime` from specified date and time arguments.
---
 src/datetime.rs           |  25 +++++
 src/datetime/builder.rs   | 187 ++++++++++++++++++++++++++++++++++++++
 src/tests/modules/bson.rs |  41 +++++++++
 3 files changed, 253 insertions(+)
 create mode 100644 src/datetime/builder.rs

diff --git a/src/datetime.rs b/src/datetime.rs
index b6419de8..a857b9a3 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -1,3 +1,5 @@
+//! BSON DateTime
+
 use std::{
     convert::TryInto,
     error,
@@ -6,6 +8,8 @@ use std::{
     time::{Duration, SystemTime},
 };
 
+pub(crate) mod builder;
+pub use crate::datetime::builder::DateTimeBuilder;
 use time::format_description::well_known::Rfc3339;
 
 #[cfg(feature = "chrono-0_4")]
@@ -41,6 +45,18 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// # }
 /// ```
 ///
+/// You may also construct this type from a given `year`, `month`, `day`, and optionally,
+/// an `hour`, `minute`, `second` and `millisecond`, which default to 0 if not explicitly set.
+///
+/// ```
+/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// let dt = bson::DateTime::builder().year(1998).month(2).day(12).minute(1).millisecond(23).build()?;
+/// let expected = bson::DateTime::parse_rfc3339_str("1998-02-12T00:01:00.023Z")?;
+/// assert_eq!(dt, expected);
+/// # Ok(())
+/// # }
+/// ```
+///
 /// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
 /// BSON datetime rather than an RFC 3339 formatted string. Additionally, in non-BSON formats, it
 /// will serialize to and deserialize from that format's equivalent of the
@@ -131,6 +147,15 @@ impl crate::DateTime {
         Self::from_millis(dt.timestamp_millis())
     }
 
+    /// Returns a builder used to construct a [`DateTime`] from a given year, month,
+    /// day, and optionally, an hour, minute, second and millisecond, which default to
+    /// 0 if not explicitly set.
+    ///
+    /// Note: You cannot call `build()` before setting at least the year, month and day.
+    pub fn builder() -> DateTimeBuilder {
+        DateTimeBuilder::default()
+    }
+
     /// Convert this [`DateTime`] to a [`chrono::DateTime<Utc>`].
     ///
     /// Note: Not every BSON datetime can be represented as a [`chrono::DateTime`]. For such dates,
diff --git a/src/datetime/builder.rs b/src/datetime/builder.rs
new file mode 100644
index 00000000..c16e22e2
--- /dev/null
+++ b/src/datetime/builder.rs
@@ -0,0 +1,187 @@
+use super::*;
+use std::convert::TryFrom;
+use time::Date;
+
+/// Builder for constructing a BSON [`DateTime`]
+pub struct DateTimeBuilder<Y = NoYear, M = NoMonth, D = NoDay> {
+    pub(crate) year: Y,
+    pub(crate) month: M,
+    pub(crate) day: D,
+
+    pub(crate) hour: Option<u8>,
+    pub(crate) minute: Option<u8>,
+    pub(crate) second: Option<u8>,
+    pub(crate) millisecond: Option<u16>,
+}
+
+impl Default for DateTimeBuilder {
+    fn default() -> Self {
+        Self {
+            year: NoYear,
+            month: NoMonth,
+            day: NoDay,
+            hour: None,
+            minute: None,
+            second: None,
+            millisecond: None,
+        }
+    }
+}
+
+pub struct Year(i32);
+pub struct NoYear;
+
+pub struct Month(u8);
+pub struct NoMonth;
+
+pub struct Day(u8);
+pub struct NoDay;
+
+impl<M, D> DateTimeBuilder<NoYear, M, D> {
+    /// Sets the year for the builder instance. Years between ±9999 inclusive are valid.
+    /// If the specified value is out of range, calling the `build()` method will return
+    /// an error.
+    ///
+    /// Note: This is a required method. You will not be able to call `build()` before calling
+    /// this method.
+    pub fn year(self, y: i32) -> DateTimeBuilder<Year, M, D> {
+        let Self {
+            year: _,
+            month,
+            day,
+            hour,
+            minute,
+            second,
+            millisecond,
+        } = self;
+        DateTimeBuilder {
+            year: Year(y),
+            month,
+            day,
+            hour,
+            minute,
+            second,
+            millisecond,
+        }
+    }
+}
+
+impl<Y, D> DateTimeBuilder<Y, NoMonth, D> {
+    /// Sets the month for the builder instance. Maps months as 1-January to 12-December.
+    /// If the specified value is out of range, calling the `build()` method will return
+    /// an error.
+    ///
+    /// Note: This is a required method. You will not be able to call `build()` before calling
+    /// this method.
+    pub fn month(self, m: u8) -> DateTimeBuilder<Y, Month, D> {
+        let Self {
+            year,
+            month: _,
+            day,
+            hour,
+            minute,
+            second,
+            millisecond,
+        } = self;
+        DateTimeBuilder {
+            year,
+            month: Month(m),
+            day,
+            hour,
+            minute,
+            second,
+            millisecond,
+        }
+    }
+}
+
+impl<Y, M> DateTimeBuilder<Y, M, NoDay> {
+    /// Sets the day for the builder instance. Values in the range `1..=31` are valid.
+    /// If the specified value does not exist for the provided month/year or is out of range,
+    /// calling the `build()` method will return an error.
+    ///
+    /// Note: This is a required method. You will not be able to call `build()` before calling
+    /// this method.
+    pub fn day(self, d: u8) -> DateTimeBuilder<Y, M, Day> {
+        let Self {
+            year,
+            month,
+            day: _,
+            hour,
+            minute,
+            second,
+            millisecond,
+        } = self;
+        DateTimeBuilder {
+            year,
+            month,
+            day: Day(d),
+            hour,
+            minute,
+            second,
+            millisecond,
+        }
+    }
+}
+
+impl<Y, M, D> DateTimeBuilder<Y, M, D> {
+    /// Sets the hour (24-hour format) for the builder instance. Values must be in the range
+    /// `0..=23`. If the specified value is out of range, calling the `build()` method will
+    /// return an error.
+    ///
+    /// Note: This is an optional method. The hour will default to 0 if not explicitly set.
+    pub fn hour(mut self, hour: u8) -> DateTimeBuilder<Y, M, D> {
+        self.hour = Some(hour);
+        self
+    }
+
+    /// Sets the minute for the builder instance. Values must be in the range `0..=59`.
+    /// If the specified value is out of range, calling the `build()` method will return an error.
+    ///
+    /// Note: This is an optional method. The minute will default to 0 if not explicitly set.
+    pub fn minute(mut self, minute: u8) -> DateTimeBuilder<Y, M, D> {
+        self.minute = Some(minute);
+        self
+    }
+
+    /// Sets the second for the builder instance. Values must be in range `0..=59`.
+    /// If the specified value is out of range, calling the `build()` method will return an error.
+    ///
+    /// Note: This is an optional method. The second will default to 0 if not explicitly set.
+    pub fn second(mut self, second: u8) -> DateTimeBuilder<Y, M, D> {
+        self.second = Some(second);
+        self
+    }
+
+    /// Sets the millisecond for the builder instance. Values must be in the range `0..=999`.
+    /// If the specified value is out of range, calling the `build()` method will return an error.
+    ///
+    /// Note: This is an optional method. The millisecond will default to 0 if not explicitly set.
+    pub fn millisecond(mut self, millisecond: u16) -> DateTimeBuilder<Y, M, D> {
+        self.millisecond = Some(millisecond);
+        self
+    }
+}
+
+impl DateTimeBuilder<Year, Month, Day> {
+    /// Convert a builder with a specified year, month, day, and optionally, an hour, minute, second
+    /// and millisecond to a [`DateTime`].
+    ///
+    /// Note: You cannot call `build()` before setting at least the year, month and day.
+    pub fn build(self) -> Result<DateTime> {
+        let err = |e: time::error::ComponentRange| Error::InvalidTimestamp {
+            message: e.to_string(),
+        };
+        let month = time::Month::try_from(self.month.0).map_err(err)?;
+        let dt = Date::from_calendar_date(self.year.0, month, self.day.0)
+            .map_err(err)?
+            .with_hms_milli(
+                self.hour.unwrap_or(0),
+                self.minute.unwrap_or(0),
+                self.second.unwrap_or(0),
+                self.millisecond.unwrap_or(0),
+            )
+            .map_err(err)?;
+        Ok(DateTime::from_time_private(dt.assume_utc()))
+    }
+}
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 8f6de566..9f89079c 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -16,6 +16,7 @@ use crate::{
     Regex,
     Timestamp,
 };
+
 use serde_json::{json, Value};
 
 #[test]
@@ -363,6 +364,46 @@ fn from_external_datetime() {
     }
 }
 
+#[test]
+fn from_datetime_builder() {
+    {
+        let dt = DateTime::builder()
+            .year(2022)
+            .month(9)
+            .day(15)
+            .minute(2)
+            .millisecond(1)
+            .build();
+        assert!(dt.is_ok());
+        assert_eq!(
+            DateTime::from_time_0_3(time::macros::datetime!(2022 - 09 - 15 00:02:00.001 UTC)),
+            dt.unwrap()
+        );
+    }
+
+    {
+        let dt = DateTime::builder()
+            .year(2022)
+            .month(18)
+            .day(15)
+            .minute(2)
+            .millisecond(1)
+            .build();
+        assert!(dt.is_err());
+    }
+
+    {
+        let dt = DateTime::builder()
+            .year(2022)
+            .day(15)
+            .month(18)
+            .minute(83)
+            .millisecond(1)
+            .build();
+        assert!(dt.is_err());
+    }
+}
+
 #[test]
 fn system_time() {
     let _guard = LOCK.run_concurrently();

From 20675fff811c7c49bdb2794f3adbbe623564dbda Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 21 Jul 2022 15:52:31 -0400
Subject: [PATCH 006/156] RUST-1398 Pin `clippy` version to 1.62.0 (#366)

---
 .evergreen/check-clippy.sh | 9 +++++++--
 src/datetime.rs            | 2 +-
 src/de/raw.rs              | 2 +-
 src/document.rs            | 2 +-
 src/raw/bson.rs            | 2 +-
 src/raw/test/mod.rs        | 2 +-
 src/tests/modules/bson.rs  | 2 +-
 7 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index 43699eb4..da0c9f68 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -4,7 +4,12 @@ set -o errexit
 
 . ~/.cargo/env
 
-cargo clippy --all-targets --all-features -p bson -- -D warnings
+# Pin clippy to the latest version. This should be updated when new versions of Rust are released.
+CLIPPY_VERSION=1.62.0
+
+rustup install $CLIPPY_VERSION
+
+cargo +$CLIPPY_VERSION clippy --all-targets --all-features -p bson -- -D warnings
 
 cd serde-tests
-cargo clippy --all-targets --all-features -p serde-tests -- -D warnings
+cargo +$CLIPPY_VERSION clippy --all-targets --all-features -p serde-tests -- -D warnings
diff --git a/src/datetime.rs b/src/datetime.rs
index a857b9a3..9bb8dc68 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -292,7 +292,7 @@ impl crate::DateTime {
         } else {
             // need to convert to i128 before calculating absolute value since i64::MIN.abs()
             // overflows and panics.
-            SystemTime::UNIX_EPOCH - Duration::from_millis((self.0 as i128).abs() as u64)
+            SystemTime::UNIX_EPOCH - Duration::from_millis((self.0 as i128).unsigned_abs() as u64)
         }
     }
 
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 52701fd2..51842782 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -1673,7 +1673,7 @@ struct RawBsonDeserializer<'a> {
     value: BsonContent<'a>,
 }
 
-impl<'de, 'a> serde::de::Deserializer<'de> for RawBsonDeserializer<'de> {
+impl<'de> serde::de::Deserializer<'de> for RawBsonDeserializer<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
diff --git a/src/document.rs b/src/document.rs
index db5ac198..54b22dcb 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -165,7 +165,7 @@ impl FromIterator<(String, Bson)> for Document {
     }
 }
 
-impl<'a> Iterator for IntoIter {
+impl Iterator for IntoIter {
     type Item = (String, Bson);
 
     fn next(&mut self) -> Option<(String, Bson)> {
diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index 05f4dfc6..638ca57c 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -447,7 +447,7 @@ impl Serialize for RawBson {
     }
 }
 
-impl<'a> TryFrom<RawBson> for Bson {
+impl TryFrom<RawBson> for Bson {
     type Error = Error;
 
     fn try_from(rawbson: RawBson) -> Result<Bson> {
diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs
index 5bcec28e..250141d6 100644
--- a/src/raw/test/mod.rs
+++ b/src/raw/test/mod.rs
@@ -249,7 +249,7 @@ fn null() {
     let rawdoc = rawdoc! {
         "null": null,
     };
-    let () = rawdoc
+    rawdoc
         .get("null")
         .expect("error finding key null")
         .expect("no key null")
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 9f89079c..171aa3b7 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -433,7 +433,7 @@ fn system_time() {
     );
     assert_eq!(
         crate::DateTime::MIN.to_system_time(),
-        SystemTime::UNIX_EPOCH - Duration::from_millis((i64::MIN as i128).abs() as u64)
+        SystemTime::UNIX_EPOCH - Duration::from_millis((i64::MIN as i128).unsigned_abs() as u64)
     );
 
     assert_eq!(

From 0567e3bb006b6b030c9e09f3b144b01de5f15404 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 23 Aug 2022 12:13:13 -0400
Subject: [PATCH 007/156] RUST-1385 Add binary/raw conversions (#370)

---
 src/bson.rs         | 3 ++-
 src/raw/bson_ref.rs | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/bson.rs b/src/bson.rs
index 2004adfd..83f8b424 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -1130,7 +1130,8 @@ impl Binary {
         }
     }
 
-    pub(crate) fn as_raw_binary(&self) -> RawBinaryRef<'_> {
+    /// Borrow the contents as a `RawBinaryRef`.
+    pub fn as_raw_binary(&self) -> RawBinaryRef<'_> {
         RawBinaryRef {
             bytes: self.bytes.as_slice(),
             subtype: self.subtype,
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index c27ff939..a0668e01 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -460,6 +460,14 @@ pub struct RawBinaryRef<'a> {
 }
 
 impl<'a> RawBinaryRef<'a> {
+    /// Copy the contents into a `Binary`.
+    pub fn to_binary(&self) -> Binary {
+        Binary {
+            subtype: self.subtype,
+            bytes: self.bytes.to_owned(),
+        }
+    }
+
     pub(crate) fn len(&self) -> i32 {
         match self.subtype {
             BinarySubtype::BinaryOld => self.bytes.len() as i32 + 4,

From bad146878902da3add29c5e656ddbde65927300e Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 2 Sep 2022 12:38:45 -0400
Subject: [PATCH 008/156] RUST-1440 bump bson clippy version to 1.63.0 (#372)

---
 .evergreen/check-clippy.sh |  2 +-
 src/datetime.rs            |  9 +++++----
 src/lib.rs                 |  2 +-
 src/raw/document_buf.rs    |  2 +-
 src/tests/modules/bson.rs  | 14 ++++++++------
 5 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index da0c9f68..036b8242 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.62.0
+CLIPPY_VERSION=1.63.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/src/datetime.rs b/src/datetime.rs
index 9bb8dc68..d212f7a2 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -159,7 +159,8 @@ impl crate::DateTime {
     /// Convert this [`DateTime`] to a [`chrono::DateTime<Utc>`].
     ///
     /// Note: Not every BSON datetime can be represented as a [`chrono::DateTime`]. For such dates,
-    /// [`chrono::MIN_DATETIME`] or [`chrono::MAX_DATETIME`] will be returned, whichever is closer.
+    /// [`chrono::DateTime::MIN_UTC`] or [`chrono::DateTime::MAX_UTC`] will be returned, whichever
+    /// is closer.
     ///
     /// ```
     /// let bson_dt = bson::DateTime::now();
@@ -168,7 +169,7 @@ impl crate::DateTime {
     ///
     /// let big = bson::DateTime::from_millis(i64::MAX);
     /// let chrono_big = big.to_chrono();
-    /// assert_eq!(chrono_big, chrono::MAX_DATETIME)
+    /// assert_eq!(chrono_big, chrono::DateTime::<chrono::Utc>::MAX_UTC)
     /// ```
     #[cfg(feature = "chrono-0_4")]
     #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
@@ -177,9 +178,9 @@ impl crate::DateTime {
             LocalResult::Single(dt) => dt,
             _ => {
                 if self.0 < 0 {
-                    chrono::MIN_DATETIME
+                    chrono::DateTime::<Utc>::MIN_UTC
                 } else {
-                    chrono::MAX_DATETIME
+                    chrono::DateTime::<Utc>::MAX_UTC
                 }
             }
         }
diff --git a/src/lib.rs b/src/lib.rs
index 8d856fee..ed301c54 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -263,7 +263,7 @@
 //! The MSRV for this crate is currently 1.53.0. This will be rarely be increased, and if it ever is,
 //! it will only happen in a minor or major version release.
 
-#![allow(clippy::cognitive_complexity)]
+#![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
 #![doc(html_root_url = "https://docs.rs/bson/2.3.0")]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 5c25afe8..5624506e 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -386,7 +386,7 @@ impl Deref for RawDocumentBuf {
 
 impl Borrow<RawDocument> for RawDocumentBuf {
     fn borrow(&self) -> &RawDocument {
-        &*self
+        self.deref()
     }
 }
 
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 171aa3b7..67b8f4db 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -344,23 +344,25 @@ fn from_external_datetime() {
     }
     #[cfg(feature = "chrono-0_4")]
     {
-        let bdt = DateTime::from(chrono::MAX_DATETIME);
+        use chrono::Utc;
+
+        let bdt = DateTime::from(chrono::DateTime::<Utc>::MAX_UTC);
         assert_eq!(
             bdt.to_chrono().timestamp_millis(),
-            chrono::MAX_DATETIME.timestamp_millis()
+            chrono::DateTime::<Utc>::MAX_UTC.timestamp_millis()
         );
 
-        let bdt = DateTime::from(chrono::MIN_DATETIME);
+        let bdt = DateTime::from(chrono::DateTime::<Utc>::MIN_UTC);
         assert_eq!(
             bdt.to_chrono().timestamp_millis(),
-            chrono::MIN_DATETIME.timestamp_millis()
+            chrono::DateTime::<Utc>::MIN_UTC.timestamp_millis()
         );
 
         let bdt = DateTime::MAX;
-        assert_eq!(bdt.to_chrono(), chrono::MAX_DATETIME);
+        assert_eq!(bdt.to_chrono(), chrono::DateTime::<Utc>::MAX_UTC);
 
         let bdt = DateTime::MIN;
-        assert_eq!(bdt.to_chrono(), chrono::MIN_DATETIME);
+        assert_eq!(bdt.to_chrono(), chrono::DateTime::<Utc>::MIN_UTC);
     }
 }
 

From a4c05261f0058448361ee9d4864b301ba8410e35 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 29 Sep 2022 11:23:12 -0400
Subject: [PATCH 009/156] RUST-1480 Add a TryFrom<Bson> impl for RawBson (#373)

---
 src/raw/bson.rs         | 39 +++++++++++++++++++++++++++++++++++++++
 src/raw/document_buf.rs |  8 ++++++++
 2 files changed, 47 insertions(+)

diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index 638ca57c..9db28505 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -482,6 +482,45 @@ impl TryFrom<RawBson> for Bson {
     }
 }
 
+impl TryFrom<Bson> for RawBson {
+    type Error = Error;
+
+    fn try_from(bson: Bson) -> Result<RawBson> {
+        Ok(match bson {
+            Bson::Double(d) => RawBson::Double(d),
+            Bson::String(s) => RawBson::String(s),
+            Bson::Document(doc) => RawBson::Document((&doc).try_into()?),
+            Bson::Array(arr) => RawBson::Array(
+                arr.into_iter()
+                    .map(|b| -> Result<RawBson> { b.try_into() })
+                    .collect::<Result<RawArrayBuf>>()?,
+            ),
+            Bson::Binary(bin) => RawBson::Binary(bin),
+            Bson::ObjectId(id) => RawBson::ObjectId(id),
+            Bson::Boolean(b) => RawBson::Boolean(b),
+            Bson::DateTime(dt) => RawBson::DateTime(dt),
+            Bson::Null => RawBson::Null,
+            Bson::RegularExpression(regex) => RawBson::RegularExpression(regex),
+            Bson::JavaScriptCode(s) => RawBson::JavaScriptCode(s),
+            Bson::Int32(i) => RawBson::Int32(i),
+            Bson::Timestamp(ts) => RawBson::Timestamp(ts),
+            Bson::Int64(i) => RawBson::Int64(i),
+            Bson::Undefined => RawBson::Undefined,
+            Bson::DbPointer(p) => RawBson::DbPointer(p),
+            Bson::Symbol(s) => RawBson::Symbol(s),
+            Bson::JavaScriptCodeWithScope(jcws) => {
+                RawBson::JavaScriptCodeWithScope(crate::RawJavaScriptCodeWithScope {
+                    code: jcws.code,
+                    scope: (&jcws.scope).try_into()?,
+                })
+            }
+            Bson::Decimal128(d) => RawBson::Decimal128(d),
+            Bson::MaxKey => RawBson::MaxKey,
+            Bson::MinKey => RawBson::MinKey,
+        })
+    }
+}
+
 /// A BSON "code with scope" value backed by owned raw BSON.
 #[derive(Debug, Clone, PartialEq)]
 pub struct RawJavaScriptCodeWithScope {
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 5624506e..0a27396a 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -361,6 +361,14 @@ impl TryFrom<RawDocumentBuf> for Document {
     }
 }
 
+impl TryFrom<&Document> for RawDocumentBuf {
+    type Error = Error;
+
+    fn try_from(doc: &Document) -> Result<RawDocumentBuf> {
+        RawDocumentBuf::from_document(doc)
+    }
+}
+
 impl<'a> IntoIterator for &'a RawDocumentBuf {
     type IntoIter = Iter<'a>;
     type Item = Result<(&'a str, RawBsonRef<'a>)>;

From 90adccd355de511f5f2e50294e5c8dbb22957239 Mon Sep 17 00:00:00 2001
From: Satya Rohith <me@satyarohith.com>
Date: Mon, 3 Oct 2022 18:58:38 +0530
Subject: [PATCH 010/156] docs(readme): fix broken hyperlink (#375)

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 60067634..70023fac 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Encoding and decoding support for BSON in Rust
     - [Importing](#importing)
         - [Feature flags](#feature-flags)
 - [Useful links](#useful-links)
-- [Overview of BSON Format](#overview-of-bson-format)
+- [Overview of BSON Format](#overview-of-the-bson-format)
 - [Usage](#usage)
     - [BSON Values](#bson-values)
     - [BSON Documents](#bson-documents)

From 0612667e1344f9aabc3592a2cee02a96ac1b76bc Mon Sep 17 00:00:00 2001
From: Martin <bajanam@kean.edu>
Date: Wed, 5 Oct 2022 15:26:45 -0400
Subject: [PATCH 011/156] fix for stale issues action

---
 .github/workflows/remove_labels.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/remove_labels.yml b/.github/workflows/remove_labels.yml
index 37e9455a..8b027b6a 100644
--- a/.github/workflows/remove_labels.yml
+++ b/.github/workflows/remove_labels.yml
@@ -14,4 +14,4 @@ jobs:
       - name: initial labeling
         uses: andymckay/labeler@master
         with:
-          remove-labels: "waiting-for-reporter"
+          remove-labels: "waiting-for-reporter, Stale"

From 89521946106e1d6c3af390175bb0485ef578664a Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 4 Nov 2022 10:30:49 -0400
Subject: [PATCH 012/156] RUST-1534: implement iter_mut on Document (#382)

---
 src/document.rs     | 20 ++++++++++++++++++++
 src/raw/document.rs |  2 +-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/document.rs b/src/document.rs
index 54b22dcb..fedc38a1 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -117,6 +117,11 @@ pub struct Values<'a> {
     inner: indexmap::map::Values<'a, String, Bson>,
 }
 
+/// An iterator over a `Document`'s keys and mutable values.
+pub struct IterMut<'a> {
+    inner: indexmap::map::IterMut<'a, String, Bson>,
+}
+
 impl<'a> Iterator for Keys<'a> {
     type Item = &'a String;
 
@@ -181,6 +186,14 @@ impl<'a> Iterator for Iter<'a> {
     }
 }
 
+impl<'a> Iterator for IterMut<'a> {
+    type Item = (&'a String, &'a mut Bson);
+
+    fn next(&mut self) -> Option<(&'a String, &'a mut Bson)> {
+        self.inner.next()
+    }
+}
+
 impl Document {
     /// Creates a new empty Document.
     pub fn new() -> Document {
@@ -194,6 +207,13 @@ impl Document {
         self.into_iter()
     }
 
+    /// Gets an iterator over pairs of keys and mutable values.
+    pub fn iter_mut(&mut self) -> IterMut {
+        IterMut {
+            inner: self.inner.iter_mut(),
+        }
+    }
+
     /// Clears the document, removing all values.
     pub fn clear(&mut self) {
         self.inner.clear();
diff --git a/src/raw/document.rs b/src/raw/document.rs
index fb5f86dc..b5193067 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -28,7 +28,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document};
 
 /// A slice of a BSON document (akin to [`std::str`]). This can be created from a
 /// [`RawDocumentBuf`] or any type that contains valid BSON data, including static binary literals,
-/// [Vec<u8>](std::vec::Vec), or arrays.
+/// [`Vec<u8>`](std::vec::Vec), or arrays.
 ///
 /// This is an _unsized_ type, meaning that it must always be used behind a pointer like `&`. For an
 /// owned version of this type, see [`RawDocumentBuf`].

From d499e645e24d4ebe92b50ab3b11ccd4db0db026a Mon Sep 17 00:00:00 2001
From: bgd0403 <samiodev@icloud.com>
Date: Mon, 14 Nov 2022 20:22:46 +0100
Subject: [PATCH 013/156] RUST-1540 impl i64_as_datetime (#383)

---
 src/serde_helpers.rs | 39 +++++++++++++++++++++++++++++++++++++++
 src/tests/serde.rs   | 21 +++++++++++++++++++++
 2 files changed, 60 insertions(+)

diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index b015c3ea..e836d1c0 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -23,6 +23,11 @@ pub use hex_string_as_object_id::{
     serialize as serialize_hex_string_as_object_id,
 };
 #[doc(inline)]
+pub use i64_as_datetime::{
+    deserialize as deserialize_i64_from_datetime,
+    serialize as serialize_i64_as_datetime,
+};
+#[doc(inline)]
 pub use rfc3339_string_as_bson_datetime::{
     deserialize as deserialize_rfc3339_string_from_bson_datetime,
     serialize as serialize_rfc3339_string_as_bson_datetime,
@@ -412,6 +417,40 @@ pub mod hex_string_as_object_id {
     }
 }
 
+/// Contains functions to `serialize` a `i64` integer as `DateTime` and `deserialize`
+/// a `i64` integer from `DateTime`
+///
+/// ### The i64 should represent seconds `(DateTime::timestamp_millis(..))`.
+///
+/// ```rust
+/// # use serde::{Serialize, Deserialize};
+/// # use bson::serde_helpers::i64_as_datetime;
+/// #[derive(Serialize, Deserialize)]
+/// struct Item {
+///     #[serde(with = "i64_as_datetime")]
+///     pub now: i64,
+/// }
+/// ```
+pub mod i64_as_datetime {
+    use crate::DateTime;
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
+
+    /// Deserializes a i64 integer from a DateTime.
+    pub fn deserialize<'de, D>(deserializer: D) -> Result<i64, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let date: DateTime = DateTime::deserialize(deserializer)?;
+        Ok(date.timestamp_millis())
+    }
+
+    /// Serializes a i64 integer as a DateTime.
+    pub fn serialize<S: Serializer>(val: &i64, serializer: S) -> Result<S::Ok, S::Error> {
+        let date_time = DateTime::from_millis(*val);
+        date_time.serialize(serializer)
+    }
+}
+
 #[allow(unused_macros)]
 macro_rules! as_binary_mod {
     ($feat:meta, $uu:path) => {
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 362587a8..0718c2e9 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -10,6 +10,7 @@ use crate::{
     serde_helpers::{
         bson_datetime_as_rfc3339_string,
         hex_string_as_object_id,
+        i64_as_datetime,
         rfc3339_string_as_bson_datetime,
         serialize_object_id_as_hex_string,
         timestamp_as_u32,
@@ -886,6 +887,26 @@ fn test_oid_helpers() {
     assert_eq!(a.oid, oid.to_string());
 }
 
+#[test]
+fn test_i64_as_datetime() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct A {
+        #[serde(with = "i64_as_datetime")]
+        now: i64,
+    }
+
+    let now = DateTime::now();
+    let a = A {
+        now: now.timestamp_millis(),
+    };
+    let doc = to_document(&a).unwrap();
+    assert_eq!(doc.get_datetime("now").unwrap(), &now);
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.now, now.timestamp_millis());
+}
+
 #[test]
 #[cfg(feature = "uuid-0_8")]
 fn test_uuid_0_8_helpers() {

From b20236480e76be316f00332598ad40867145c265 Mon Sep 17 00:00:00 2001
From: Patrick Freed <patrick.freed@mongodb.com>
Date: Thu, 17 Nov 2022 15:11:24 -0500
Subject: [PATCH 014/156] RUST-1062 More efficiently serialize array indexes
 (#384)

---
 src/ser/raw/document_serializer.rs | 33 +++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index ba2447f0..c4899cf0 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -30,17 +30,29 @@ impl<'a> DocumentSerializer<'a> {
         })
     }
 
+    /// Serialize a document key using the provided closure.
+    fn serialize_doc_key_custom<F: FnOnce(&mut Serializer) -> Result<()>>(
+        &mut self,
+        f: F,
+    ) -> Result<()> {
+        // push a dummy element type for now, will update this once we serialize the value
+        self.root_serializer.reserve_element_type();
+        f(self.root_serializer)?;
+        self.num_keys_serialized += 1;
+        Ok(())
+    }
+
+    /// Serialize a document key to string using `KeySerializer`.
     fn serialize_doc_key<T>(&mut self, key: &T) -> Result<()>
     where
         T: serde::Serialize + ?Sized,
     {
-        // push a dummy element type for now, will update this once we serialize the value
-        self.root_serializer.reserve_element_type();
-        key.serialize(KeySerializer {
-            root_serializer: &mut *self.root_serializer,
+        self.serialize_doc_key_custom(|rs| {
+            key.serialize(KeySerializer {
+                root_serializer: rs,
+            })?;
+            Ok(())
         })?;
-
-        self.num_keys_serialized += 1;
         Ok(())
     }
 
@@ -63,7 +75,13 @@ impl<'a> serde::ser::SerializeSeq for DocumentSerializer<'a> {
     where
         T: serde::Serialize,
     {
-        self.serialize_doc_key(&self.num_keys_serialized.to_string())?;
+        let index = self.num_keys_serialized;
+        self.serialize_doc_key_custom(|rs| {
+            use std::io::Write;
+            write!(&mut rs.bytes, "{}", index)?;
+            rs.bytes.push(0);
+            Ok(())
+        })?;
         value.serialize(&mut *self.root_serializer)
     }
 
@@ -160,6 +178,7 @@ impl<'a> serde::ser::SerializeTupleStruct for DocumentSerializer<'a> {
 }
 
 /// Serializer used specifically for serializing document keys.
+/// Only keys that serialize to strings will be accepted.
 struct KeySerializer<'a> {
     root_serializer: &'a mut Serializer,
 }

From adc440ee5969e447bc6825a7d83f325c31d24052 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Tue, 29 Nov 2022 12:50:58 -0500
Subject: [PATCH 015/156] minor: bump clippy to 1.65 (#387)

---
 .evergreen/check-clippy.sh                   |  2 +-
 src/raw/document_buf.rs                      | 29 ++++++++++----------
 src/ser/mod.rs                               |  4 +--
 src/ser/raw/mod.rs                           |  2 +-
 src/tests/modules/serializer_deserializer.rs |  2 +-
 src/tests/serde.rs                           |  2 +-
 6 files changed, 19 insertions(+), 22 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index 036b8242..fac04d3e 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.63.0
+CLIPPY_VERSION=1.65.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 0a27396a..ded704e1 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -71,7 +71,7 @@ impl RawDocumentBuf {
     /// Creates a new, empty [`RawDocumentBuf`].
     pub fn new() -> RawDocumentBuf {
         let mut data = Vec::new();
-        data.extend(&MIN_BSON_DOCUMENT_SIZE.to_le_bytes());
+        data.extend(MIN_BSON_DOCUMENT_SIZE.to_le_bytes());
         data.push(0);
         Self { data }
     }
@@ -196,7 +196,7 @@ impl RawDocumentBuf {
     pub fn append(&mut self, key: impl AsRef<str>, value: impl Into<RawBson>) {
         fn append_string(doc: &mut RawDocumentBuf, value: &str) {
             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.as_bytes());
             doc.data.push(0);
         }
@@ -220,7 +220,7 @@ impl RawDocumentBuf {
 
         match value {
             RawBson::Int32(i) => {
-                self.data.extend(&i.to_le_bytes());
+                self.data.extend(i.to_le_bytes());
             }
             RawBson::String(s) => {
                 append_string(self, s.as_str());
@@ -237,32 +237,31 @@ 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);
             }
             RawBson::Boolean(b) => {
-                let byte = if b { 1 } else { 0 };
-                self.data.push(byte);
+                self.data.push(b as u8);
             }
             RawBson::DateTime(dt) => {
-                self.data.extend(&dt.timestamp_millis().to_le_bytes());
+                self.data.extend(dt.timestamp_millis().to_le_bytes());
             }
             RawBson::DbPointer(dbp) => {
                 append_string(self, dbp.namespace.as_str());
-                self.data.extend(&dbp.id.bytes());
+                self.data.extend(dbp.id.bytes());
             }
             RawBson::Decimal128(d) => {
-                self.data.extend(&d.bytes());
+                self.data.extend(d.bytes());
             }
             RawBson::Double(d) => {
-                self.data.extend(&d.to_le_bytes());
+                self.data.extend(d.to_le_bytes());
             }
             RawBson::Int64(i) => {
-                self.data.extend(&i.to_le_bytes());
+                self.data.extend(i.to_le_bytes());
             }
             RawBson::RegularExpression(re) => {
                 append_cstring(self, re.pattern.as_str());
@@ -277,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.as_str());
                 self.data.extend(code_w_scope.scope.into_bytes());
             }
             RawBson::Timestamp(ts) => {
-                self.data.extend(&ts.to_le_i64().to_le_bytes());
+                self.data.extend(ts.to_le_i64().to_le_bytes());
             }
             RawBson::ObjectId(oid) => {
-                self.data.extend(&oid.bytes());
+                self.data.extend(oid.bytes());
             }
             RawBson::Symbol(s) => {
                 append_string(self, s.as_str());
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index fd2c34f9..8c26ee5a 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -134,9 +134,7 @@ pub(crate) fn serialize_bson<W: Write + ?Sized>(
         Bson::String(ref v) => write_string(writer, v),
         Bson::Array(ref v) => serialize_array(writer, v),
         Bson::Document(ref v) => v.to_writer(writer),
-        Bson::Boolean(v) => writer
-            .write_all(&[if v { 0x01 } else { 0x00 }])
-            .map_err(From::from),
+        Bson::Boolean(v) => writer.write_all(&[v as u8]).map_err(From::from),
         Bson::RegularExpression(Regex {
             ref pattern,
             ref options,
diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs
index 64829d4a..af82c06a 100644
--- a/src/ser/raw/mod.rs
+++ b/src/ser/raw/mod.rs
@@ -121,7 +121,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     #[inline]
     fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
         self.update_element_type(ElementType::Boolean)?;
-        self.bytes.push(if v { 1 } else { 0 });
+        self.bytes.push(v as u8);
         Ok(())
     }
 
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index b5f5ba7f..2f476841 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -322,7 +322,7 @@ fn test_serialize_utc_date_time() {
     #[allow(unused)]
     let src = time::OffsetDateTime::from_unix_timestamp(1_286_705_410).unwrap();
     #[cfg(feature = "chrono-0_4")]
-    let src = chrono::Utc.timestamp(1_286_705_410, 0);
+    let src = chrono::Utc.timestamp_opt(1_286_705_410, 0).unwrap();
     let dst = vec![
         18, 0, 0, 0, 9, 107, 101, 121, 0, 208, 111, 158, 149, 43, 1, 0, 0, 0,
     ];
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 0718c2e9..59e94407 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 use crate::{
     bson,

From 5e0bea6d77a1a08162b61b17e97d6f2e2b70f68a Mon Sep 17 00:00:00 2001
From: Sana Verma <sanyaverma0303@gmail.com>
Date: Wed, 30 Nov 2022 11:05:25 -0500
Subject: [PATCH 016/156] RUST-1225 Add base64 string constructor to `Binary`
 (#365)

Co-authored-by: Isabel Atkinson <isabel.atkinson@mongodb.com>
---
 src/binary.rs               | 113 ++++++++++++++++++++++++++++++++++++
 src/bson.rs                 |  61 +------------------
 src/de/mod.rs               |   3 +-
 src/de/serde.rs             |   3 +-
 src/document.rs             |   3 +-
 src/lib.rs                  |   4 +-
 src/tests/modules/binary.rs |  21 +++++++
 src/tests/modules/mod.rs    |   1 +
 8 files changed, 145 insertions(+), 64 deletions(-)
 create mode 100644 src/binary.rs
 create mode 100644 src/tests/modules/binary.rs

diff --git a/src/binary.rs b/src/binary.rs
new file mode 100644
index 00000000..e7a8e789
--- /dev/null
+++ b/src/binary.rs
@@ -0,0 +1,113 @@
+use crate::{spec::BinarySubtype, Document, RawBinaryRef};
+use std::{
+    convert::TryFrom,
+    error,
+    fmt::{self, Display},
+};
+
+/// Represents a BSON binary value.
+#[derive(Debug, Clone, PartialEq)]
+pub struct Binary {
+    /// The subtype of the bytes.
+    pub subtype: BinarySubtype,
+
+    /// The binary bytes.
+    pub bytes: Vec<u8>,
+}
+
+impl Display for Binary {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            fmt,
+            "Binary({:#x}, {})",
+            u8::from(self.subtype),
+            base64::encode(&self.bytes)
+        )
+    }
+}
+
+impl Binary {
+    /// Creates a [`Binary`] from a base64 string and optional [`BinarySubtype`]. If the
+    /// `subtype` argument is `None`, the [`Binary`] constructed will default to
+    /// [`BinarySubtype::Generic`].
+    ///
+    /// ```rust
+    /// # use bson::{Binary, binary::Result};
+    /// # fn example() -> Result<()> {
+    /// let input = base64::encode("hello");
+    /// let binary = Binary::from_base64(input, None)?;
+    /// println!("{:?}", binary);
+    /// // binary: Binary { subtype: Generic, bytes: [104, 101, 108, 108, 111] }
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn from_base64(
+        input: impl AsRef<str>,
+        subtype: impl Into<Option<BinarySubtype>>,
+    ) -> Result<Self> {
+        let bytes = base64::decode(input.as_ref()).map_err(|e| Error::DecodingError {
+            message: e.to_string(),
+        })?;
+        let subtype = match subtype.into() {
+            Some(s) => s,
+            None => BinarySubtype::Generic,
+        };
+        Ok(Binary { subtype, bytes })
+    }
+
+    pub(crate) fn from_extended_doc(doc: &Document) -> Option<Self> {
+        let binary_doc = doc.get_document("$binary").ok()?;
+
+        if let Ok(bytes) = binary_doc.get_str("base64") {
+            let bytes = base64::decode(bytes).ok()?;
+            let subtype = binary_doc.get_str("subType").ok()?;
+            let subtype = hex::decode(subtype).ok()?;
+            if subtype.len() == 1 {
+                Some(Self {
+                    bytes,
+                    subtype: subtype[0].into(),
+                })
+            } else {
+                None
+            }
+        } else {
+            // in non-human-readable mode, RawBinary will serialize as
+            // { "$binary": { "bytes": <bytes>, "subType": <i32> } };
+            let binary = binary_doc.get_binary_generic("bytes").ok()?;
+            let subtype = binary_doc.get_i32("subType").ok()?;
+
+            Some(Self {
+                bytes: binary.clone(),
+                subtype: u8::try_from(subtype).ok()?.into(),
+            })
+        }
+    }
+
+    /// Borrow the contents as a `RawBinaryRef`.
+    pub fn as_raw_binary(&self) -> RawBinaryRef<'_> {
+        RawBinaryRef {
+            bytes: self.bytes.as_slice(),
+            subtype: self.subtype,
+        }
+    }
+}
+
+/// Possible errors that can arise during [`Binary`] construction.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub enum Error {
+    /// While trying to decode from base64, an error was returned.
+    DecodingError { message: String },
+}
+
+impl error::Error for Error {}
+
+impl std::fmt::Display for Error {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Error::DecodingError { message: m } => fmt.write_str(m),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/bson.rs b/src/bson.rs
index 83f8b424..bb8af34f 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -32,8 +32,8 @@ pub use crate::document::Document;
 use crate::{
     oid::{self, ObjectId},
     spec::{BinarySubtype, ElementType},
+    Binary,
     Decimal128,
-    RawBinaryRef,
 };
 
 /// Possible BSON value types.
@@ -1080,65 +1080,6 @@ impl Display for JavaScriptCodeWithScope {
     }
 }
 
-/// Represents a BSON binary value.
-#[derive(Debug, Clone, PartialEq)]
-pub struct Binary {
-    /// The subtype of the bytes.
-    pub subtype: BinarySubtype,
-
-    /// The binary bytes.
-    pub bytes: Vec<u8>,
-}
-
-impl Display for Binary {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        write!(
-            fmt,
-            "Binary({:#x}, {})",
-            u8::from(self.subtype),
-            base64::encode(&self.bytes)
-        )
-    }
-}
-
-impl Binary {
-    pub(crate) fn from_extended_doc(doc: &Document) -> Option<Self> {
-        let binary_doc = doc.get_document("$binary").ok()?;
-
-        if let Ok(bytes) = binary_doc.get_str("base64") {
-            let bytes = base64::decode(bytes).ok()?;
-            let subtype = binary_doc.get_str("subType").ok()?;
-            let subtype = hex::decode(subtype).ok()?;
-            if subtype.len() == 1 {
-                Some(Self {
-                    bytes,
-                    subtype: subtype[0].into(),
-                })
-            } else {
-                None
-            }
-        } else {
-            // in non-human-readable mode, RawBinary will serialize as
-            // { "$binary": { "bytes": <bytes>, "subType": <i32> } };
-            let binary = binary_doc.get_binary_generic("bytes").ok()?;
-            let subtype = binary_doc.get_i32("subType").ok()?;
-
-            Some(Self {
-                bytes: binary.clone(),
-                subtype: u8::try_from(subtype).ok()?.into(),
-            })
-        }
-    }
-
-    /// Borrow the contents as a `RawBinaryRef`.
-    pub fn as_raw_binary(&self) -> RawBinaryRef<'_> {
-        RawBinaryRef {
-            bytes: self.bytes.as_slice(),
-            subtype: self.subtype,
-        }
-    }
-}
-
 /// Represents a DBPointer. (Deprecated)
 #[derive(Debug, Clone, PartialEq)]
 pub struct DbPointer {
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 5078263e..05b3214b 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -33,11 +33,12 @@ pub use self::{
 use std::io::Read;
 
 use crate::{
-    bson::{Array, Binary, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
+    bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     oid::{self, ObjectId},
     raw::RawBinaryRef,
     ser::write_i32,
     spec::{self, BinarySubtype},
+    Binary,
     Decimal128,
 };
 
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 4598a935..3045f643 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -21,13 +21,14 @@ use serde::de::{
 use serde_bytes::ByteBuf;
 
 use crate::{
-    bson::{Binary, Bson, DbPointer, JavaScriptCodeWithScope, Regex, Timestamp},
+    bson::{Bson, DbPointer, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
     document::{Document, IntoIter},
     oid::ObjectId,
     raw::{RawBsonRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     spec::BinarySubtype,
     uuid::UUID_NEWTYPE_NAME,
+    Binary,
     Decimal128,
 };
 
diff --git a/src/document.rs b/src/document.rs
index fedc38a1..b8d1600c 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -13,11 +13,12 @@ use indexmap::IndexMap;
 use serde::de::Error;
 
 use crate::{
-    bson::{Array, Binary, Bson, Timestamp},
+    bson::{Array, Bson, Timestamp},
     de::{deserialize_bson_kvp, ensure_read_exactly, read_i32, MIN_BSON_DOCUMENT_SIZE},
     oid::ObjectId,
     ser::{serialize_bson, write_i32},
     spec::BinarySubtype,
+    Binary,
     Decimal128,
 };
 
diff --git a/src/lib.rs b/src/lib.rs
index ed301c54..9e17cffe 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -269,8 +269,9 @@
 
 #[doc(inline)]
 pub use self::{
-    bson::{Array, Binary, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
+    bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
+    binary::Binary,
     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,
@@ -291,6 +292,7 @@ pub use self::{
 #[macro_use]
 mod macros;
 mod bson;
+pub mod binary;
 pub mod datetime;
 pub mod de;
 pub mod decimal128;
diff --git a/src/tests/modules/binary.rs b/src/tests/modules/binary.rs
new file mode 100644
index 00000000..d26c4d65
--- /dev/null
+++ b/src/tests/modules/binary.rs
@@ -0,0 +1,21 @@
+use crate::{spec::BinarySubtype, tests::LOCK, Binary};
+
+#[test]
+fn binary_from_base64() {
+    let _guard = LOCK.run_concurrently();
+
+    let input = base64::encode("hello");
+    let produced = Binary::from_base64(input, None).unwrap();
+    let expected = Binary {
+        bytes: "hello".as_bytes().to_vec(),
+        subtype: BinarySubtype::Generic,
+    };
+    assert_eq!(produced, expected);
+
+    let produced = Binary::from_base64("", BinarySubtype::Uuid).unwrap();
+    let expected = Binary {
+        bytes: "".as_bytes().to_vec(),
+        subtype: BinarySubtype::Uuid,
+    };
+    assert_eq!(produced, expected);
+}
diff --git a/src/tests/modules/mod.rs b/src/tests/modules/mod.rs
index 36c1e4fd..d55a287e 100644
--- a/src/tests/modules/mod.rs
+++ b/src/tests/modules/mod.rs
@@ -1,3 +1,4 @@
+mod binary;
 mod bson;
 mod document;
 mod lock;

From 56dc006448d4a8c70a83bb606509477d673c59b2 Mon Sep 17 00:00:00 2001
From: Mark Smith <judy@judy.co.uk>
Date: Thu, 15 Dec 2022 15:45:16 +0000
Subject: [PATCH 017/156] Fix links in the Feature Flags table. (#388)

---
 README.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index 70023fac..c4e7729e 100644
--- a/README.md
+++ b/README.md
@@ -44,12 +44,12 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 
 #### Feature Flags
 
-| Feature      | Description                                                                                         | Extra dependencies | Default |
-|:-------------|:----------------------------------------------------------------------------------------------------|:-------------------|:--------|
-| `chrono-0_4` | Enable support for v0.4 of the [`chrono`](docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
-| `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
-| `uuid-1`     | Enable support for v1.x of the [`uuid`](docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
-| `serde_with` | Enable [`serde_with`](docs.rs/serde_with/latest) integrations for `bson::DateTime` and `bson::Uuid` | serde_with         | no      |
+| Feature      | Description                                                                                                 | Extra dependencies | Default |
+| :----------- | :---------------------------------------------------------------------------------------------------------- | :----------------- | :------ |
+| `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
+| `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
+| `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
+| `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/latest) integrations for `bson::DateTime` and `bson::Uuid` | serde_with         | no      |
 
 ## Overview of the BSON Format
 

From 739b84b008910d3b956e7673e3c7dd288da93a6a Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 4 Jan 2023 16:11:04 -0500
Subject: [PATCH 018/156] RUST-782 Add hyperlinks for all types in rustdoc
 (#389)

---
 src/binary.rs                      |  4 +--
 src/bson.rs                        | 49 +++++++++++++++++-------------
 src/datetime.rs                    | 18 +++++------
 src/de/error.rs                    |  7 +++--
 src/de/mod.rs                      |  8 ++---
 src/de/raw.rs                      | 28 ++++++++---------
 src/de/serde.rs                    |  2 +-
 src/document.rs                    | 12 ++++----
 src/lib.rs                         | 16 +++++-----
 src/raw/array_buf.rs               | 16 +++++-----
 src/raw/bson.rs                    | 46 ++++++++++++++--------------
 src/raw/bson_ref.rs                | 42 ++++++++++++-------------
 src/raw/document.rs                |  2 +-
 src/raw/document_buf.rs            | 10 +++---
 src/raw/mod.rs                     |  6 ++--
 src/raw/serde.rs                   |  6 ++--
 src/ser/mod.rs                     | 10 +++---
 src/ser/raw/document_serializer.rs |  2 +-
 src/ser/raw/value_serializer.rs    |  2 +-
 src/ser/serde.rs                   |  6 ++--
 src/serde_helpers.rs               |  4 +--
 src/spec.rs                        |  2 +-
 src/tests/spec/corpus.rs           |  4 +--
 src/uuid/mod.rs                    | 26 ++++++++--------
 24 files changed, 168 insertions(+), 160 deletions(-)

diff --git a/src/binary.rs b/src/binary.rs
index e7a8e789..2a6d0fa3 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -28,7 +28,7 @@ impl Display for Binary {
 
 impl Binary {
     /// Creates a [`Binary`] from a base64 string and optional [`BinarySubtype`]. If the
-    /// `subtype` argument is `None`, the [`Binary`] constructed will default to
+    /// `subtype` argument is [`None`], the [`Binary`] constructed will default to
     /// [`BinarySubtype::Generic`].
     ///
     /// ```rust
@@ -83,7 +83,7 @@ impl Binary {
         }
     }
 
-    /// Borrow the contents as a `RawBinaryRef`.
+    /// Borrow the contents as a [`RawBinaryRef`].
     pub fn as_raw_binary(&self) -> RawBinaryRef<'_> {
         RawBinaryRef {
             bytes: self.bytes.as_slice(),
diff --git a/src/bson.rs b/src/bson.rs
index bb8af34f..3780b12e 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -514,7 +514,7 @@ impl Bson {
         }
     }
 
-    /// Get the `ElementType` of this value.
+    /// Get the [`ElementType`] of this value.
     pub fn element_type(&self) -> ElementType {
         match *self {
             Bson::Double(..) => ElementType::Double,
@@ -841,7 +841,8 @@ impl Bson {
 
 /// Value helpers
 impl Bson {
-    /// If `Bson` is `Double`, return its value as an `f64`. Returns `None` otherwise
+    /// If `self` is [`Double`](Bson::Double), return its value as an `f64`. Returns [`None`]
+    /// otherwise.
     pub fn as_f64(&self) -> Option<f64> {
         match *self {
             Bson::Double(v) => Some(v),
@@ -849,7 +850,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `String`, return its value as a `&str`. Returns `None` otherwise
+    /// If `self` is [`String`](Bson::String), return its value as a `&str`. Returns [`None`]
+    /// otherwise.
     pub fn as_str(&self) -> Option<&str> {
         match *self {
             Bson::String(ref s) => Some(s),
@@ -857,8 +859,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `String`, return a mutable reference to its value as a `str`. Returns `None`
-    /// otherwise
+    /// If `self` is [`String`](Bson::String), return a mutable reference to its value as a [`str`].
+    /// Returns [`None`] otherwise.
     pub fn as_str_mut(&mut self) -> Option<&mut str> {
         match *self {
             Bson::String(ref mut s) => Some(s),
@@ -866,7 +868,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Array`, return its value. Returns `None` otherwise
+    /// If `self` is [`Array`](Bson::Array), return its value. Returns [`None`] otherwise.
     pub fn as_array(&self) -> Option<&Array> {
         match *self {
             Bson::Array(ref v) => Some(v),
@@ -874,7 +876,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Array`, return a mutable reference to its value. Returns `None` otherwise
+    /// If `self` is [`Array`](Bson::Array), return a mutable reference to its value. Returns
+    /// [`None`] otherwise.
     pub fn as_array_mut(&mut self) -> Option<&mut Array> {
         match *self {
             Bson::Array(ref mut v) => Some(v),
@@ -882,7 +885,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Document`, return its value. Returns `None` otherwise
+    /// If `self` is [`Document`](Bson::Document), return its value. Returns [`None`] otherwise.
     pub fn as_document(&self) -> Option<&Document> {
         match *self {
             Bson::Document(ref v) => Some(v),
@@ -890,7 +893,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Document`, return a mutable reference to its value. Returns `None` otherwise
+    /// If `self` is [`Document`](Bson::Document), return a mutable reference to its value. Returns
+    /// [`None`] otherwise.
     pub fn as_document_mut(&mut self) -> Option<&mut Document> {
         match *self {
             Bson::Document(ref mut v) => Some(v),
@@ -898,7 +902,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Bool`, return its value. Returns `None` otherwise
+    /// If `self` is [`Boolean`](Bson::Boolean), return its value. Returns [`None`] otherwise.
     pub fn as_bool(&self) -> Option<bool> {
         match *self {
             Bson::Boolean(v) => Some(v),
@@ -906,7 +910,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `I32`, return its value. Returns `None` otherwise
+    /// If `self` is [`Int32`](Bson::Int32), return its value. Returns [`None`] otherwise.
     pub fn as_i32(&self) -> Option<i32> {
         match *self {
             Bson::Int32(v) => Some(v),
@@ -914,7 +918,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `I64`, return its value. Returns `None` otherwise
+    /// If `self` is [`Int64`](Bson::Int64), return its value. Returns [`None`] otherwise.
     pub fn as_i64(&self) -> Option<i64> {
         match *self {
             Bson::Int64(v) => Some(v),
@@ -922,7 +926,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Objectid`, return its value. Returns `None` otherwise
+    /// If `self` is [`ObjectId`](Bson::ObjectId), return its value. Returns [`None`] otherwise.
     pub fn as_object_id(&self) -> Option<oid::ObjectId> {
         match *self {
             Bson::ObjectId(v) => Some(v),
@@ -930,7 +934,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Objectid`, return a mutable reference to its value. Returns `None` otherwise
+    /// If `self` is [`ObjectId`](Bson::ObjectId), return a mutable reference to its value. Returns
+    /// [`None`] otherwise.
     pub fn as_object_id_mut(&mut self) -> Option<&mut oid::ObjectId> {
         match *self {
             Bson::ObjectId(ref mut v) => Some(v),
@@ -938,7 +943,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `DateTime`, return its value. Returns `None` otherwise
+    /// If `self` is [`DateTime`](Bson::DateTime), return its value. Returns [`None`] otherwise.
     pub fn as_datetime(&self) -> Option<&crate::DateTime> {
         match *self {
             Bson::DateTime(ref v) => Some(v),
@@ -946,8 +951,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `DateTime`, return a mutable reference to its value. Returns `None`
-    /// otherwise
+    /// If `self` is [`DateTime`](Bson::DateTime), return a mutable reference to its value. Returns
+    /// [`None`] otherwise.
     pub fn as_datetime_mut(&mut self) -> Option<&mut crate::DateTime> {
         match *self {
             Bson::DateTime(ref mut v) => Some(v),
@@ -955,7 +960,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Symbol`, return its value. Returns `None` otherwise
+    /// If `self` is [`Symbol`](Bson::Symbol), return its value. Returns [`None`] otherwise.
     pub fn as_symbol(&self) -> Option<&str> {
         match *self {
             Bson::Symbol(ref v) => Some(v),
@@ -963,7 +968,8 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Symbol`, return a mutable reference to its value. Returns `None` otherwise
+    /// If `self` is [`Symbol`](Bson::Symbol), return a mutable reference to its value. Returns
+    /// [`None`] otherwise.
     pub fn as_symbol_mut(&mut self) -> Option<&mut str> {
         match *self {
             Bson::Symbol(ref mut v) => Some(v),
@@ -971,7 +977,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Timestamp`, return its value. Returns `None` otherwise
+    /// If `self` is [`Timestamp`](Bson::Timestamp), return its value. Returns [`None`] otherwise.
     pub fn as_timestamp(&self) -> Option<Timestamp> {
         match *self {
             Bson::Timestamp(timestamp) => Some(timestamp),
@@ -979,7 +985,7 @@ impl Bson {
         }
     }
 
-    /// If `Bson` is `Null`, return its value. Returns `None` otherwise
+    /// If `self` is [`Null`](Bson::Null), return `()`. Returns [`None`] otherwise.
     pub fn as_null(&self) -> Option<()> {
         match *self {
             Bson::Null => Some(()),
@@ -987,6 +993,7 @@ impl Bson {
         }
     }
 
+    /// If `self` is [`DbPointer`](Bson::DbPointer), return its value.  Returns [`None`] otherwise.
     pub fn as_db_pointer(&self) -> Option<&DbPointer> {
         match self {
             Bson::DbPointer(ref db_pointer) => Some(db_pointer),
diff --git a/src/datetime.rs b/src/datetime.rs
index d212f7a2..8f8b7fee 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -87,10 +87,10 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// ## The `serde_with` feature flag
 ///
 /// The `serde_with` feature can be enabled to support more ergonomic serde attributes for
-/// (de)serializing `chrono::DateTime` from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
+/// (de)serializing [`chrono::DateTime`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
 /// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with` can
-/// handle nested `chrono::DateTime` values (e.g. in `Option`), whereas the former only works on
-/// fields that are exactly `chrono::DateTime`.
+/// handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only works on
+/// fields that are exactly [`chrono::DateTime`].
 /// ```
 /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with"))]
 /// # {
@@ -100,7 +100,7 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// #[serde_with::serde_as]
 /// #[derive(Deserialize, Serialize, PartialEq, Debug)]
 /// struct Foo {
-///   /// Serializes as a BSON datetime rather than using `chrono::DateTime`'s serialization
+///   /// Serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization
 ///   #[serde_as(as = "Option<bson::DateTime>")]
 ///   as_bson: Option<chrono::DateTime<chrono::Utc>>,
 /// }
@@ -139,8 +139,8 @@ impl crate::DateTime {
         Self::from_system_time(SystemTime::now())
     }
 
-    /// Convert the given `chrono::DateTime` into a `bson::DateTime`, truncating it to millisecond
-    /// precision.
+    /// Convert the given [`chrono::DateTime`] into a [`bson::DateTime`](DateTime), truncating it to
+    /// millisecond precision.
     #[cfg(feature = "chrono-0_4")]
     #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
     pub fn from_chrono<T: chrono::TimeZone>(dt: chrono::DateTime<T>) -> Self {
@@ -206,8 +206,8 @@ impl crate::DateTime {
         Self::from_time_private(dt)
     }
 
-    /// Convert the given `time::OffsetDateTime` into a `bson::DateTime`, truncating it to
-    /// millisecond precision.
+    /// Convert the given [`time::OffsetDateTime`] into a [`bson::DateTime`](DateTime), truncating
+    /// it to millisecond precision.
     ///
     /// If the provided time is too far in the future or too far in the past to be represented
     /// by a BSON datetime, either [`DateTime::MAX`] or [`DateTime::MIN`] will be
@@ -455,7 +455,7 @@ pub enum Error {
     /// Error returned when an invalid datetime format is provided to a conversion method.
     #[non_exhaustive]
     InvalidTimestamp { message: String },
-    /// Error returned when a `DateTime` cannot be represented in a particular format.
+    /// Error returned when a [`DateTime`] cannot be represented in a particular format.
     #[non_exhaustive]
     CannotFormat { message: String },
 }
diff --git a/src/de/error.rs b/src/de/error.rs
index 7aee0680..30d4f51a 100644
--- a/src/de/error.rs
+++ b/src/de/error.rs
@@ -15,8 +15,8 @@ pub enum Error {
     /// while decoding a UTF-8 String from the input data.
     InvalidUtf8String(string::FromUtf8Error),
 
-    /// While decoding a `Document` from bytes, an unexpected or unsupported element type was
-    /// encountered.
+    /// While decoding a [`Document`](crate::Document) from bytes, an unexpected or unsupported
+    /// element type was encountered.
     #[non_exhaustive]
     UnrecognizedDocumentElementType {
         /// The key at which an unexpected/unsupported element type was encountered.
@@ -91,7 +91,8 @@ impl de::Error for Error {
 pub type Result<T> = std::result::Result<T, Error>;
 
 impl Bson {
-    /// Method for converting a given `Bson` value to a `serde::de::Unexpected` for error reporting.
+    /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error
+    /// reporting.
     pub(crate) fn as_unexpected(&self) -> Unexpected {
         match self {
             Bson::Array(_) => Unexpected::Seq,
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 05b3214b..909b71cd 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -65,11 +65,11 @@ enum DeserializerHint {
     None,
 
     /// The type being deserialized expects the BSON to contain a binary value with the provided
-    /// subtype. This is currently used to deserialize `bson::Uuid` values.
+    /// subtype. This is currently used to deserialize [`bson::Uuid`] values.
     BinarySubtype(BinarySubtype),
 
     /// The type being deserialized is raw BSON, meaning no allocations should occur as part of
-    /// deserializing and everything should be visited via borrowing or `Copy` if possible.
+    /// deserializing and everything should be visited via borrowing or [`Copy`] if possible.
     RawBson,
 }
 
@@ -433,7 +433,7 @@ impl JavaScriptCodeWithScope {
 
 /// Deserialize a `T` from the provided [`Bson`] value.
 ///
-/// The `Deserializer` used by this function presents itself as human readable, whereas the
+/// The [`Deserializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`from_slice`] does not. This means that this function may deserialize differently
 /// than [`from_slice`] for types that change their deserialization logic depending on whether
 /// the format is human readable or not. To deserialize from [`Bson`] with a deserializer that
@@ -473,7 +473,7 @@ where
 
 /// Deserialize a `T` from the provided [`Document`].
 ///
-/// The `Deserializer` used by this function presents itself as human readable, whereas the
+/// The [`Deserializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`from_slice`] does not. This means that this function may deserialize differently
 /// than [`from_slice`] for types that change their deserialization logic depending on whether
 /// the format is human readable or not. To deserialize from [`Document`] with a deserializer that
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 51842782..a5ef20c1 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -129,7 +129,7 @@ impl<'de> Deserializer<'de> {
     ///
     /// If hinted to use raw BSON, the bytes themselves will be visited using a special newtype
     /// name. Otherwise, the key-value pairs will be accessed in order, either as part of a
-    /// `MapAccess` for documents or a `SeqAccess` for arrays.
+    /// [`MapAccess`] for documents or a [`SeqAccess`] for arrays.
     fn deserialize_document<V>(
         &mut self,
         visitor: V,
@@ -165,7 +165,7 @@ impl<'de> Deserializer<'de> {
         }
     }
 
-    /// Construct a `DocumentAccess` and pass it into the provided closure, returning the
+    /// Construct a [`DocumentAccess`] and pass it into the provided closure, returning the
     /// result of the closure if no other errors are encountered.
     fn access_document<F, O>(&mut self, f: F) -> Result<O>
     where
@@ -188,7 +188,7 @@ impl<'de> Deserializer<'de> {
     }
 
     /// Deserialize the next element type and update `current_type` accordingly.
-    /// Returns `None` if a null byte is read.
+    /// Returns [`None`] if a null byte is read.
     fn deserialize_next_type(&mut self) -> Result<Option<ElementType>> {
         let tag = read_u8(&mut self.bytes)?;
         if tag == 0 {
@@ -505,7 +505,7 @@ impl<'d, 'de> DocumentAccess<'d, 'de> {
     /// Executes a closure that reads from the BSON bytes and returns an error if the number of
     /// bytes read exceeds length_remaining.
     ///
-    /// A mutable reference to this `DocumentAccess` is passed into the closure.
+    /// A mutable reference to this [`DocumentAccess`] is passed into the closure.
     fn read<F, O>(&mut self, f: F) -> Result<O>
     where
         F: FnOnce(&mut Self) -> Result<O>,
@@ -711,7 +711,7 @@ impl<'de> serde::de::Deserializer<'de> for FieldDeserializer {
     }
 }
 
-/// A `MapAccess` used to deserialize entire documents as chunks of bytes without deserializing
+/// A [`MapAccess`] used to deserialize entire documents as chunks of bytes without deserializing
 /// the individual key/value pairs.
 struct RawDocumentAccess<'d> {
     deserializer: RawDocumentDeserializer<'d>,
@@ -751,7 +751,7 @@ impl<'de> serde::de::MapAccess<'de> for RawDocumentAccess<'de> {
         if !self.deserialized_first {
             self.deserialized_first = true;
 
-            // the newtype name will indicate to the `RawBson` enum that the incoming
+            // the newtype name will indicate to the [`RawBson`] enum that the incoming
             // bytes are meant to be treated as a document or array instead of a binary value.
             seed.deserialize(FieldDeserializer {
                 field_name: if self.array {
@@ -1027,7 +1027,7 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut TimestampDeserializer {
     }
 }
 
-/// A `MapAccess` providing access to a BSON datetime being deserialized.
+/// A [`MapAccess`] providing access to a BSON datetime being deserialized.
 ///
 /// If hinted to be raw BSON, this deserializes the serde data model equivalent
 /// of { "$date": <i64 ms from epoch> }.
@@ -1136,7 +1136,7 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut DateTimeDeserializer {
     }
 }
 
-/// A `MapAccess` providing access to a BSON binary being deserialized.
+/// A [`MapAccess`] providing access to a BSON binary being deserialized.
 ///
 /// If hinted to be raw BSON, this deserializes the serde data model equivalent
 /// of { "$binary": { "subType": <u8>, "bytes": <borrowed bytes> } }.
@@ -1241,7 +1241,7 @@ enum BinaryDeserializationStage {
     Done,
 }
 
-/// A `MapAccess` providing access to a BSON code with scope being deserialized.
+/// A [`MapAccess`] providing access to a BSON code with scope being deserialized.
 ///
 /// If hinted to be raw BSON, this deserializes the serde data model equivalent
 /// of { "$code": <borrowed str>, "$scope": <&RawDocument> } }.
@@ -1308,7 +1308,7 @@ impl<'de, 'a> CodeWithScopeDeserializer<'de, 'a> {
     /// Executes a closure that reads from the BSON bytes and returns an error if the number of
     /// bytes read exceeds length_remaining.
     ///
-    /// A mutable reference to this `CodeWithScopeDeserializer` is passed into the closure.
+    /// A mutable reference to this [`CodeWithScopeDeserializer`] is passed into the closure.
     fn read<F, O>(&mut self, f: F) -> Result<O>
     where
         F: FnOnce(&mut Self) -> Result<O>,
@@ -1381,7 +1381,7 @@ enum CodeWithScopeDeserializationStage {
     Done,
 }
 
-/// A `MapAccess` providing access to a BSON DB pointer being deserialized.
+/// A [`MapAccess`] providing access to a BSON DB pointer being deserialized.
 ///
 /// Regardless of the hint, this deserializes the serde data model equivalent
 /// of { "$dbPointer": { "$ref": <borrowed str>, "$id": <bytes> } }.
@@ -1498,7 +1498,7 @@ enum DbPointerDeserializationStage {
     Done,
 }
 
-/// A `MapAccess` providing access to a BSON regular expression being deserialized.
+/// A [`MapAccess`] providing access to a BSON regular expression being deserialized.
 ///
 /// Regardless of the hint, this deserializes the serde data model equivalent
 /// of { "$regularExpression": { "pattern": <borrowed str>, "options": <borrowed str> } }.
@@ -1773,7 +1773,7 @@ impl<'a> BsonBuf<'a> {
     /// Attempts to read a null-terminated UTF-8 cstring from the data.
     ///
     /// If utf8_lossy and invalid UTF-8 is encountered, the unicode replacement character will be
-    /// inserted in place of the offending data, resulting in an owned `String`. Otherwise, the
+    /// inserted in place of the offending data, resulting in an owned [`String`]. Otherwise, the
     /// data will be borrowed as-is.
     fn read_cstr(&mut self) -> Result<Cow<'a, str>> {
         let start = self.index;
@@ -1807,7 +1807,7 @@ impl<'a> BsonBuf<'a> {
     /// Attempts to read a null-terminated UTF-8 string from the data.
     ///
     /// If invalid UTF-8 is encountered, the unicode replacement character will be inserted in place
-    /// of the offending data, resulting in an owned `String`. Otherwise, the data will be
+    /// of the offending data, resulting in an owned [`String`]. Otherwise, the data will be
     /// borrowed as-is.
     fn read_str(&mut self) -> Result<Cow<'a, str>> {
         let start = self._advance_to_len_encoded_str()?;
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 3045f643..8181b677 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -101,7 +101,7 @@ impl<'de> Deserialize<'de> for ObjectId {
 }
 
 impl<'de> Deserialize<'de> for Document {
-    /// Deserialize this value given this `Deserializer`.
+    /// Deserialize this value given this [`Deserializer`].
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
diff --git a/src/document.rs b/src/document.rs
index b8d1600c..f27e923d 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -118,7 +118,7 @@ pub struct Values<'a> {
     inner: indexmap::map::Values<'a, String, Bson>,
 }
 
-/// An iterator over a `Document`'s keys and mutable values.
+/// An iterator over a [`Document`]'s keys and mutable values.
 pub struct IterMut<'a> {
     inner: indexmap::map::IterMut<'a, String, Bson>,
 }
@@ -526,10 +526,10 @@ impl Document {
         }
     }
 
-    /// Attempts to serialize the `Document` into a byte stream.
+    /// Attempts to serialize the [`Document`] into a byte stream.
     ///
     /// While the method signature indicates an owned writer must be passed in, a mutable reference
-    /// may also be passed in due to blanket implementations of `Write` provided in the standard
+    /// may also be passed in due to blanket implementations of [`Write`] provided in the standard
     /// library.
     ///
     /// ```
@@ -592,10 +592,10 @@ impl Document {
         Ok(doc)
     }
 
-    /// Attempts to deserialize a `Document` from a byte stream.
+    /// Attempts to deserialize a [`Document`] from a byte stream.
     ///
     /// While the method signature indicates an owned reader must be passed in, a mutable reference
-    /// may also be passed in due to blanket implementations of `Read` provided in the standard
+    /// may also be passed in due to blanket implementations of [`Read`] provided in the standard
     /// library.
     ///
     /// ```
@@ -624,7 +624,7 @@ impl Document {
         Self::decode(&mut reader, false)
     }
 
-    /// Attempt to deserialize a `Document` that may contain invalid UTF-8 strings from a byte
+    /// Attempt to deserialize a [`Document`] that may contain invalid UTF-8 strings from a byte
     /// stream.
     ///
     /// This is mainly useful when reading raw BSON returned from a MongoDB server, which
diff --git a/src/lib.rs b/src/lib.rs
index 9e17cffe..17dc6435 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -183,7 +183,7 @@
 //!     phones: Vec<String>,
 //! }
 //!
-//! // Some BSON input data as a `Bson`.
+//! // Some BSON input data as a [`Bson`].
 //! let bson_data: Bson = bson!({
 //!     "name": "John Doe",
 //!     "age": 43,
@@ -202,11 +202,11 @@
 //! println!("Redacting {}'s record.", person.name);
 //! person.name = "REDACTED".to_string();
 //!
-//! // Get a serialized version of the input data as a `Bson`.
+//! // Get a serialized version of the input data as a [`Bson`].
 //! let redacted_bson = bson::to_bson(&person).unwrap();
 //! ```
 //!
-//! Any types that implement `Serialize` and `Deserialize` can be used in this way. Doing so helps
+//! Any types that implement [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) can be used in this way. Doing so helps
 //! separate the "business logic" that operates over the data from the (de)serialization logic that
 //! translates the data to/from its serialized form. This can lead to more clear and concise code
 //! that is also less error prone.
@@ -215,15 +215,15 @@
 //!
 //! The BSON format includes a datetime type, which is modeled in this crate by the
 //! [`DateTime`] struct, and the
-//! `Serialize` and `Deserialize` implementations for this struct produce and parse BSON datetimes
+//! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations for this struct produce and parse BSON datetimes
 //! when serializing to or deserializing from BSON. The popular crate [`chrono`](docs.rs/chrono)
-//! also provides a `DateTime` type, but its `Serialize` and `Deserialize` implementations operate
+//! also provides a [`DateTime`] type, but its [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations operate
 //! on strings instead, so when using it with BSON, the BSON datetime type is not used. To work
 //! around this, the `chrono-0_4` feature flag can be enabled. This flag exposes a number of
-//! convenient conversions between `bson::DateTime` and `chrono::DateTime`, including the
+//! convenient conversions between [`bson::DateTime`](crate::DateTime) and [`chrono::DateTime`], including the
 //! [`serde_helpers::chrono_datetime_as_bson_datetime`]
-//! serde helper, which can be used to (de)serialize `chrono::DateTime`s to/from BSON datetimes, and
-//! the `From<chrono::DateTime>` implementation for [`Bson`], which allows `chrono::DateTime` values
+//! serde helper, which can be used to (de)serialize [`chrono::DateTime`]s to/from BSON datetimes, and
+//! the `From<chrono::DateTime>` implementation for [`Bson`], which allows [`chrono::DateTime`] values
 //! to be used in the `doc!` and `bson!` macros.
 //!
 //! e.g.
diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index 3c389d1f..fa696783 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -12,7 +12,7 @@ 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
-/// [`RawDocumentBuf`] or as a field in a `Deserialize` struct.
+/// [`RawDocumentBuf`] or as a field in a [`Deserialize`] struct.
 ///
 /// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`] value that borrows from
 /// the original document without making any additional allocations.
@@ -36,11 +36,11 @@ use super::{bson::RawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter};
 /// # 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.
+/// This type implements [`Deref`](std::ops::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,
@@ -48,7 +48,7 @@ pub struct RawArrayBuf {
 }
 
 impl RawArrayBuf {
-    /// Construct a new, empty `RawArrayBuf`.
+    /// Construct a new, empty [`RawArrayBuf`].
     pub fn new() -> RawArrayBuf {
         Self {
             inner: RawDocumentBuf::new(),
@@ -56,7 +56,7 @@ impl RawArrayBuf {
         }
     }
 
-    /// Construct a new `RawArrayBuf` from the provided `Vec` of 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 {
diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index 9db28505..c216c8fd 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -104,7 +104,7 @@ impl RawBson {
         }
     }
 
-    /// Gets the wrapped `f64` value or returns `None` if the 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<f64> {
         match self {
@@ -113,8 +113,8 @@ impl RawBson {
         }
     }
 
-    /// 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 {
             RawBson::String(s) => Some(s),
@@ -122,7 +122,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the wrapped
+    /// 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 {
@@ -131,7 +131,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a mutable reference to the [`RawArrayBuf`] that's wrapped or returns `None` if the
+    /// 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 {
@@ -140,7 +140,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the wrapped
+    /// 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 {
@@ -149,7 +149,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a mutable reference to the [`RawDocumentBuf`] that's wrapped or returns `None` if the
+    /// 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 {
@@ -158,7 +158,7 @@ impl RawBson {
         }
     }
 
-    /// Gets the wrapped `bool` value or returns `None` if the wrapped value isn't a BSON
+    /// Gets the wrapped `bool` value or returns [`None`] if the wrapped value isn't a BSON
     /// boolean.
     pub fn as_bool(&self) -> Option<bool> {
         match self {
@@ -167,7 +167,7 @@ impl RawBson {
         }
     }
 
-    /// Gets the wrapped `i32` value or returns `None` if the wrapped 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<i32> {
         match self {
@@ -176,7 +176,7 @@ impl RawBson {
         }
     }
 
-    /// Gets the wrapped `i64` value or returns `None` if the wrapped 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<i64> {
         match self {
@@ -185,8 +185,8 @@ impl RawBson {
         }
     }
 
-    /// 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<oid::ObjectId> {
         match self {
             RawBson::ObjectId(v) => Some(*v),
@@ -194,7 +194,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a reference to the [`Binary`] that's wrapped or returns `None` if the wrapped value
+    /// 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<RawBinaryRef<'_>> {
         match self {
@@ -206,7 +206,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a reference to the [`Regex`] that's wrapped or returns `None` if the wrapped value
+    /// 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<RawRegexRef<'_>> {
         match self {
@@ -218,7 +218,7 @@ impl RawBson {
         }
     }
 
-    /// Gets the wrapped [`crate::DateTime`] value or returns `None` if the wrapped value isn't a
+    /// Gets the wrapped [`crate::DateTime`] value or returns [`None`] if the wrapped value isn't a
     /// BSON datetime.
     pub fn as_datetime(&self) -> Option<crate::DateTime> {
         match self {
@@ -227,8 +227,8 @@ impl RawBson {
         }
     }
 
-    /// 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 {
             RawBson::Symbol(v) => Some(v),
@@ -236,7 +236,7 @@ impl RawBson {
         }
     }
 
-    /// Gets the wrapped [`crate::Timestamp`] value or returns `None` if the wrapped value isn't a
+    /// Gets the wrapped [`crate::Timestamp`] value or returns [`None`] if the wrapped value isn't a
     /// BSON datetime.
     pub fn as_timestamp(&self) -> Option<Timestamp> {
         match self {
@@ -245,7 +245,7 @@ impl RawBson {
         }
     }
 
-    /// Returns `Some(())` if this value is null, otherwise returns `None`.
+    /// Returns `Some(())` if this value is null, otherwise returns [`None`].
     pub fn as_null(&self) -> Option<()> {
         match self {
             RawBson::Null => Some(()),
@@ -253,8 +253,8 @@ impl RawBson {
         }
     }
 
-    /// 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<RawDbPointerRef<'_>> {
         match self {
             RawBson::DbPointer(d) => Some(RawDbPointerRef {
@@ -265,7 +265,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a reference to the code that's wrapped or returns `None` if the wrapped value isn't a
+    /// 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 {
@@ -274,7 +274,7 @@ impl RawBson {
         }
     }
 
-    /// Gets a reference to the [`RawJavaScriptCodeWithScope`] that's wrapped or returns `None`
+    /// 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<RawJavaScriptCodeWithScopeRef<'_>> {
         match self {
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index a0668e01..4af7eb45 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -101,7 +101,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the `f64` that's referenced or returns `None` if the referenced value isn't a BSON
+    /// Gets the `f64` that's referenced or returns [`None`] if the referenced value isn't a BSON
     /// double.
     pub fn as_f64(self) -> Option<f64> {
         match self {
@@ -110,7 +110,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the `&str` that's referenced or returns `None` if the referenced value isn't a BSON
+    /// 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 {
@@ -119,7 +119,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`RawArray`] that's referenced or returns `None` if the referenced value
+    /// 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 {
@@ -128,7 +128,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`RawDocument`] that's referenced or returns `None` if the referenced value
+    /// 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 {
@@ -137,7 +137,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the `bool` that's referenced or returns `None` if the referenced value isn't a BSON
+    /// Gets the `bool` that's referenced or returns [`None`] if the referenced value isn't a BSON
     /// boolean.
     pub fn as_bool(self) -> Option<bool> {
         match self {
@@ -146,7 +146,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the `i32` that's referenced or returns `None` if the referenced value isn't a BSON
+    /// Gets the `i32` that's referenced or returns [`None`] if the referenced value isn't a BSON
     /// Int32.
     pub fn as_i32(self) -> Option<i32> {
         match self {
@@ -155,7 +155,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the `i64` that's referenced or returns `None` if the referenced value isn't a BSON
+    /// Gets the `i64` that's referenced or returns [`None`] if the referenced value isn't a BSON
     /// Int64.
     pub fn as_i64(self) -> Option<i64> {
         match self {
@@ -164,7 +164,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`crate::oid::ObjectId`] that's referenced or returns `None` if the referenced
+    /// 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<oid::ObjectId> {
         match self {
@@ -173,8 +173,8 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`RawBinaryRef`] that's referenced or returns `None` if the referenced value isn't
-    /// a BSON binary.
+    /// Gets the [`RawBinaryRef`] that's referenced or returns [`None`] if the referenced value
+    /// isn't a BSON binary.
     pub fn as_binary(self) -> Option<RawBinaryRef<'a>> {
         match self {
             RawBsonRef::Binary(v) => Some(v),
@@ -182,8 +182,8 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`RawRegexRef`] that's referenced or returns `None` if the referenced value isn't a
-    /// BSON regular expression.
+    /// 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<RawRegexRef<'a>> {
         match self {
             RawBsonRef::RegularExpression(v) => Some(v),
@@ -191,7 +191,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`crate::DateTime`] that's referenced or returns `None` if the referenced value
+    /// 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<crate::DateTime> {
         match self {
@@ -200,7 +200,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the symbol that's referenced or returns `None` if the referenced value isn't a BSON
+    /// 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 {
@@ -209,7 +209,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`crate::Timestamp`] that's referenced or returns `None` if the referenced value
+    /// 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<Timestamp> {
         match self {
@@ -218,8 +218,8 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the null value that's referenced or returns `None` if the referenced value isn't a BSON
-    /// null.
+    /// 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(()),
@@ -227,7 +227,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`RawDbPointerRef`] that's referenced or returns `None` if the referenced value
+    /// 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<RawDbPointerRef<'a>> {
         match self {
@@ -236,7 +236,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the code that's referenced or returns `None` if the referenced value isn't a BSON
+    /// 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 {
@@ -245,7 +245,7 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Gets the [`RawJavaScriptCodeWithScope`] that's referenced or returns `None` if the
+    /// 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<RawJavaScriptCodeWithScopeRef<'a>> {
         match self {
@@ -460,7 +460,7 @@ pub struct RawBinaryRef<'a> {
 }
 
 impl<'a> RawBinaryRef<'a> {
-    /// Copy the contents into a `Binary`.
+    /// Copy the contents into a [`Binary`].
     pub fn to_binary(&self) -> Binary {
         Binary {
             subtype: self.subtype,
diff --git a/src/raw/document.rs b/src/raw/document.rs
index b5193067..57a42f10 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -124,7 +124,7 @@ impl RawDocument {
         Ok(RawDocument::new_unchecked(data))
     }
 
-    /// Creates a new `RawDocument` referencing the provided data slice.
+    /// Creates a new [`RawDocument`] referencing the provided data slice.
     pub(crate) fn new_unchecked<D: AsRef<[u8]> + ?Sized>(data: &D) -> &RawDocument {
         // SAFETY:
         //
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index ded704e1..978de443 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -49,11 +49,11 @@ use super::{
 /// # Ok::<(), Error>(())
 /// ```
 ///
-/// This type implements `Deref` to [`RawDocument`], meaning that all methods on [`RawDocument`] are
-/// available on [`RawDocumentBuf`] values as well. This includes [`RawDocument::get`] or any of the
-/// type-specific getters, such as [`RawDocument::get_object_id`] or [`RawDocument::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.
+/// This type implements [`Deref`] to [`RawDocument`], meaning that all methods on [`RawDocument`]
+/// are available on [`RawDocumentBuf`] values as well. This includes [`RawDocument::get`] or any of
+/// the type-specific getters, such as [`RawDocument::get_object_id`] or [`RawDocument::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.
 ///
 /// ```
 /// use bson::raw::RawDocumentBuf;
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index 3eebc030..ced3f1dd 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -12,9 +12,9 @@
 //! A [`RawDocumentBuf`] can be created from a `Vec<u8>` containing raw BSON data. A
 //! [`RawDocument`] can be created from anything that can be borrowed as a `&[u8]`. Both types
 //! can access elements via methods similar to those available on the [`crate::Document`] type.
-//! Note that [`RawDocument::get`] (which [`RawDocument`] calls through to via its `Deref`
-//! implementation) returns a `Result`, since the bytes contained in the document are not fully
-//! validated until trying to access the contained data.
+//! Note that [`RawDocument::get`] (which [`RawDocument`] calls through to via its
+//! [`Deref`](std::ops::Deref) implementation) returns a [`Result`], since the bytes contained in
+//! the document are not fully validated until trying to access the contained data.
 //!
 //! ```rust
 //! use bson::raw::{
diff --git a/src/raw/serde.rs b/src/raw/serde.rs
index e13ffdd7..ab99ef93 100644
--- a/src/raw/serde.rs
+++ b/src/raw/serde.rs
@@ -30,8 +30,8 @@ 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`.
+/// This is used to consolidate the [`Serialize`] and [`Deserialize`] implementations for
+/// [`RawBson`] and [`OwnedRawBson`].
 pub(crate) enum OwnedOrBorrowedRawBson<'a> {
     Owned(RawBson),
     Borrowed(RawBsonRef<'a>),
@@ -68,7 +68,7 @@ impl<'a> From<RawBson> for OwnedOrBorrowedRawBson<'a> {
 }
 
 /// Wrapper around a `Cow<str>` to enable borrowed deserialization.
-/// The default `Deserialize` impl for `Cow` always uses the owned version.
+/// The default [`Deserialize`] impl for [`Cow`] always uses the owned version.
 #[derive(Debug, Deserialize)]
 struct CowStr<'a>(#[serde(borrow)] Cow<'a, str>);
 
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index 8c26ee5a..a15065e8 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -183,9 +183,9 @@ pub(crate) fn serialize_bson<W: Write + ?Sized>(
     }
 }
 
-/// Encode a `T` Serializable into a BSON `Value`.
+/// Encode a `T` Serializable into a [`Bson`] value.
 ///
-/// The `Serializer` used by this function presents itself as human readable, whereas the
+/// The [`Serializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`to_vec`] does not. This means that this function will produce different BSON than
 /// [`to_vec`] for types that change their serialization output depending on whether
 /// the format is human readable or not. To serialize to a [`Document`] with a serializer that
@@ -199,7 +199,7 @@ where
     value.serialize(ser)
 }
 
-/// Encode a `T` into a `Bson` value, configuring the underlying serializer with the provided
+/// Encode a `T` into a [`Bson`] value, configuring the underlying serializer with the provided
 /// options.
 /// ```
 /// # use serde::Serialize;
@@ -223,9 +223,9 @@ where
     value.serialize(ser)
 }
 
-/// Encode a `T` Serializable into a BSON `Document`.
+/// Encode a `T` Serializable into a BSON [`Document`].
 ///
-/// The `Serializer` used by this function presents itself as human readable, whereas the
+/// The [`Serializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`to_vec`] does not. This means that this function will produce different BSON than
 /// [`to_vec`] for types that change their serialization output depending on whether
 /// the format is human readable or not. To serialize to a [`Document`] with a serializer that
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index c4899cf0..e3eb53ee 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -42,7 +42,7 @@ impl<'a> DocumentSerializer<'a> {
         Ok(())
     }
 
-    /// Serialize a document key to string using `KeySerializer`.
+    /// Serialize a document key to string using [`KeySerializer`].
     fn serialize_doc_key<T>(&mut self, key: &T) -> Result<()>
     where
         T: serde::Serialize + ?Sized,
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index ad4d0812..6f7b9945 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -17,7 +17,7 @@ use crate::{
 use super::{document_serializer::DocumentSerializer, Serializer};
 
 /// A serializer used specifically for serializing the serde-data-model form of a BSON type (e.g.
-/// `Binary`) to raw bytes.
+/// [`Binary`]) to raw bytes.
 pub(crate) struct ValueSerializer<'a> {
     root_serializer: &'a mut Serializer,
     state: SerializationStep,
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index 1b4b5b43..d4556bb9 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -151,7 +151,7 @@ impl SerializerOptionsBuilder {
 }
 
 impl Serializer {
-    /// Construct a new `Serializer`.
+    /// Construct a new [`Serializer`].
     #[allow(clippy::new_without_default)]
     pub fn new() -> Serializer {
         Serializer {
@@ -159,7 +159,7 @@ impl Serializer {
         }
     }
 
-    /// Construct a new `Serializer` configured with the provided [`SerializerOptions`].
+    /// Construct a new [`Serializer`] configured with the provided [`SerializerOptions`].
     pub fn new_with_options(options: SerializerOptions) -> Self {
         Serializer { options }
     }
@@ -308,7 +308,7 @@ impl ser::Serializer for Serializer {
                 let is_human_readable = self.is_human_readable();
                 match value.serialize(self)? {
                     Bson::String(s) if is_human_readable => {
-                        // the serializer reports itself as human readable, so `Uuid` will
+                        // the serializer reports itself as human readable, so [`Uuid`] will
                         // serialize itself as a string.
                         let uuid = crate::Uuid::parse_str(s).map_err(Error::custom)?;
                         Ok(Bson::Binary(uuid.into()))
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index e836d1c0..ae133608 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -417,8 +417,8 @@ pub mod hex_string_as_object_id {
     }
 }
 
-/// Contains functions to `serialize` a `i64` integer as `DateTime` and `deserialize`
-/// a `i64` integer from `DateTime`
+/// Contains functions to `serialize` a `i64` integer as [`DateTime`](crate::DateTime) and
+/// `deserialize` a `i64` integer from [`DateTime`](crate::DateTime).
 ///
 /// ### The i64 should represent seconds `(DateTime::timestamp_millis(..))`.
 ///
diff --git a/src/spec.rs b/src/spec.rs
index 04ac478a..1d2d6853 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -58,7 +58,7 @@ const BINARY_SUBTYPE_USER_DEFINED: u8 = 0x80;
 
 /// All available BSON element types.
 ///
-/// Not all element types are representable by the `Bson` type.
+/// Not all element types are representable by the [`Bson`](crate::Bson) type.
 #[repr(u8)]
 #[derive(Debug, Eq, PartialEq, Clone, Copy)]
 pub enum ElementType {
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index ceb1976c..6ded2dd5 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -103,7 +103,7 @@ fn run_test(test: TestFile) {
 
         let canonical_bson = hex::decode(&valid.canonical_bson).expect(&description);
 
-        // these four cover the four ways to create a `Document` from the provided BSON.
+        // these four cover the four ways to create a [`Document`] from the provided BSON.
         let documentfromreader_cb =
             Document::from_reader(canonical_bson.as_slice()).expect(&description);
 
@@ -133,7 +133,7 @@ fn run_test(test: TestFile) {
         let canonical_raw_document_from_slice =
             crate::from_slice::<&RawDocument>(canonical_bson.as_slice()).expect(&description);
 
-        // These cover the ways to serialize those `Documents` back to BSON.
+        // These cover the ways to serialize those [`Documents`] back to BSON.
         let mut documenttowriter_documentfromreader_cb = Vec::new();
         documentfromreader_cb
             .to_writer(&mut documenttowriter_documentfromreader_cb)
diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs
index fe658b60..446e57f0 100644
--- a/src/uuid/mod.rs
+++ b/src/uuid/mod.rs
@@ -13,8 +13,8 @@
 //! binary values. Instead, when serialized with `bson::to_bson`, it produces as a string, and when
 //! serialized with `bson::to_vec`, it produces a binary value with subtype _0_ rather than 4.
 //! Because of this, it is highly recommended to use the [`crate::Uuid`] type when working with BSON
-//! instead of the `uuid` crate's `Uuid`, since [`crate::Uuid`] correctly produces subtype 4 binary
-//! values via either serialization function.
+//! instead of the `uuid` crate's [`Uuid`], since [`crate::Uuid`] correctly produces subtype 4
+//! binary values via either serialization function.
 //!
 //! e.g.
 //!
@@ -44,10 +44,10 @@
 //!
 //! ## The `uuid-1` feature flag
 //!
-//! To facilitate the conversion between [`crate::Uuid`] values and the `uuid` crate's `Uuid`
+//! To facilitate the conversion between [`crate::Uuid`] values and the `uuid` crate's [`Uuid`]
 //! values, the `uuid-1` feature flag can be enabled. This flag exposes a number of convenient
 //! conversions, including the `crate::Uuid::to_uuid_1` method and the `From<uuid::Uuid>`
-//! implementation for `Bson`, which allows the `uuid` crate's `Uuid` values to be used in the
+//! implementation for [`Bson`], which allows the `uuid` crate's [`Uuid`] values to be used in the
 //! `doc!` and `bson!` macros.
 //!
 //! ```
@@ -77,10 +77,10 @@
 //! ## The `serde_with` feature flag
 //!
 //! The `serde_with` feature can be enabled to support more ergonomic serde attributes for
-//! (de)serializing `uuid::Uuid` from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
+//! (de)serializing [`uuid::Uuid`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
 //! crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with` can
-//! handle nested `uuid::Uuid` values (e.g. in `Option`), whereas the former only works on fields
-//! that are exactly `uuid::Uuid`.
+//! handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former only works on
+//! fields that are exactly [`uuid::Uuid`].
 //! ```
 //! # #[cfg(all(feature = "uuid-1", feature = "serde_with"))]
 //! # {
@@ -91,7 +91,7 @@
 //! #[serde_with::serde_as]
 //! #[derive(Deserialize, Serialize, PartialEq, Debug)]
 //! struct Foo {
-//!   /// Serializes as a BSON binary rather than using `uuid::Uuid`'s serialization
+//!   /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization
 //!   #[serde_as(as = "Option<bson::Uuid>")]
 //!   as_bson: Option<uuid::Uuid>,
 //! }
@@ -109,9 +109,9 @@
 //! # Ok::<(), Box<dyn std::error::Error>>(())
 //! ```
 //!
-//! ## Using `crate::Uuid` with non-BSON formats
+//! ## Using [`crate::Uuid`] with non-BSON formats
 //!
-//! [`crate::Uuid`]'s `serde` implementation is the same as `uuid::Uuid`'s
+//! [`crate::Uuid`]'s `serde` implementation is the same as [`uuid::Uuid`]'s
 //! for non-BSON formats such as JSON:
 //!
 //! ``` rust
@@ -147,9 +147,9 @@ use serde::{Deserialize, Serialize};
 
 use crate::{de::BsonVisitor, spec::BinarySubtype, Binary, Bson};
 
-/// Special type name used in the `Uuid` serialization implementation to indicate a BSON
+/// Special type name used in the [`Uuid`] serialization implementation to indicate a BSON
 /// UUID is being serialized or deserialized. The BSON serializers/deserializers will handle this
-/// name specially, but other serializers/deserializers will just ignore it and use `uuid::Uuid`'s
+/// name specially, but other serializers/deserializers will just ignore it and use [`uuid::Uuid`]'s
 /// serde integration.
 pub(crate) const UUID_NEWTYPE_NAME: &str = "$__bson_private_uuid";
 
@@ -160,7 +160,7 @@ pub(crate) const UUID_NEWTYPE_NAME: &str = "$__bson_private_uuid";
 /// [`uuid::Uuid`](https://docs.rs/uuid/latest/uuid/struct.Uuid.html)'s `serde` implementation doesn't
 /// produce or parse BSON UUIDs.
 ///
-/// To enable interop with the `Uuid` type from the `uuid` crate, enable the `uuid-0_8` feature
+/// To enable interop with the [`Uuid`] type from the `uuid` crate, enable the `uuid-0_8` feature
 /// flag.
 ///
 /// For more information on the usage of this type, see the [`uuid`] module-level documentation.

From 3108a180a69613834d4fb2ab124d893a9c42a4d2 Mon Sep 17 00:00:00 2001
From: Patrick Freed <patrick.freed@mongodb.com>
Date: Mon, 9 Jan 2023 12:21:18 -0500
Subject: [PATCH 019/156] RUST-1540 Rename i64_as_datetime to
 i64_as_bson_datetime (#393)

---
 src/serde_helpers.rs | 12 ++++++------
 src/tests/serde.rs   |  6 +++---
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index ae133608..42c1657f 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -23,9 +23,9 @@ pub use hex_string_as_object_id::{
     serialize as serialize_hex_string_as_object_id,
 };
 #[doc(inline)]
-pub use i64_as_datetime::{
-    deserialize as deserialize_i64_from_datetime,
-    serialize as serialize_i64_as_datetime,
+pub use i64_as_bson_datetime::{
+    deserialize as deserialize_i64_from_bson_datetime,
+    serialize as serialize_i64_as_bson_datetime,
 };
 #[doc(inline)]
 pub use rfc3339_string_as_bson_datetime::{
@@ -424,14 +424,14 @@ pub mod hex_string_as_object_id {
 ///
 /// ```rust
 /// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::i64_as_datetime;
+/// # use bson::serde_helpers::i64_as_bson_datetime;
 /// #[derive(Serialize, Deserialize)]
 /// struct Item {
-///     #[serde(with = "i64_as_datetime")]
+///     #[serde(with = "i64_as_bson_datetime")]
 ///     pub now: i64,
 /// }
 /// ```
-pub mod i64_as_datetime {
+pub mod i64_as_bson_datetime {
     use crate::DateTime;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
 
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 59e94407..d2b7d884 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -10,7 +10,7 @@ use crate::{
     serde_helpers::{
         bson_datetime_as_rfc3339_string,
         hex_string_as_object_id,
-        i64_as_datetime,
+        i64_as_bson_datetime,
         rfc3339_string_as_bson_datetime,
         serialize_object_id_as_hex_string,
         timestamp_as_u32,
@@ -888,12 +888,12 @@ fn test_oid_helpers() {
 }
 
 #[test]
-fn test_i64_as_datetime() {
+fn test_i64_as_bson_datetime() {
     let _guard = LOCK.run_concurrently();
 
     #[derive(Serialize, Deserialize)]
     struct A {
-        #[serde(with = "i64_as_datetime")]
+        #[serde(with = "i64_as_bson_datetime")]
         now: i64,
     }
 

From 0b218ab22b5d60a117aa6cd8a21e99459574930b Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 10 Jan 2023 13:30:47 -0500
Subject: [PATCH 020/156] Fix double extjson deserialization (#386) (#395)

Co-authored-by: mitchrmiller <69634302+mitchrmiller@users.noreply.github.com>
---
 src/de/serde.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/de/serde.rs b/src/de/serde.rs
index 8181b677..a219ff82 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -361,7 +361,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                         "Infinity" => Bson::Double(std::f64::INFINITY),
                         "-Infinity" => Bson::Double(std::f64::NEG_INFINITY),
                         "NaN" => Bson::Double(std::f64::NAN),
-                        _ => Bson::Int64(string.parse().map_err(|_| {
+                        _ => Bson::Double(string.parse().map_err(|_| {
                             V::Error::invalid_value(
                                 Unexpected::Str(&string),
                                 &"64-bit signed integer as a string",

From 3960c0a4cba9ce871fb4b9beb3d5c556ef6d8a44 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 12 Jan 2023 15:28:03 -0500
Subject: [PATCH 021/156] RUST-1564 Fix a fuzzer-found failure (#396)

---
 src/de/raw.rs      | 12 +++++++-----
 src/tests/serde.rs |  6 ++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/src/de/raw.rs b/src/de/raw.rs
index a5ef20c1..f8798745 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -511,14 +511,16 @@ impl<'d, 'de> DocumentAccess<'d, 'de> {
         F: FnOnce(&mut Self) -> Result<O>,
     {
         let start_bytes = self.root_deserializer.bytes.bytes_read();
-        let out = f(self);
+        let out = f(self)?;
         let bytes_read = self.root_deserializer.bytes.bytes_read() - start_bytes;
-        *self.length_remaining -= bytes_read as i32;
-
-        if *self.length_remaining < 0 {
+        let bytes_read: i32 = bytes_read
+            .try_into()
+            .map_err(|_| Error::custom("overflow in read size"))?;
+        if bytes_read > *self.length_remaining {
             return Err(Error::custom("length of document too short"));
         }
-        out
+        *self.length_remaining -= bytes_read;
+        Ok(out)
     }
 
     /// Read the next value from the document.
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index d2b7d884..29d3253f 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -1042,3 +1042,9 @@ fn oid_as_hex_string() {
     let doc = to_document(&foo).unwrap();
     assert_eq!(doc.get_str("oid").unwrap(), oid.to_hex());
 }
+
+#[test]
+fn fuzz_regression_00() {
+    let buf: &[u8] = &[227, 0, 35, 4, 2, 0, 255, 255, 255, 127, 255, 255, 255, 47];
+    let _ = crate::from_slice::<Document>(buf);
+}

From a6a9dc9601a5cb5a8f2031b3c27ed84c61bff01d Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 13 Jan 2023 15:12:48 -0500
Subject: [PATCH 022/156] minor: update version numbers for 2.5.0 release
 (#399)

---
 Cargo.toml | 3 ++-
 README.md  | 2 +-
 src/lib.rs | 4 ++--
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index aedea92c..db54bf7c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,12 +1,13 @@
 [package]
 name = "bson"
-version = "2.3.0"
+version = "2.5.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
     "Saghm Rossi <saghmrossi@gmail.com>",
     "Patrick Freed <patrick.freed@mongodb.com>",
     "Isabel Atkinson <isabel.atkinson@mongodb.com>",
+    "Abraham Egnor <abraham.egnor@mongodb.com>",
 ]
 description = "Encoding and decoding support for BSON in Rust"
 license = "MIT"
diff --git a/README.md b/README.md
index c4e7729e..012752f8 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.3.0"
+bson = "2.5.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 17dc6435..afe69bf4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.3.0"
+//! bson = "2.5.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in
@@ -264,7 +264,7 @@
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
-#![doc(html_root_url = "https://docs.rs/bson/2.3.0")]
+#![doc(html_root_url = "https://docs.rs/bson/2.5.0")]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 
 #[doc(inline)]

From 94e6d2afe391a7af0389b1722d20189ad4a5e49c Mon Sep 17 00:00:00 2001
From: Martin <bajanam@kean.edu>
Date: Tue, 24 Jan 2023 14:59:12 -0500
Subject: [PATCH 023/156] update team members

---
 .github/workflows/remove_labels.yml | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/remove_labels.yml b/.github/workflows/remove_labels.yml
index 8b027b6a..9dc473b1 100644
--- a/.github/workflows/remove_labels.yml
+++ b/.github/workflows/remove_labels.yml
@@ -6,9 +6,8 @@ on:
     types: [created, edited]
 jobs:
   remove-labels:
-    if: ${{ github.actor != 'bajanam' &&  github.actor != 'patrickfreed'
-        && github.actor != 'abr-egn' && github.actor != 'isabelatkinson'
-        && github.actor !='kmahar'}}
+    if: ${{ github.actor != 'Tom Selander' &&  github.actor != 'patrickfreed'
+        && github.actor != 'abr-egn' && github.actor != 'isabelatkinson'}}
     runs-on: ubuntu-latest
     steps:
       - name: initial labeling

From 79ab64ec484124730027c7a6cb84dd33ea0114f1 Mon Sep 17 00:00:00 2001
From: Patrick Freed <patrick.freed@mongodb.com>
Date: Wed, 1 Feb 2023 10:47:37 -0500
Subject: [PATCH 024/156] minor: improve serde documentation of DateTime and
 ObjectId (#401)

---
 src/datetime.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++-----
 src/oid.rs      | 69 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 135 insertions(+), 9 deletions(-)

diff --git a/src/datetime.rs b/src/datetime.rs
index 8f8b7fee..80bbb786 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -1,4 +1,5 @@
-//! BSON DateTime
+//! Module containing functionality related to BSON DateTimes.
+//! For more information, see the documentation for the [`DateTime`] type.
 
 use std::{
     convert::TryInto,
@@ -57,12 +58,68 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// # }
 /// ```
 ///
+/// ## Serde integration
+///
 /// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
-/// BSON datetime rather than an RFC 3339 formatted string. Additionally, in non-BSON formats, it
-/// will serialize to and deserialize from that format's equivalent of the
-/// [extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) of a datetime.
-/// To serialize a [`chrono::DateTime`] as a BSON datetime, you can use
-/// [`crate::serde_helpers::chrono_datetime_as_bson_datetime`].
+/// BSON datetime rather than an RFC 3339 formatted string.
+///
+/// e.g.
+/// ```rust
+/// use serde::{Serialize, Deserialize};
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Foo {
+///     // serializes as a BSON datetime.
+///     date_time: bson::DateTime,
+///
+///     // serializes as an RFC 3339 / ISO-8601 string.
+///     chrono_datetime: chrono::DateTime<chrono::Utc>,
+/// }
+///
+/// # fn main() -> bson::ser::Result<()> {
+/// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() };
+/// println!("{:?}", bson::to_document(&f)?);
+/// # Ok(())
+/// # }
+/// ```
+/// Produces the following output:
+/// ```js
+/// { "date_time": DateTime("2023-01-23 20:11:47.316 +00:00:00"), "chrono_datetime": "2023-01-23T20:11:47.316114543Z" }
+/// ```
+///
+/// Additionally, in non-BSON formats, it will serialize to and deserialize from that format's
+/// equivalent of the [extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) of a datetime.
+///
+/// e.g.
+/// ```rust
+/// # use serde::Serialize;
+/// # #[derive(Serialize)]
+/// # struct Foo {
+/// #    // serializes as a BSON datetime.
+/// #    date_time: bson::DateTime,
+/// #
+/// #   // serializes as an RFC 3339 / ISO-8601 string.
+/// #   chrono_datetime: chrono::DateTime<chrono::Utc>,
+/// # }
+/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() };
+/// println!("{}", serde_json::to_string(&f)?);
+/// # Ok(())
+/// # }
+/// ```
+/// Produces the following output:
+/// ```js
+/// {"date_time":{"$date":{"$numberLong":"1674504029491"}},"chrono_datetime":"2023-01-23T20:00:29.491791120Z"}
+/// ```
+///
+/// ### `serde_helpers`
+/// The `bson` crate provides a number of useful helpers for serializing and deserializing
+/// various datetime types to and from different formats. For example, to serialize a
+/// [`chrono::DateTime`] as a BSON datetime, you can use
+/// [`crate::serde_helpers::chrono_datetime_as_bson_datetime`]. Similarly, to serialize a BSON
+/// [`DateTime`] to a string, you can use [`crate::serde_helpers::bson_datetime_as_rfc3339_string`].
+/// Check out the [`crate::serde_helpers`] module documentation for a list of all of the helpers
+/// offered by the crate.
 ///
 /// ```rust
 /// # #[cfg(feature = "chrono-0_4")]
@@ -81,10 +138,14 @@ use serde_with::{DeserializeAs, SerializeAs};
 ///     // this requires the "chrono-0_4" feature flag
 ///     #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
 ///     chrono_as_bson: chrono::DateTime<chrono::Utc>,
+///
+///     // serializes as an RFC 3339 / ISO-8601 string.
+///     #[serde(with = "bson::serde_helpers::bson_datetime_as_rfc3339_string")]
+///     bson_as_string: bson::DateTime,
 /// }
 /// # }
 /// ```
-/// ## The `serde_with` feature flag
+/// ### The `serde_with` feature flag
 ///
 /// The `serde_with` feature can be enabled to support more ergonomic serde attributes for
 /// (de)serializing [`chrono::DateTime`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
diff --git a/src/oid.rs b/src/oid.rs
index 037eac86..9161cd8f 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -1,4 +1,5 @@
-//! ObjectId
+//! Module containing functionality related to BSON ObjectIds.
+//! For more information, see the documentation for the [`ObjectId`] type.
 
 use std::{
     convert::TryInto,
@@ -72,7 +73,71 @@ impl fmt::Display for Error {
 
 impl error::Error for Error {}
 
-/// A wrapper around raw 12-byte ObjectId representations.
+/// A wrapper around a raw 12-byte ObjectId.
+///
+/// ## `serde` integration
+/// When serialized to BSON via `serde`, this type produces a BSON ObjectId. In non-BSON formats, it
+/// will serialize to and deserialize from that format's equivalent of the [extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) of a BSON ObjectId.
+///
+/// [`ObjectId`]s can be deserialized from hex strings in all formats.
+///
+/// e.g.
+/// ```rust
+/// use serde::{Serialize, Deserialize};
+/// use bson::oid::ObjectId;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Foo {
+///     oid: ObjectId,
+/// }
+///
+/// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
+/// let f = Foo { oid: ObjectId::new() };
+/// println!("bson: {}", bson::to_document(&f)?);
+/// println!("json: {}", serde_json::to_string(&f)?);
+/// # Ok(())
+/// # }
+/// ```
+/// Produces the following output:
+/// ```text
+/// bson: { "oid": ObjectId("63ceed18f71dda7d8cf21e8e") }
+/// json: {"oid":{"$oid":"63ceed18f71dda7d8cf21e8e"}}
+/// ```
+///
+/// ### `serde_helpers`
+/// The `bson` crate provides a number of useful helpers for serializing and deserializing
+/// various types to and from different formats. For example, to serialize an
+/// [`ObjectId`] as a hex string, you can use
+/// [`crate::serde_helpers::serialize_object_id_as_hex_string`].
+/// Check out the [`crate::serde_helpers`] module documentation for a list of all of the helpers
+/// offered by the crate.
+///
+/// e.g.
+/// ```rust
+/// use serde::{Serialize, Deserialize};
+/// use bson::oid::ObjectId;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Foo {
+///     // Serializes as a BSON ObjectId or extJSON in non-BSON formats
+///     oid: ObjectId,
+///
+///     // Serializes as a hex string in all formats
+///     #[serde(serialize_with = "bson::serde_helpers::serialize_object_id_as_hex_string")]
+///     oid_as_hex: ObjectId,
+/// }
+/// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
+/// let f = Foo { oid: ObjectId::new(), oid_as_hex: ObjectId::new() };
+/// println!("bson: {}", bson::to_document(&f)?);
+/// println!("json: {}", serde_json::to_string(&f)?);
+/// # Ok(())
+/// # }
+/// ```
+/// Produces the following output:
+/// ```text
+/// bson: { "oid": ObjectId("63ceeffd37518221cdc6cda2"), "oid_as_hex": "63ceeffd37518221cdc6cda3" }
+/// json: {"oid":{"$oid":"63ceeffd37518221cdc6cda2"},"oid_as_hex":"63ceeffd37518221cdc6cda3"}
+/// ```
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
 pub struct ObjectId {
     id: [u8; 12],

From fda2cf35c91d28aa76f86e161943b2cbe8bc7812 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 15 Feb 2023 13:29:12 -0500
Subject: [PATCH 025/156] RUST-1592 Support decimal128 to/from human-readable
 strings (#404)

---
 .evergreen/config.yml    |   4 +-
 Cargo.toml               |   3 +-
 serde-tests/json.rs      |   2 +-
 src/bson.rs              |  13 +-
 src/de/serde.rs          |  13 +-
 src/decimal128.rs        | 425 ++++++++++++++++++++++++++++++++++++++-
 src/extjson/de.rs        |   9 +-
 src/extjson/models.rs    |  24 ++-
 src/lib.rs               |   4 +-
 src/ser/serde.rs         |  12 +-
 src/tests/spec/corpus.rs |  77 +++----
 11 files changed, 507 insertions(+), 79 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index fc992e4f..ff09d7ff 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -181,9 +181,9 @@ axes:
   - id: "extra-rust-versions"
     values:
       - id: "min"
-        display_name: "1.53 (minimum supported version)"
+        display_name: "1.56 (minimum supported version)"
         variables:
-          RUST_VERSION: "1.53.0"
+          RUST_VERSION: "1.56.0"
           MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
diff --git a/Cargo.toml b/Cargo.toml
index db54bf7c..8329dcaf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -67,6 +67,7 @@ uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
 serde_with = { version = "1", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
+bitvec = "1.0.1"
 
 [dev-dependencies]
 assert_matches = "1.2"
@@ -78,4 +79,4 @@ chrono = { version = "0.4", features = ["serde", "clock", "std"], default-featur
 
 [package.metadata.docs.rs]
 all-features = true
-rustdoc-args = ["--cfg", "docsrs"]
\ No newline at end of file
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/serde-tests/json.rs b/serde-tests/json.rs
index 473b3f21..417ea6c9 100644
--- a/serde-tests/json.rs
+++ b/serde-tests/json.rs
@@ -48,7 +48,7 @@ fn all_types_json() {
         "undefined": { "$undefined": true },
         "code": { "$code": code },
         "code_w_scope": { "$code": code_w_scope.code, "$scope": scope_json },
-        "decimal": { "$numberDecimalBytes": v.decimal.bytes() },
+        "decimal": { "$numberDecimal": v.decimal.to_string() },
         "symbol": { "$symbol": "ok" },
         "min_key": { "$minKey": 1 },
         "max_key": { "$maxKey": 1 },
diff --git a/src/bson.rs b/src/bson.rs
index 3780b12e..92f93a8b 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -455,7 +455,7 @@ impl Bson {
                 "$date": { "$numberLong": v.timestamp_millis().to_string() },
             }),
             Bson::Symbol(v) => json!({ "$symbol": v }),
-            Bson::Decimal128(_) => panic!("Decimal128 extended JSON not implemented yet."),
+            Bson::Decimal128(v) => json!({ "$numberDecimal": v.to_string() }),
             Bson::Undefined => json!({ "$undefined": true }),
             Bson::MinKey => json!({ "$minKey": 1 }),
             Bson::MaxKey => json!({ "$maxKey": 1 }),
@@ -474,9 +474,6 @@ impl Bson {
     }
 
     /// Converts the Bson value into its [canonical extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-    ///
-    /// Note: extended json encoding for `Decimal128` values is not supported. If this method is
-    /// called on a case which contains a `Decimal128` value, it will panic.
     pub fn into_canonical_extjson(self) -> Value {
         match self {
             Bson::Int32(i) => json!({ "$numberInt": i.to_string() }),
@@ -705,6 +702,14 @@ impl Bson {
                 _ => {}
             },
 
+            ["$numberDecimal"] => {
+                if let Ok(d) = doc.get_str("$numberDecimal") {
+                    if let Ok(d) = d.parse() {
+                        return Bson::Decimal128(d);
+                    }
+                }
+            }
+
             ["$numberDecimalBytes"] => {
                 if let Ok(bytes) = doc.get_binary_generic("$numberDecimalBytes") {
                     if let Ok(b) = bytes.clone().try_into() {
diff --git a/src/de/serde.rs b/src/de/serde.rs
index a219ff82..0ab77187 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -466,10 +466,15 @@ impl<'de> Visitor<'de> for BsonVisitor {
                 }
 
                 "$numberDecimal" => {
-                    return Err(Error::custom(
-                        "deserializing decimal128 values from strings is not currently supported"
-                            .to_string(),
-                    ));
+                    let string: String = visitor.next_value()?;
+                    return Ok(Bson::Decimal128(string.parse::<Decimal128>().map_err(
+                        |_| {
+                            V::Error::invalid_value(
+                                Unexpected::Str(&string),
+                                &"decimal128 as a string",
+                            )
+                        },
+                    )?));
                 }
 
                 "$numberDecimalBytes" => {
diff --git a/src/decimal128.rs b/src/decimal128.rs
index 533b10dd..eb0ee57d 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -2,6 +2,8 @@
 
 use std::{convert::TryInto, fmt};
 
+use bitvec::prelude::*;
+
 /// Struct representing a BSON Decimal128 type.
 ///
 /// Currently, this type can only be used to round-trip through BSON. See
@@ -9,7 +11,7 @@ use std::{convert::TryInto, fmt};
 #[derive(Copy, Clone, PartialEq)]
 pub struct Decimal128 {
     /// BSON bytes containing the decimal128. Stored for round tripping.
-    pub(crate) bytes: [u8; 128 / 8],
+    pub(crate) bytes: [u8; 16],
 }
 
 impl Decimal128 {
@@ -39,6 +41,425 @@ impl fmt::Debug for Decimal128 {
 
 impl fmt::Display for Decimal128 {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self)
+        write!(f, "{}", ParsedDecimal128::new(self))
+    }
+}
+
+impl std::str::FromStr for Decimal128 {
+    type Err = ParseError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(s.parse::<ParsedDecimal128>()?.pack())
+    }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+struct ParsedDecimal128 {
+    sign: bool,
+    kind: Decimal128Kind,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+enum Decimal128Kind {
+    NaN {
+        signalling: bool,
+    },
+    Infinity,
+    Finite {
+        exponent: Exponent,
+        coefficient: Coefficient,
+    },
+}
+
+#[derive(Debug, Clone, PartialEq)]
+struct Exponent([u8; 2]);
+
+impl Exponent {
+    /// The exponent is stored as an unsigned value; `BIAS` is subtracted to get the actual value.
+    const BIAS: i16 = 6176;
+    /// The minimum representable exponent.  This is distinct from the specifications "min" value,
+    /// which marks the point at which exponents are considered subnormal.
+    const TINY: i16 = -6176;
+    /// The maximum representable exponent.
+    const MAX: i16 = 6111;
+
+    /// The number of unused bits in the parsed representation.
+    const UNUSED_BITS: usize = 2;
+    /// The total number of bits in the packed representation.
+    const PACKED_WIDTH: usize = 14;
+
+    fn from_bits(src_bits: &BitSlice<u8, Msb0>) -> Self {
+        let mut bytes = [0u8; 2];
+        bytes.view_bits_mut::<Msb0>()[Self::UNUSED_BITS..].copy_from_bitslice(src_bits);
+        Self(bytes)
+    }
+
+    fn from_native(value: i16) -> Self {
+        let mut bytes = [0u8; 2];
+        bytes.view_bits_mut::<Msb0>().store_be(value + Self::BIAS);
+        Self(bytes)
+    }
+
+    fn bits(&self) -> &BitSlice<u8, Msb0> {
+        &self.0.view_bits::<Msb0>()[Self::UNUSED_BITS..]
+    }
+
+    fn raw(&self) -> u16 {
+        self.0.view_bits::<Msb0>().load_be::<u16>()
+    }
+
+    fn value(&self) -> i16 {
+        (self.raw() as i16) - Self::BIAS
+    }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+struct Coefficient([u8; 16]);
+
+impl Coefficient {
+    /// The number of unused bits in the parsed representation.
+    const UNUSED_BITS: usize = 14;
+    /// The maximum number of digits allowed in a base-10 string representation of the coefficient.
+    const MAX_DIGITS: usize = 34;
+    /// The maximum allowable value of a coefficient.
+    const MAX_VALUE: u128 = 9_999_999_999_999_999_999_999_999_999_999_999;
+
+    fn from_bits(
+        src_prefix: &BitSlice<u8, Msb0>,
+        src_suffix: &BitSlice<u8, Msb0>,
+    ) -> Result<Self, ParseError> {
+        let mut bytes = [0u8; 16];
+        let bits = &mut bytes.view_bits_mut::<Msb0>()[Self::UNUSED_BITS..];
+        let prefix_len = src_prefix.len();
+        bits[0..prefix_len].copy_from_bitslice(src_prefix);
+        bits[prefix_len..].copy_from_bitslice(src_suffix);
+        let out = Self(bytes);
+        if out.value() > Self::MAX_VALUE {
+            Err(ParseError::Overflow)
+        } else {
+            Ok(out)
+        }
+    }
+
+    fn from_native(value: u128) -> Self {
+        let mut bytes = [0u8; 16];
+        bytes.view_bits_mut::<Msb0>().store_be(value);
+        Self(bytes)
+    }
+
+    fn bits(&self) -> &BitSlice<u8, Msb0> {
+        &self.0.view_bits::<Msb0>()[Self::UNUSED_BITS..]
+    }
+
+    fn value(&self) -> u128 {
+        self.0.view_bits::<Msb0>().load_be::<u128>()
+    }
+}
+
+impl ParsedDecimal128 {
+    fn new(source: &Decimal128) -> Self {
+        // BSON byte order is the opposite of the decimal128 spec byte order, so flip 'em.  The rest
+        // of this method could be rewritten to not need this, but readability is helped by
+        // keeping the implementation congruent with the spec.
+        let tmp: [u8; 16] = {
+            let mut tmp = [0u8; 16];
+            tmp.view_bits_mut::<Msb0>()
+                .store_be(source.bytes.view_bits::<Msb0>().load_le::<u128>());
+            tmp
+        };
+        let src_bits = tmp.view_bits::<Msb0>();
+
+        let sign = src_bits[0];
+        let kind = if src_bits[1..5].all() {
+            // Special value
+            if src_bits[5] {
+                Decimal128Kind::NaN {
+                    signalling: src_bits[6],
+                }
+            } else {
+                Decimal128Kind::Infinity
+            }
+        } else {
+            // Finite value
+            let exponent_offset;
+            let coeff_prefix;
+            if src_bits[1..3].all() {
+                exponent_offset = 3;
+                coeff_prefix = bits![static u8, Msb0; 1, 0, 0];
+            } else {
+                exponent_offset = 1;
+                coeff_prefix = bits![static u8, Msb0; 0];
+            }
+            let coeff_offset = exponent_offset + Exponent::PACKED_WIDTH;
+
+            let exponent = Exponent::from_bits(&src_bits[exponent_offset..coeff_offset]);
+            let coefficient = match Coefficient::from_bits(coeff_prefix, &src_bits[coeff_offset..])
+            {
+                Ok(c) => c,
+                // Invalid coefficients get silently replaced with zero.
+                Err(_) => Coefficient([0u8; 16]),
+            };
+            Decimal128Kind::Finite {
+                exponent,
+                coefficient,
+            }
+        };
+        ParsedDecimal128 { sign, kind }
+    }
+
+    fn pack(&self) -> Decimal128 {
+        let mut tmp = [0u8; 16];
+        let dest_bits = tmp.view_bits_mut::<Msb0>();
+
+        dest_bits.set(0, self.sign);
+
+        match &self.kind {
+            Decimal128Kind::NaN { signalling } => {
+                dest_bits[1..6].copy_from_bitslice(bits![u8, Msb0; 1, 1, 1, 1, 1]);
+                dest_bits.set(6, *signalling);
+            }
+            Decimal128Kind::Infinity => {
+                dest_bits[1..6].copy_from_bitslice(bits![u8, Msb0; 1, 1, 1, 1, 0]);
+            }
+            Decimal128Kind::Finite {
+                exponent,
+                coefficient,
+            } => {
+                let mut coeff_bits = coefficient.bits();
+                let exponent_offset;
+                if coeff_bits[0] {
+                    dest_bits.set(1, true);
+                    dest_bits.set(2, true);
+                    coeff_bits = &coeff_bits[3..];
+                    exponent_offset = 3;
+                } else {
+                    coeff_bits = &coeff_bits[1..];
+                    exponent_offset = 1;
+                };
+                let coeff_offset = exponent_offset + Exponent::PACKED_WIDTH;
+                dest_bits[exponent_offset..coeff_offset].copy_from_bitslice(exponent.bits());
+                dest_bits[coeff_offset..].copy_from_bitslice(coeff_bits);
+            }
+        }
+
+        let mut bytes = [0u8; 16];
+        bytes
+            .view_bits_mut::<Msb0>()
+            .store_le(tmp.view_bits::<Msb0>().load_be::<u128>());
+        Decimal128 { bytes }
+    }
+}
+
+impl fmt::Display for ParsedDecimal128 {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // MongoDB diverges from the IEEE spec and requires no sign for NaN
+        if self.sign && !matches!(&self.kind, Decimal128Kind::NaN { .. }) {
+            write!(f, "-")?;
+        }
+        match &self.kind {
+            Decimal128Kind::NaN {
+                signalling: _signalling,
+            } => {
+                /* Likewise, MongoDB requires no 's' prefix for signalling.
+                if *signalling {
+                    write!(f, "s")?;
+                }
+                */
+                write!(f, "NaN")?;
+            }
+            Decimal128Kind::Infinity => write!(f, "Infinity")?,
+            Decimal128Kind::Finite {
+                exponent,
+                coefficient,
+            } => {
+                let coeff_str = format!("{}", coefficient.value());
+                let exp_val = exponent.value();
+                let adj_exp = exp_val + (coeff_str.len() as i16) - 1;
+                if exp_val <= 0 && adj_exp >= -6 {
+                    // Plain notation
+                    if exp_val == 0 {
+                        write!(f, "{}", coeff_str)?;
+                    } else {
+                        let dec_charlen = exp_val.unsigned_abs() as usize;
+                        if dec_charlen >= coeff_str.len() {
+                            write!(f, "0.")?;
+                            write!(f, "{}", "0".repeat(dec_charlen - coeff_str.len()))?;
+                            write!(f, "{}", coeff_str)?;
+                        } else {
+                            let (pre, post) = coeff_str.split_at(coeff_str.len() - dec_charlen);
+                            write!(f, "{}", pre)?;
+                            write!(f, ".")?;
+                            write!(f, "{}", post)?;
+                        }
+                    }
+                } else {
+                    // Exponential notation
+                    let (pre, post) = coeff_str.split_at(1);
+                    write!(f, "{}", pre)?;
+                    if !post.is_empty() {
+                        write!(f, ".{}", post)?;
+                    }
+                    write!(f, "E")?;
+                    if adj_exp > 0 {
+                        write!(f, "+")?;
+                    }
+                    write!(f, "{}", adj_exp)?;
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum ParseError {
+    EmptyExponent,
+    InvalidExponent(std::num::ParseIntError),
+    InvalidCoefficient(std::num::ParseIntError),
+    Overflow,
+    Underflow,
+    InexactRounding,
+}
+
+impl fmt::Display for ParseError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ParseError::EmptyExponent => write!(f, "empty exponent"),
+            ParseError::InvalidExponent(e) => write!(f, "invalid exponent: {}", e),
+            ParseError::InvalidCoefficient(e) => write!(f, "invalid coefficient: {}", e),
+            ParseError::Overflow => write!(f, "overflow"),
+            ParseError::Underflow => write!(f, "underflow"),
+            ParseError::InexactRounding => write!(f, "inexact rounding"),
+        }
+    }
+}
+
+impl std::error::Error for ParseError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            ParseError::InvalidExponent(e) => Some(e),
+            ParseError::InvalidCoefficient(e) => Some(e),
+            _ => None,
+        }
+    }
+}
+
+impl std::str::FromStr for ParsedDecimal128 {
+    type Err = ParseError;
+
+    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
+        let sign;
+        if let Some(rest) = s.strip_prefix(&['-', '+'][..]) {
+            sign = s.starts_with('-');
+            s = rest;
+        } else {
+            sign = false;
+        }
+        let kind = match s.to_ascii_lowercase().as_str() {
+            "nan" => Decimal128Kind::NaN { signalling: false },
+            "snan" => Decimal128Kind::NaN { signalling: true },
+            "infinity" | "inf" => Decimal128Kind::Infinity,
+            finite_str => {
+                // Split into parts
+                let mut decimal_str;
+                let exp_str;
+                match finite_str.split_once('e') {
+                    None => {
+                        decimal_str = finite_str;
+                        exp_str = "0";
+                    }
+                    Some((_, "")) => return Err(ParseError::EmptyExponent),
+                    Some((pre, post)) => {
+                        decimal_str = pre;
+                        exp_str = post;
+                    }
+                }
+                let mut exp = exp_str
+                    .parse::<i16>()
+                    .map_err(ParseError::InvalidExponent)?;
+
+                // Remove decimal point and adjust exponent
+                let joined_str;
+                if let Some((pre, post)) = decimal_str.split_once('.') {
+                    let exp_adj = post.len().try_into().map_err(|_| ParseError::Underflow)?;
+                    exp = exp.checked_sub(exp_adj).ok_or(ParseError::Underflow)?;
+                    joined_str = format!("{}{}", pre, post);
+                    decimal_str = &joined_str;
+                }
+
+                // Strip leading zeros
+                let rest = decimal_str.trim_start_matches('0');
+                decimal_str = if rest.is_empty() { "0" } else { rest };
+
+                // Check decimal precision
+                {
+                    let len = decimal_str.len();
+                    if len > Coefficient::MAX_DIGITS {
+                        decimal_str = round_decimal_str(decimal_str, Coefficient::MAX_DIGITS)?;
+                        let exp_adj = (len - decimal_str.len())
+                            .try_into()
+                            .map_err(|_| ParseError::Overflow)?;
+                        exp = exp.checked_add(exp_adj).ok_or(ParseError::Overflow)?;
+                    }
+                }
+
+                // Check exponent limits
+                if exp < Exponent::TINY {
+                    if decimal_str != "0" {
+                        let delta = (Exponent::TINY - exp)
+                            .try_into()
+                            .map_err(|_| ParseError::Overflow)?;
+                        let new_precision = decimal_str
+                            .len()
+                            .checked_sub(delta)
+                            .ok_or(ParseError::Underflow)?;
+                        decimal_str = round_decimal_str(decimal_str, new_precision)?;
+                    }
+                    exp = Exponent::TINY;
+                }
+                let padded_str;
+                if exp > Exponent::MAX {
+                    if decimal_str != "0" {
+                        let delta = (exp - Exponent::MAX)
+                            .try_into()
+                            .map_err(|_| ParseError::Overflow)?;
+                        if decimal_str
+                            .len()
+                            .checked_add(delta)
+                            .ok_or(ParseError::Overflow)?
+                            > Coefficient::MAX_DIGITS
+                        {
+                            return Err(ParseError::Overflow);
+                        }
+                        padded_str = format!("{}{}", decimal_str, "0".repeat(delta));
+                        decimal_str = &padded_str;
+                    }
+                    exp = Exponent::MAX;
+                }
+
+                // Assemble the final value
+                let exponent = Exponent::from_native(exp);
+                let coeff: u128 = decimal_str
+                    .parse()
+                    .map_err(ParseError::InvalidCoefficient)?;
+                let coefficient = Coefficient::from_native(coeff);
+                Decimal128Kind::Finite {
+                    exponent,
+                    coefficient,
+                }
+            }
+        };
+
+        Ok(Self { sign, kind })
+    }
+}
+
+fn round_decimal_str(s: &str, precision: usize) -> Result<&str, ParseError> {
+    let (pre, post) = s.split_at(precision);
+    // Any nonzero trimmed digits mean it would be an imprecise round.
+    if post.chars().any(|c| c != '0') {
+        return Err(ParseError::InexactRounding);
     }
+    Ok(pre)
 }
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
index 0b97dd42..e4683391 100644
--- a/src/extjson/de.rs
+++ b/src/extjson/de.rs
@@ -112,6 +112,11 @@ impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
             return Ok(Bson::Double(double.parse()?));
         }
 
+        if obj.contains_key("$numberDecimal") {
+            let decimal: models::Decimal128 = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Decimal128(decimal.parse()?));
+        }
+
         if obj.contains_key("$binary") {
             let binary: models::Binary = serde_json::from_value(obj.into())?;
             return Ok(Bson::Binary(binary.parse()?));
@@ -159,10 +164,6 @@ impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
             return Ok(db_ptr.parse()?.into());
         }
 
-        if obj.contains_key("$numberDecimal") {
-            return Err(Error::custom("decimal128 extjson support not implemented"));
-        }
-
         if obj.contains_key("$undefined") {
             let undefined: models::Undefined = serde_json::from_value(obj.into())?;
             return undefined.parse();
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 667123c3..48775113 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -20,7 +20,7 @@ impl Int32 {
         let i: i32 = self.value.parse().map_err(|_| {
             extjson::de::Error::invalid_value(
                 Unexpected::Str(self.value.as_str()),
-                &"expected i32 as a string",
+                &"i32 as a string",
             )
         })?;
         Ok(i)
@@ -39,7 +39,7 @@ impl Int64 {
         let i: i64 = self.value.parse().map_err(|_| {
             extjson::de::Error::invalid_value(
                 Unexpected::Str(self.value.as_str()),
-                &"expected i64 as a string",
+                &"i64 as a string",
             )
         })?;
         Ok(i)
@@ -63,7 +63,7 @@ impl Double {
                 let d: f64 = other.parse().map_err(|_| {
                     extjson::de::Error::invalid_value(
                         Unexpected::Str(other),
-                        &"expected bson double as string",
+                        &"bson double as string",
                     )
                 })?;
                 Ok(d)
@@ -72,6 +72,24 @@ impl Double {
     }
 }
 
+#[derive(Deserialize)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct Decimal128 {
+    #[serde(rename = "$numberDecimal")]
+    value: String,
+}
+
+impl Decimal128 {
+    pub(crate) fn parse(self) -> extjson::de::Result<crate::Decimal128> {
+        self.value.parse().map_err(|_| {
+            extjson::de::Error::invalid_value(
+                Unexpected::Str(&self.value),
+                &"bson decimal128 as string",
+            )
+        })
+    }
+}
+
 #[derive(Serialize, Deserialize)]
 #[serde(deny_unknown_fields)]
 pub(crate) struct ObjectId {
diff --git a/src/lib.rs b/src/lib.rs
index afe69bf4..d940dae9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,7 +43,7 @@
 //!
 //! ## Installation
 //! ### Requirements
-//! - Rust 1.53+
+//! - Rust 1.56+
 //!
 //! ### Importing
 //! This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application,
@@ -260,7 +260,7 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.53.0. This will be rarely be increased, and if it ever is,
+//! The MSRV for this crate is currently 1.56.0. This will be rarely be increased, and if it ever is,
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index d4556bb9..e2866a54 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -695,9 +695,15 @@ impl Serialize for Decimal128 {
     where
         S: ser::Serializer,
     {
-        let mut state = serializer.serialize_struct("$numberDecimal", 1)?;
-        state.serialize_field("$numberDecimalBytes", serde_bytes::Bytes::new(&self.bytes))?;
-        state.end()
+        if serializer.is_human_readable() {
+            let mut state = serializer.serialize_map(Some(1))?;
+            state.serialize_entry("$numberDecimal", &self.to_string())?;
+            state.end()
+        } else {
+            let mut state = serializer.serialize_struct("$numberDecimal", 1)?;
+            state.serialize_field("$numberDecimalBytes", serde_bytes::Bytes::new(&self.bytes))?;
+            state.end()
+        }
     }
 }
 
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 6ded2dd5..88d872ca 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -387,12 +387,6 @@ fn run_test(test: TestFile) {
             }
         }
 
-        // TODO RUST-36: Enable decimal128 tests.
-        // extJSON not implemented for decimal128, so we must stop here.
-        if test.bson_type == "0x13" {
-            continue;
-        }
-
         let cej: serde_json::Value =
             serde_json::from_str(&valid.canonical_extjson).expect(&description);
 
@@ -422,15 +416,12 @@ fn run_test(test: TestFile) {
             }
         }
 
-        // TODO RUST-36: Enable decimal128 tests.
-        if test.bson_type != "0x13" {
-            assert_eq!(
-                Bson::Document(documentfromreader_cb.clone()).into_canonical_extjson(),
-                cej_updated_float,
-                "{}",
-                description
-            );
-        }
+        assert_eq!(
+            Bson::Document(documentfromreader_cb.clone()).into_canonical_extjson(),
+            cej_updated_float,
+            "{}",
+            description
+        );
 
         // native_to_relaxed_extended_json( bson_to_native(cB) ) = cEJ
 
@@ -468,15 +459,12 @@ fn run_test(test: TestFile) {
                 .to_writer(&mut native_to_bson_json_to_native_cej)
                 .unwrap();
 
-            // TODO RUST-36: Enable decimal128 tests.
-            if test.bson_type != "0x13" {
-                assert_eq!(
-                    hex::encode(native_to_bson_json_to_native_cej).to_lowercase(),
-                    valid.canonical_bson.to_lowercase(),
-                    "{}",
-                    description,
-                );
-            }
+            assert_eq!(
+                hex::encode(native_to_bson_json_to_native_cej).to_lowercase(),
+                valid.canonical_bson.to_lowercase(),
+                "{}",
+                description,
+            );
         }
 
         if let Some(ref degenerate_extjson) = valid.degenerate_extjson {
@@ -490,14 +478,11 @@ fn run_test(test: TestFile) {
             let native_to_canonical_extended_json_json_to_native_dej =
                 json_to_native_dej.clone().into_canonical_extjson();
 
-            // TODO RUST-36: Enable decimal128 tests.
-            if test.bson_type != "0x13" {
-                assert_eq!(
-                    native_to_canonical_extended_json_json_to_native_dej, cej,
-                    "{}",
-                    description,
-                );
-            }
+            assert_eq!(
+                native_to_canonical_extended_json_json_to_native_dej, cej,
+                "{}",
+                description,
+            );
 
             // native_to_bson( json_to_native(dEJ) ) = cB (unless lossy)
 
@@ -509,15 +494,12 @@ fn run_test(test: TestFile) {
                     .to_writer(&mut native_to_bson_json_to_native_dej)
                     .unwrap();
 
-                // TODO RUST-36: Enable decimal128 tests.
-                if test.bson_type != "0x13" {
-                    assert_eq!(
-                        hex::encode(native_to_bson_json_to_native_dej).to_lowercase(),
-                        valid.canonical_bson.to_lowercase(),
-                        "{}",
-                        description,
-                    );
-                }
+                assert_eq!(
+                    hex::encode(native_to_bson_json_to_native_dej).to_lowercase(),
+                    valid.canonical_bson.to_lowercase(),
+                    "{}",
+                    description,
+                );
             }
         }
 
@@ -571,23 +553,12 @@ fn run_test(test: TestFile) {
     }
 
     for parse_error in test.parse_errors {
-        // TODO RUST-36: Enable decimal128 tests.
-        if test.bson_type == "0x13" {
-            continue;
-        }
-
         // no special support for dbref convention
         if parse_error.description.contains("DBRef") {
             continue;
         }
 
-        // TODO RUST-36: Enable decimal128 tests.
-        if parse_error.description.contains("$numberDecimal") {
-            continue;
-        }
-
-        let json: serde_json::Value =
-            serde_json::from_str(parse_error.string.as_str()).expect(&parse_error.description);
+        let json: serde_json::Value = serde_json::Value::String(parse_error.string);
 
         if let Ok(bson) = Bson::try_from(json.clone()) {
             // if converting to bson succeeds, assert that translating that bson to bytes fails

From f9a8b52f8bbcfaed089e668b3875788307a5c966 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 2 Mar 2023 14:50:10 -0500
Subject: [PATCH 026/156] RUST-504 Use js timestamps when generating objectids
 (#406)

---
 .evergreen/config.yml        | 23 +++++++++++++++++++++++
 .evergreen/run-wasm-tests.sh | 10 ++++++++++
 Cargo.toml                   |  3 +++
 src/oid.rs                   |  8 ++++++--
 wasm-test/Cargo.toml         | 17 +++++++++++++++++
 wasm-test/src/lib.rs         |  2 ++
 wasm-test/src/test.rs        |  6 ++++++
 7 files changed, 67 insertions(+), 2 deletions(-)
 create mode 100755 .evergreen/run-wasm-tests.sh
 create mode 100644 wasm-test/Cargo.toml
 create mode 100644 wasm-test/src/lib.rs
 create mode 100644 wasm-test/src/test.rs

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index ff09d7ff..7c9ba3af 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -133,6 +133,16 @@ functions:
           ${PREPARE_SHELL}
           .evergreen/check-rustdoc.sh
 
+  "run wasm tests":
+    - command: shell.exec
+      type: test
+      params:
+        shell: bash
+        working_dir: "src"
+        script: |
+          ${PREPARE_SHELL}
+          .evergreen/run-wasm-tests.sh
+
   "init test-results":
     - command: shell.exec
       params:
@@ -177,6 +187,10 @@ tasks:
     commands:
       - func: "run fuzzer"
 
+  - name: "wasm-test"
+    commands:
+      - func: "run wasm tests"
+
 axes:
   - id: "extra-rust-versions"
     values:
@@ -207,6 +221,7 @@ buildvariants:
     - ubuntu1804-test
   tasks:
     - name: "compile-only"
+
 -
   name: "lint"
   display_name: "Lint"
@@ -224,3 +239,11 @@ buildvariants:
     - ubuntu1804-test
   tasks:
     - name: "run-fuzzer"
+
+-
+  name: "wasm"
+  display_name: "WASM"
+  run_on:
+    - ubuntu1804-test
+  tasks:
+    - name: "wasm-test"
\ No newline at end of file
diff --git a/.evergreen/run-wasm-tests.sh b/.evergreen/run-wasm-tests.sh
new file mode 100755
index 00000000..806c675e
--- /dev/null
+++ b/.evergreen/run-wasm-tests.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -o errexit
+
+. ~/.cargo/env
+
+curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+
+cd $(dirname $0)/../wasm-test
+wasm-pack test --node
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 8329dcaf..dde634fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -69,6 +69,9 @@ serde_with = { version = "1", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
 
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+js-sys = "0.3"
+
 [dev-dependencies]
 assert_matches = "1.2"
 criterion = "0.3.0"
diff --git a/src/oid.rs b/src/oid.rs
index 9161cd8f..263fc805 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -2,15 +2,16 @@
 //! For more information, see the documentation for the [`ObjectId`] type.
 
 use std::{
-    convert::TryInto,
     error,
     fmt,
     result,
     str::FromStr,
     sync::atomic::{AtomicUsize, Ordering},
-    time::SystemTime,
 };
 
+#[cfg(not(target_arch = "wasm32"))]
+use std::{convert::TryInto, time::SystemTime};
+
 use hex::{self, FromHexError};
 use rand::{thread_rng, Rng};
 
@@ -240,6 +241,9 @@ impl ObjectId {
     /// Generates a new timestamp representing the current seconds since epoch.
     /// Represented in Big Endian.
     fn gen_timestamp() -> [u8; 4] {
+        #[cfg(target_arch = "wasm32")]
+        let timestamp: u32 = (js_sys::Date::now() / 1000.0) as u32;
+        #[cfg(not(target_arch = "wasm32"))]
         let timestamp: u32 = SystemTime::now()
             .duration_since(SystemTime::UNIX_EPOCH)
             .expect("system clock is before 1970")
diff --git a/wasm-test/Cargo.toml b/wasm-test/Cargo.toml
new file mode 100644
index 00000000..fb583123
--- /dev/null
+++ b/wasm-test/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "bson-wasm-test"
+version = "0.1.0"
+authors = ["Abraham Egnor <abe.egnor@gmail.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
+bson = { path = ".." }
+getrandom = { version = "0.2", features = ["js"] }
+
+[dev-dependencies]
+wasm-bindgen-test = "0.3.0"
\ No newline at end of file
diff --git a/wasm-test/src/lib.rs b/wasm-test/src/lib.rs
new file mode 100644
index 00000000..534ffa4b
--- /dev/null
+++ b/wasm-test/src/lib.rs
@@ -0,0 +1,2 @@
+#[cfg(test)]
+mod test;
\ No newline at end of file
diff --git a/wasm-test/src/test.rs b/wasm-test/src/test.rs
new file mode 100644
index 00000000..8703effa
--- /dev/null
+++ b/wasm-test/src/test.rs
@@ -0,0 +1,6 @@
+use wasm_bindgen_test::wasm_bindgen_test;
+
+#[wasm_bindgen_test]
+fn objectid_new() {
+    let _ = bson::oid::ObjectId::new();
+}
\ No newline at end of file

From d21860b6de67def13126c5e1272472b7d22c5327 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 13 Mar 2023 14:17:21 -0400
Subject: [PATCH 027/156] RUST-1613 Update feature flags table (#407)

---
 src/lib.rs | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index d940dae9..70cc6350 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -59,11 +59,13 @@
 //!
 //! #### Feature Flags
 //!
-//! | Feature      | Description                                                                                         | Extra dependencies | Default |
-//! |:-------------|:----------------------------------------------------------------------------------------------------|:-------------------|:--------|
-//! | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
-//! | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
-//! | `serde_with` | Enable [`serde_with`](docs.rs/serde_with/latest) integrations for `bson::DateTime` and `bson::Uuid` | serde_with         | no      |
+//! | Feature      | Description                                                                                          | Default |
+//! |:-------------|:-----------------------------------------------------------------------------------------------------|:--------|
+//! | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.       | no      |
+//! | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.           | no      |
+//! | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API.           | no      |
+//! | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.           | no      |
+//! | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/latest) integrations for [`DateTime`] and [`Uuid`]. | no      |
 //!
 //! ## BSON values
 //!

From 7c46ba9d2ea1d61a3f65b88307502b45463a19d0 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 13 Mar 2023 14:50:51 -0400
Subject: [PATCH 028/156] release v2.6.0

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index dde634fd..270d2fb7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.5.0"
+version = "2.6.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index 012752f8..7a128708 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.5.0"
+bson = "2.6.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 70cc6350..60c89040 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.5.0"
+//! bson = "2.6.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in
@@ -266,7 +266,7 @@
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
-#![doc(html_root_url = "https://docs.rs/bson/2.5.0")]
+#![doc(html_root_url = "https://docs.rs/bson/2.6.0")]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 
 #[doc(inline)]

From 3cc6dd32993a26f13c4129ea343282ab3908fda7 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 20 Mar 2023 12:55:56 -0400
Subject: [PATCH 029/156] RUST-1617 Update Decimal128 documentation with
 examples of string roundtrips. (#409)

---
 src/decimal128.rs | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/decimal128.rs b/src/decimal128.rs
index eb0ee57d..fecd0f16 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -6,8 +6,21 @@ use bitvec::prelude::*;
 
 /// Struct representing a BSON Decimal128 type.
 ///
-/// Currently, this type can only be used to round-trip through BSON. See
-/// [RUST-36](https://jira.mongodb.org/browse/RUST-36) to track the progress towards a complete implementation.
+/// This type supports conversion to and from human-readable strings via the [std::fmt::Display] and
+/// [std::str::FromStr] traits:
+///
+/// ```rust
+/// # use std::str::FromStr;
+/// # use bson::Decimal128;
+/// # fn example() -> std::result::Result<(), Box<dyn std::error::Error>> {
+/// let value: Decimal128 = "3.14159".parse()?;
+/// assert_eq!("3.14159", format!("{}", value));
+/// let scientific = Decimal128::from_str("1.05E+3")?;
+/// assert_eq!("1.05E+3", scientific.to_string());
+/// # Ok(())
+/// # }
+/// # example().unwrap()
+/// ```
 #[derive(Copy, Clone, PartialEq)]
 pub struct Decimal128 {
     /// BSON bytes containing the decimal128. Stored for round tripping.

From 70b49c5ca52f9909e3ce71742ac7d33ee5d1c125 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 25 Apr 2023 11:11:59 -0400
Subject: [PATCH 030/156] RUST-1635 Document WASM support (#413)

---
 README.md  | 5 +++++
 src/lib.rs | 9 +++++++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 7a128708..6fa99643 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ Encoding and decoding support for BSON in Rust
     - [Modeling BSON with strongly typed data structures](#modeling-bson-with-strongly-typed-data-structures)
     - [Working with datetimes](#working-with-datetimes)
     - [Working with UUIDs](#working-with-uuids)
+    - [WASM support](#wasm-support)
 - [Contributing](#contributing)
 - [Running the Tests](#running-the-tests)
 - [Continuous Integration](#continuous-integration)
@@ -250,6 +251,10 @@ let query = doc! {
 
 See the module-level documentation for the [`bson::uuid` module](https://docs.rs/bson/latest/bson/uuid).
 
+### WASM support
+
+This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `js-sys` crate is used for the current timestamp component of `ObjectId` generation.
+
 ## Minimum supported Rust version (MSRV)
 
 The MSRV for this crate is currently 1.48.0. This will be rarely be increased, and if it ever is,
diff --git a/src/lib.rs b/src/lib.rs
index 60c89040..130f7028 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -260,6 +260,11 @@
 //!
 //! See the module level documentation for the [`uuid`] module.
 //!
+//! ## WASM support
+//!
+//! This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `js-sys` crate is
+//! used for the current timestamp component of `ObjectId` generation.
+//!
 //! ## Minimum supported Rust version (MSRV)
 //!
 //! The MSRV for this crate is currently 1.56.0. This will be rarely be increased, and if it ever is,
@@ -271,9 +276,9 @@
 
 #[doc(inline)]
 pub use self::{
+    binary::Binary,
     bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
-    binary::Binary,
     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,
@@ -293,8 +298,8 @@ pub use self::{
 
 #[macro_use]
 mod macros;
-mod bson;
 pub mod binary;
+mod bson;
 pub mod datetime;
 pub mod de;
 pub mod decimal128;

From 818e90f16266793f819f2647a031c4ad3dc2b595 Mon Sep 17 00:00:00 2001
From: liyixin <601947961@qq.com>
Date: Wed, 17 May 2023 01:28:51 +0800
Subject: [PATCH 031/156] update ahash from 0.7.6 to 0.8.3 (#414)

---
 .evergreen/Cargo.lock.msrv | 739 +++++++++++++++++++++++++------------
 Cargo.toml                 |   2 +-
 2 files changed, 510 insertions(+), 231 deletions(-)

diff --git a/.evergreen/Cargo.lock.msrv b/.evergreen/Cargo.lock.msrv
index 39a9f2e1..90d589d7 100644
--- a/.evergreen/Cargo.lock.msrv
+++ b/.evergreen/Cargo.lock.msrv
@@ -4,15 +4,25 @@ version = 3
 
 [[package]]
 name = "ahash"
-version = "0.7.4"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
+checksum = "57e6e951cfbb2db8de1828d49073a113a29fd7117b1596caa781a258c7e38d72"
 dependencies = [
+ "cfg-if",
  "getrandom",
  "once_cell",
  "version_check",
 ]
 
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "ansi_term"
 version = "0.11.0"
@@ -34,28 +44,28 @@ version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
  "winapi",
 ]
 
 [[package]]
 name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "base64"
-version = "0.13.0"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
 [[package]]
 name = "bit-set"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
+checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
 dependencies = [
  "bit-vec",
 ]
@@ -72,17 +82,31 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
 [[package]]
 name = "bson"
-version = "2.3.0"
+version = "2.6.0"
 dependencies = [
  "ahash",
  "assert_matches",
  "base64",
+ "bitvec",
  "chrono",
  "criterion",
  "hex",
  "indexmap",
+ "js-sys",
  "lazy_static",
  "pretty_assertions",
  "proptest",
@@ -92,26 +116,15 @@ dependencies = [
  "serde_json",
  "serde_with",
  "time",
- "uuid",
-]
-
-[[package]]
-name = "bstr"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
-dependencies = [
- "lazy_static",
- "memchr",
- "regex-automata",
- "serde",
+ "uuid 0.8.2",
+ "uuid 1.1.2",
 ]
 
 [[package]]
 name = "bumpalo"
-version = "3.8.0"
+version = "3.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
+checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
 
 [[package]]
 name = "byteorder"
@@ -121,12 +134,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "cast"
-version = "0.2.7"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
-dependencies = [
- "rustc_version",
-]
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
+name = "cc"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
 
 [[package]]
 name = "cfg-if"
@@ -136,11 +152,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.19"
+version = "0.4.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
 dependencies = [
- "libc",
+ "iana-time-zone",
  "num-integer",
  "num-traits",
  "serde",
@@ -149,20 +165,26 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "2.33.3"
+version = "2.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
 dependencies = [
  "bitflags",
  "textwrap",
  "unicode-width",
 ]
 
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+
 [[package]]
 name = "criterion"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
+checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
 dependencies = [
  "atty",
  "cast",
@@ -186,9 +208,9 @@ dependencies = [
 
 [[package]]
 name = "criterion-plot"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
+checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
 dependencies = [
  "cast",
  "itertools",
@@ -196,9 +218,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.1"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -206,9 +228,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
 dependencies = [
  "cfg-if",
  "crossbeam-epoch",
@@ -217,36 +239,34 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.5"
+version = "0.9.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
+checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
 dependencies = [
+ "autocfg",
  "cfg-if",
  "crossbeam-utils",
- "lazy_static",
  "memoffset",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.5"
+version = "0.8.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
+checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
 dependencies = [
  "cfg-if",
- "lazy_static",
 ]
 
 [[package]]
 name = "csv"
-version = "1.1.6"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
+checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad"
 dependencies = [
- "bstr",
  "csv-core",
- "itoa 0.4.7",
+ "itoa",
  "ryu",
  "serde",
 ]
@@ -262,19 +282,19 @@ dependencies = [
 
 [[package]]
 name = "ctor"
-version = "0.1.20"
+version = "0.1.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
+checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
 dependencies = [
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
 name = "darling"
-version = "0.13.0"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -282,27 +302,27 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.13.0"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
  "strsim",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.13.0"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
 dependencies = [
  "darling_core",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -313,9 +333,39 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 
 [[package]]
 name = "either"
-version = "1.6.1"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+
+[[package]]
+name = "errno"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
 
 [[package]]
 name = "fnv"
@@ -323,11 +373,17 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
 [[package]]
 name = "getrandom"
-version = "0.2.3"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
 dependencies = [
  "cfg-if",
  "libc",
@@ -342,9 +398,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
 
 [[package]]
 name = "hashbrown"
-version = "0.9.1"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "hermit-abi"
@@ -355,12 +411,50 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
+
 [[package]]
 name = "hex"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
+[[package]]
+name = "iana-time-zone"
+version = "0.1.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "ident_case"
 version = "1.0.1"
@@ -369,40 +463,54 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
 [[package]]
 name = "indexmap"
-version = "1.6.2"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
  "hashbrown",
 ]
 
 [[package]]
-name = "itertools"
-version = "0.10.1"
+name = "instant"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 dependencies = [
- "either",
+ "cfg-if",
 ]
 
 [[package]]
-name = "itoa"
-version = "0.4.7"
+name = "io-lifetimes"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
+dependencies = [
+ "hermit-abi 0.3.1",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
 
 [[package]]
 name = "itoa"
-version = "1.0.2"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
 
 [[package]]
 name = "js-sys"
-version = "0.3.55"
+version = "0.3.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
+checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -415,39 +523,51 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.121"
+version = "0.2.144"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
+checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
+
+[[package]]
+name = "libm"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
 
 [[package]]
 name = "log"
-version = "0.4.14"
+version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 dependencies = [
  "cfg-if",
 ]
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memoffset"
-version = "0.6.4"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "num-integer"
-version = "0.1.44"
+version = "0.1.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
 dependencies = [
  "autocfg",
  "num-traits",
@@ -455,20 +575,21 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
 dependencies = [
  "autocfg",
+ "libm",
 ]
 
 [[package]]
 name = "num_cpus"
-version = "1.13.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.2.6",
  "libc",
 ]
 
@@ -483,9 +604,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.7.2"
+version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
 
 [[package]]
 name = "oorandom"
@@ -495,18 +616,18 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
 name = "output_vt100"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
+checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
 dependencies = [
  "winapi",
 ]
 
 [[package]]
 name = "plotters"
-version = "0.3.1"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
+checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
 dependencies = [
  "num-traits",
  "plotters-backend",
@@ -517,24 +638,24 @@ dependencies = [
 
 [[package]]
 name = "plotters-backend"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
+checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
 
 [[package]]
 name = "plotters-svg"
-version = "0.3.1"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
+checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
 dependencies = [
  "plotters-backend",
 ]
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.10"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "pretty_assertions"
@@ -550,18 +671,18 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.27"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16"
 dependencies = [
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
 name = "proptest"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
+checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70"
 dependencies = [
  "bit-set",
  "bitflags",
@@ -572,9 +693,10 @@ dependencies = [
  "rand",
  "rand_chacha",
  "rand_xorshift",
- "regex-syntax",
+ "regex-syntax 0.6.29",
  "rusty-fork",
  "tempfile",
+ "unarray",
 ]
 
 [[package]]
@@ -591,23 +713,28 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
 
 [[package]]
 name = "quote"
-version = "1.0.9"
+version = "1.0.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
 dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
 [[package]]
 name = "rand"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
  "rand_chacha",
  "rand_core",
- "rand_hc",
 ]
 
 [[package]]
@@ -622,22 +749,13 @@ dependencies = [
 
 [[package]]
 name = "rand_core"
-version = "0.6.3"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
  "getrandom",
 ]
 
-[[package]]
-name = "rand_hc"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
-dependencies = [
- "rand_core",
-]
-
 [[package]]
 name = "rand_xorshift"
 version = "0.3.0"
@@ -649,83 +767,70 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.5.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
 dependencies = [
- "autocfg",
- "crossbeam-deque",
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.9.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "lazy_static",
  "num_cpus",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.10"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "regex"
-version = "1.5.4"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
 dependencies = [
- "regex-syntax",
+ "regex-syntax 0.7.1",
 ]
 
-[[package]]
-name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-
 [[package]]
 name = "regex-syntax"
-version = "0.6.25"
+version = "0.6.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 
 [[package]]
-name = "remove_dir_all"
-version = "0.5.3"
+name = "regex-syntax"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
+checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
 
 [[package]]
-name = "rustc_version"
-version = "0.4.0"
+name = "rustix"
+version = "0.37.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
 dependencies = [
- "semver",
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "rustversion"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
-
 [[package]]
 name = "rusty-fork"
 version = "0.3.0"
@@ -740,9 +845,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.5"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
 
 [[package]]
 name = "same-file"
@@ -759,26 +864,20 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
-[[package]]
-name = "semver"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
-
 [[package]]
 name = "serde"
-version = "1.0.126"
+version = "1.0.163"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_bytes"
-version = "0.11.5"
+version = "0.11.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9"
+checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
 dependencies = [
  "serde",
 ]
@@ -795,48 +894,47 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.126"
+version = "1.0.163"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.16",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.64"
+version = "1.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
 dependencies = [
  "indexmap",
- "itoa 0.4.7",
+ "itoa",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_with"
-version = "1.11.0"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3"
+checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
 dependencies = [
- "rustversion",
  "serde",
  "serde_with_macros",
 ]
 
 [[package]]
 name = "serde_with_macros"
-version = "1.5.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e"
+checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
 dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -847,27 +945,43 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
 [[package]]
 name = "syn"
-version = "1.0.73"
+version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
 dependencies = [
  "proc-macro2",
  "quote",
- "unicode-xid",
+ "unicode-ident",
 ]
 
+[[package]]
+name = "syn"
+version = "2.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
 [[package]]
 name = "tempfile"
-version = "3.2.0"
+version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
 dependencies = [
  "cfg-if",
- "libc",
- "rand",
+ "fastrand",
  "redox_syscall",
- "remove_dir_all",
- "winapi",
+ "rustix",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -885,7 +999,7 @@ version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
 dependencies = [
- "itoa 1.0.2",
+ "itoa",
  "libc",
  "num_threads",
  "time-macros",
@@ -908,16 +1022,22 @@ dependencies = [
 ]
 
 [[package]]
-name = "unicode-width"
-version = "0.1.9"
+name = "unarray"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
 
 [[package]]
-name = "unicode-xid"
-version = "0.2.2"
+name = "unicode-width"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
 [[package]]
 name = "uuid"
@@ -929,11 +1049,21 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "uuid"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
+dependencies = [
+ "getrandom",
+ "serde",
+]
+
 [[package]]
 name = "version_check"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wait-timeout"
@@ -946,26 +1076,25 @@ dependencies = [
 
 [[package]]
 name = "walkdir"
-version = "2.3.2"
+version = "2.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
 dependencies = [
  "same-file",
- "winapi",
  "winapi-util",
 ]
 
 [[package]]
 name = "wasi"
-version = "0.10.2+wasi-snapshot-preview1"
+version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.78"
+version = "0.2.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
+checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -973,24 +1102,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.78"
+version = "0.2.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
+checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
 dependencies = [
  "bumpalo",
- "lazy_static",
  "log",
+ "once_cell",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.16",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.78"
+version = "0.2.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
+checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -998,28 +1127,28 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.78"
+version = "0.2.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
+checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.16",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.78"
+version = "0.2.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
+checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
 
 [[package]]
 name = "web-sys"
-version = "0.3.55"
+version = "0.3.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
+checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -1055,3 +1184,153 @@ name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 270d2fb7..eb9a2a0a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -53,7 +53,7 @@ time-0_3 = []
 name = "bson"
 
 [dependencies]
-ahash = "0.7.2"
+ahash = "0.8.0"
 chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
 rand = "0.8"
 serde = { version = "1.0", features = ["derive"] }

From 54eb63500afd10b3379e8bf8a73dbb48245027ee Mon Sep 17 00:00:00 2001
From: Tom Selander <105729911+tom-selander@users.noreply.github.com>
Date: Wed, 24 May 2023 10:34:48 -0400
Subject: [PATCH 032/156] Remove Kaitlin and Patrick from auto-assignment

---
 .github/workflows/issue_assignment.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/issue_assignment.yml b/.github/workflows/issue_assignment.yml
index fa185422..ea7060cf 100644
--- a/.github/workflows/issue_assignment.yml
+++ b/.github/workflows/issue_assignment.yml
@@ -11,7 +11,7 @@ jobs:
             - name: 'Auto-assign issue'
               uses: pozil/auto-assign-issue@v1.1.0
               with:
-                  assignees: patrickfreed,abr-egn,isabelatkinson,kmahar
+                  assignees: abr-egn,isabelatkinson
                   numOfAssignee: 1
     add-labels:
         runs-on: ubuntu-latest

From b637094a4aed130a1ebf554ea17170c3ca2fa5e2 Mon Sep 17 00:00:00 2001
From: Yiyu Lin <linyiyu1992@gmail.com>
Date: Thu, 8 Jun 2023 22:27:19 +0800
Subject: [PATCH 033/156] move `lazy_static` to `once_cell` (#416)

---
 Cargo.toml       |  2 +-
 src/oid.rs       | 12 ++++--------
 src/tests/mod.rs |  6 ++----
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index eb9a2a0a..fdf9b155 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -61,7 +61,7 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
 indexmap = "1.6.2"
 hex = "0.4.2"
 base64 = "0.13.0"
-lazy_static = "1.4.0"
+once_cell = "1.5.1"
 uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true }
 uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
diff --git a/src/oid.rs b/src/oid.rs
index 263fc805..1e5f7ad5 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -13,10 +13,9 @@ use std::{
 use std::{convert::TryInto, time::SystemTime};
 
 use hex::{self, FromHexError};
+use once_cell::sync::Lazy;
 use rand::{thread_rng, Rng};
 
-use lazy_static::lazy_static;
-
 const TIMESTAMP_SIZE: usize = 4;
 const PROCESS_ID_SIZE: usize = 5;
 const COUNTER_SIZE: usize = 3;
@@ -27,9 +26,8 @@ const COUNTER_OFFSET: usize = PROCESS_ID_OFFSET + PROCESS_ID_SIZE;
 
 const MAX_U24: usize = 0xFF_FFFF;
 
-lazy_static! {
-    static ref OID_COUNTER: AtomicUsize = AtomicUsize::new(thread_rng().gen_range(0..=MAX_U24));
-}
+static OID_COUNTER: Lazy<AtomicUsize> =
+    Lazy::new(|| AtomicUsize::new(thread_rng().gen_range(0..=MAX_U24)));
 
 /// Errors that can occur during [`ObjectId`] construction and generation.
 #[derive(Clone, Debug)]
@@ -255,9 +253,7 @@ impl ObjectId {
 
     /// Generate a random 5-byte array.
     fn gen_process_id() -> [u8; 5] {
-        lazy_static! {
-            static ref BUF: [u8; 5] = thread_rng().gen();
-        }
+        static BUF: Lazy<[u8; 5]> = Lazy::new(|| thread_rng().gen());
 
         *BUF
     }
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
index eccc25d9..23deeea5 100644
--- a/src/tests/mod.rs
+++ b/src/tests/mod.rs
@@ -4,9 +4,7 @@ mod modules;
 mod serde;
 mod spec;
 
-use lazy_static::lazy_static;
 use modules::TestLock;
+use once_cell::sync::Lazy;
 
-lazy_static! {
-    pub(crate) static ref LOCK: TestLock = TestLock::new();
-}
+pub(crate) static LOCK: Lazy<TestLock> = Lazy::new(TestLock::new);

From b243db19b74745fcf52eacd9e4d34077186186d5 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Fri, 9 Jun 2023 14:51:18 -0600
Subject: [PATCH 034/156] RUST-1677 Add duration_since methods to `DateTime`
 (#417)

---
 src/datetime.rs       | 16 ++++++++++++++++
 src/tests/datetime.rs | 21 +++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/src/datetime.rs b/src/datetime.rs
index 80bbb786..a8ce59bb 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -389,6 +389,22 @@ impl crate::DateTime {
         })?;
         Ok(Self::from_time_0_3(odt))
     }
+
+    /// Returns the time elapsed since `earlier`, or `None` if the given `DateTime` is later than
+    /// this one.
+    pub fn checked_duration_since(self, earlier: Self) -> Option<Duration> {
+        if earlier.0 > self.0 {
+            return None;
+        }
+        Some(Duration::from_millis((self.0 - earlier.0) as u64))
+    }
+
+    /// Returns the time elapsed since `earlier`, or a [`Duration`] of zero if the given `DateTime`
+    /// is later than this one.
+    pub fn saturating_duration_since(self, earlier: Self) -> Duration {
+        self.checked_duration_since(earlier)
+            .unwrap_or(Duration::ZERO)
+    }
 }
 
 impl fmt::Debug for crate::DateTime {
diff --git a/src/tests/datetime.rs b/src/tests/datetime.rs
index 8f4719c3..56bba311 100644
--- a/src/tests/datetime.rs
+++ b/src/tests/datetime.rs
@@ -1,3 +1,5 @@
+use std::time::Duration;
+
 use crate::tests::LOCK;
 
 #[test]
@@ -38,3 +40,22 @@ fn datetime_to_rfc3339() {
 fn invalid_datetime_to_rfc3339() {
     assert!(crate::DateTime::MAX.try_to_rfc3339_string().is_err());
 }
+
+#[test]
+fn duration_since() {
+    let _guard = LOCK.run_concurrently();
+
+    let date1 = crate::DateTime::from_millis(100);
+    let date2 = crate::DateTime::from_millis(1000);
+
+    assert_eq!(
+        date2.checked_duration_since(date1),
+        Some(Duration::from_millis(900))
+    );
+    assert_eq!(
+        date2.saturating_duration_since(date1),
+        Duration::from_millis(900)
+    );
+    assert!(date1.checked_duration_since(date2).is_none());
+    assert_eq!(date1.saturating_duration_since(date2), Duration::ZERO);
+}

From 09a8cbb30fc6ffb406f975511a46fb496835858b Mon Sep 17 00:00:00 2001
From: Drshika A <67125579+drshika@users.noreply.github.com>
Date: Thu, 27 Jul 2023 12:47:41 -0400
Subject: [PATCH 035/156] RUST-1699: Add serde_with 3.x integration (#422)

* RUST-1699: Add serde_with 3.x integration
Co-authored-by: Abraham Egnor <abraham.egnor@mongodb.com>
Co-authored-by: Isabel Atkinson <isabel.atkinson@mongodb.com>
---
 .evergreen/Cargo.lock.msrv | 92 +++++++++++++++++++++++++++++++++-----
 .evergreen/config.yml      |  4 +-
 Cargo.toml                 |  4 +-
 README.md                  |  4 +-
 src/datetime.rs            | 71 ++++++++++++++++++++++++++---
 src/lib.rs                 |  4 +-
 src/uuid/mod.rs            | 36 ++++++++++++---
 7 files changed, 184 insertions(+), 31 deletions(-)

diff --git a/.evergreen/Cargo.lock.msrv b/.evergreen/Cargo.lock.msrv
index 90d589d7..d7c8b742 100644
--- a/.evergreen/Cargo.lock.msrv
+++ b/.evergreen/Cargo.lock.msrv
@@ -61,6 +61,12 @@ version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
+[[package]]
+name = "base64"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+
 [[package]]
 name = "bit-set"
 version = "0.5.3"
@@ -100,21 +106,22 @@ version = "2.6.0"
 dependencies = [
  "ahash",
  "assert_matches",
- "base64",
+ "base64 0.13.1",
  "bitvec",
  "chrono",
  "criterion",
  "hex",
  "indexmap",
  "js-sys",
- "lazy_static",
+ "once_cell",
  "pretty_assertions",
  "proptest",
  "rand",
  "serde",
  "serde_bytes",
  "serde_json",
- "serde_with",
+ "serde_with 1.14.0",
+ "serde_with 3.1.0",
  "time",
  "uuid 0.8.2",
  "uuid 1.1.2",
@@ -296,8 +303,18 @@ version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
 dependencies = [
- "darling_core",
- "darling_macro",
+ "darling_core 0.13.4",
+ "darling_macro 0.13.4",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+dependencies = [
+ "darling_core 0.20.3",
+ "darling_macro 0.20.3",
 ]
 
 [[package]]
@@ -314,17 +331,42 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "darling_core"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.16",
+]
+
 [[package]]
 name = "darling_macro"
 version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
 dependencies = [
- "darling_core",
+ "darling_core 0.13.4",
  "quote",
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "darling_macro"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+dependencies = [
+ "darling_core 0.20.3",
+ "quote",
+ "syn 2.0.16",
+]
+
 [[package]]
 name = "difference"
 version = "2.0.0"
@@ -469,6 +511,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
  "hashbrown",
+ "serde",
 ]
 
 [[package]]
@@ -922,7 +965,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
 dependencies = [
  "serde",
- "serde_with_macros",
+ "serde_with_macros 1.5.2",
+]
+
+[[package]]
+name = "serde_with"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3"
+dependencies = [
+ "base64 0.21.2",
+ "chrono",
+ "hex",
+ "indexmap",
+ "serde",
+ "serde_json",
+ "serde_with_macros 3.1.0",
+ "time",
 ]
 
 [[package]]
@@ -931,12 +990,24 @@ version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
 dependencies = [
- "darling",
+ "darling 0.13.4",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "serde_with_macros"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65"
+dependencies = [
+ "darling 0.20.3",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.16",
+]
+
 [[package]]
 name = "strsim"
 version = "0.10.0"
@@ -995,13 +1066,14 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
+checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
 dependencies = [
  "itoa",
  "libc",
  "num_threads",
+ "serde",
  "time-macros",
 ]
 
diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 7c9ba3af..ffb6f432 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -195,9 +195,9 @@ axes:
   - id: "extra-rust-versions"
     values:
       - id: "min"
-        display_name: "1.56 (minimum supported version)"
+        display_name: "1.60 (minimum supported version)"
         variables:
-          RUST_VERSION: "1.56.0"
+          RUST_VERSION: "1.60.0"
           MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
diff --git a/Cargo.toml b/Cargo.toml
index fdf9b155..36a1167d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,13 +65,13 @@ once_cell = "1.5.1"
 uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true }
 uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
-serde_with = { version = "1", optional = true }
+serde_with = { version = "1.3.1", optional = true }
+serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
 
 [target.'cfg(target_arch = "wasm32")'.dependencies]
 js-sys = "0.3"
-
 [dev-dependencies]
 assert_matches = "1.2"
 criterion = "0.3.0"
diff --git a/README.md b/README.md
index 6fa99643..caa5eae3 100644
--- a/README.md
+++ b/README.md
@@ -50,8 +50,8 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
 | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
 | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
-| `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/latest) integrations for `bson::DateTime` and `bson::Uuid` | serde_with         | no      |
-
+| `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
+| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.  Requires Rust 1.61. | serde_with         | no      |
 ## Overview of the BSON Format
 
 BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents.
diff --git a/src/datetime.rs b/src/datetime.rs
index a8ce59bb..1b315bad 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -145,20 +145,20 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// }
 /// # }
 /// ```
-/// ### The `serde_with` feature flag
+/// ### The `serde_with-3` feature flag
 ///
-/// The `serde_with` feature can be enabled to support more ergonomic serde attributes for
+/// The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for
 /// (de)serializing [`chrono::DateTime`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
-/// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with` can
-/// handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only works on
-/// fields that are exactly [`chrono::DateTime`].
+/// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3`
+/// can handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only
+/// works on fields that are exactly [`chrono::DateTime`].
 /// ```
-/// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with"))]
+/// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
 /// # {
 /// use serde::{Deserialize, Serialize};
 /// use bson::doc;
 ///
-/// #[serde_with::serde_as]
+/// #[serde_with_3::serde_as]
 /// #[derive(Deserialize, Serialize, PartialEq, Debug)]
 /// struct Foo {
 ///   /// Serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization
@@ -482,6 +482,36 @@ impl SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
     }
 }
 
+#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
+#[cfg_attr(
+    docsrs,
+    doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3")))
+)]
+impl<'de> serde_with_3::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateTime {
+    fn deserialize_as<D>(deserializer: D) -> std::result::Result<chrono::DateTime<Utc>, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let dt = DateTime::deserialize(deserializer)?;
+        Ok(dt.to_chrono())
+    }
+}
+
+#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))]
+impl serde_with_3::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
+    fn serialize_as<S>(
+        source: &chrono::DateTime<Utc>,
+        serializer: S,
+    ) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        let dt = DateTime::from_chrono(*source);
+        dt.serialize(serializer)
+    }
+}
+
 #[cfg(feature = "time-0_3")]
 #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
 impl From<crate::DateTime> for time::OffsetDateTime {
@@ -525,6 +555,33 @@ impl SerializeAs<time::OffsetDateTime> for crate::DateTime {
     }
 }
 
+#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with-3"))))]
+impl<'de> serde_with_3::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime {
+    fn deserialize_as<D>(deserializer: D) -> std::result::Result<time::OffsetDateTime, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let dt = DateTime::deserialize(deserializer)?;
+        Ok(dt.to_time_0_3())
+    }
+}
+
+#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))]
+impl serde_with_3::SerializeAs<time::OffsetDateTime> for crate::DateTime {
+    fn serialize_as<S>(
+        source: &time::OffsetDateTime,
+        serializer: S,
+    ) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        let dt = DateTime::from_time_0_3(*source);
+        dt.serialize(serializer)
+    }
+}
+
 /// Errors that can occur during [`DateTime`] construction and generation.
 #[derive(Clone, Debug)]
 #[non_exhaustive]
diff --git a/src/lib.rs b/src/lib.rs
index 130f7028..0ce92351 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,7 +43,7 @@
 //!
 //! ## Installation
 //! ### Requirements
-//! - Rust 1.56+
+//! - Rust 1.60+
 //!
 //! ### Importing
 //! This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application,
@@ -267,7 +267,7 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.56.0. This will be rarely be increased, and if it ever is,
+//! The MSRV for this crate is currently 1.60.0. This will be rarely be increased, and if it ever is,
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs
index 446e57f0..7e5fc44f 100644
--- a/src/uuid/mod.rs
+++ b/src/uuid/mod.rs
@@ -74,21 +74,21 @@
 //! For backwards compatibility, a `uuid-0_8` feature flag can be enabled, which provides the same
 //! API for interoperation with version 0.8 of the `uuid` crate.
 //!
-//! ## The `serde_with` feature flag
+//! ## The `serde_with-3` feature flag
 //!
-//! The `serde_with` feature can be enabled to support more ergonomic serde attributes for
+//! The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for
 //! (de)serializing [`uuid::Uuid`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
-//! crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with` can
-//! handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former only works on
+//! crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3`
+//! can handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former only works on
 //! fields that are exactly [`uuid::Uuid`].
 //! ```
-//! # #[cfg(all(feature = "uuid-1", feature = "serde_with"))]
+//! # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
 //! # {
 //! # use uuid as uuid;
 //! use serde::{Deserialize, Serialize};
 //! use bson::doc;
 //!
-//! #[serde_with::serde_as]
+//! #[serde_with_3::serde_as]
 //! #[derive(Deserialize, Serialize, PartialEq, Debug)]
 //! struct Foo {
 //!   /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization
@@ -509,6 +509,30 @@ macro_rules! trait_impls {
                 uuid.serialize(serializer)
             }
         }
+
+        #[cfg(all($feat, feature = "serde_with-3"))]
+        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))]
+        impl<'de> serde_with_3::DeserializeAs<'de, $u> for crate::Uuid {
+            fn deserialize_as<D>(deserializer: D) -> std::result::Result<$u, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                let uuid = Uuid::deserialize(deserializer)?;
+                Ok(uuid.into())
+            }
+        }
+
+        #[cfg(all($feat, feature = "serde_with_3"))]
+        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with_3"))))]
+        impl serde_with_3::SerializeAs<$u> for crate::Uuid {
+            fn serialize_as<S>(source: &$u, serializer: S) -> std::result::Result<S::Ok, S::Error>
+            where
+                S: serde::Serializer,
+            {
+                let uuid = Uuid::from(*source);
+                uuid.serialize(serializer)
+            }
+        }
     };
 }
 trait_impls!(feature = "uuid-0_8", uuid_0_8::Uuid);

From c278f6cacd6f3d53befa957019a1d606e62ad620 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 3 Aug 2023 15:57:03 -0600
Subject: [PATCH 036/156] minor: bump clippy to `1.71` (#424)

---
 .evergreen/check-clippy.sh  |  2 +-
 clippy.toml                 |  1 +
 src/de/raw.rs               | 10 +++++-----
 src/document.rs             | 10 +++++-----
 src/ser/raw/mod.rs          |  6 +-----
 src/tests/modules/macros.rs | 20 ++++++++++----------
 6 files changed, 23 insertions(+), 26 deletions(-)
 create mode 100644 clippy.toml

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index fac04d3e..99b02c10 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.65.0
+CLIPPY_VERSION=1.71.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/clippy.toml b/clippy.toml
new file mode 100644
index 00000000..59d02545
--- /dev/null
+++ b/clippy.toml
@@ -0,0 +1 @@
+msrv = "1.60.0"
\ No newline at end of file
diff --git a/src/de/raw.rs b/src/de/raw.rs
index f8798745..874d025e 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -995,7 +995,7 @@ impl TimestampDeserializer {
 impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut TimestampDeserializer {
     type Error = Error;
 
-    fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
@@ -1095,7 +1095,7 @@ impl DateTimeDeserializer {
 impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut DateTimeDeserializer {
     type Error = Error;
 
-    fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
@@ -1196,7 +1196,7 @@ impl<'a> BinaryDeserializer<'a> {
 impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut BinaryDeserializer<'de> {
     type Error = Error;
 
-    fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
@@ -1330,7 +1330,7 @@ impl<'de, 'a> CodeWithScopeDeserializer<'de, 'a> {
 impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserializer<'de, 'a> {
     type Error = Error;
 
-    fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
@@ -1447,7 +1447,7 @@ impl<'de, 'a> DbPointerDeserializer<'de, 'a> {
 impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut DbPointerDeserializer<'de, 'a> {
     type Error = Error;
 
-    fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
diff --git a/src/document.rs b/src/document.rs
index f27e923d..9b0e982b 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -253,7 +253,7 @@ impl Document {
     /// Get a reference to a Decimal128 value for key, if it exists.
     pub fn get_decimal128(&self, key: impl AsRef<str>) -> ValueAccessResult<&Decimal128> {
         match self.get(key) {
-            Some(&Bson::Decimal128(ref v)) => Ok(v),
+            Some(Bson::Decimal128(v)) => Ok(v),
             Some(_) => Err(ValueAccessError::UnexpectedType),
             None => Err(ValueAccessError::NotPresent),
         }
@@ -274,7 +274,7 @@ impl Document {
     /// Get a string slice this key if it exists and has the correct type.
     pub fn get_str(&self, key: impl AsRef<str>) -> ValueAccessResult<&str> {
         match self.get(key) {
-            Some(&Bson::String(ref v)) => Ok(v),
+            Some(Bson::String(v)) => Ok(v),
             Some(_) => Err(ValueAccessError::UnexpectedType),
             None => Err(ValueAccessError::NotPresent),
         }
@@ -293,7 +293,7 @@ impl Document {
     /// the correct type.
     pub fn get_array(&self, key: impl AsRef<str>) -> ValueAccessResult<&Array> {
         match self.get(key) {
-            Some(&Bson::Array(ref v)) => Ok(v),
+            Some(Bson::Array(v)) => Ok(v),
             Some(_) => Err(ValueAccessError::UnexpectedType),
             None => Err(ValueAccessError::NotPresent),
         }
@@ -313,7 +313,7 @@ impl Document {
     /// the correct type.
     pub fn get_document(&self, key: impl AsRef<str>) -> ValueAccessResult<&Document> {
         match self.get(key) {
-            Some(&Bson::Document(ref v)) => Ok(v),
+            Some(Bson::Document(v)) => Ok(v),
             Some(_) => Err(ValueAccessError::UnexpectedType),
             None => Err(ValueAccessError::NotPresent),
         }
@@ -458,7 +458,7 @@ impl Document {
     /// Get a reference to a UTC datetime value for this key if it exists and has the correct type.
     pub fn get_datetime(&self, key: impl AsRef<str>) -> ValueAccessResult<&crate::DateTime> {
         match self.get(key) {
-            Some(&Bson::DateTime(ref v)) => Ok(v),
+            Some(Bson::DateTime(v)) => Ok(v),
             Some(_) => Err(ValueAccessError::UnexpectedType),
             None => Err(ValueAccessError::NotPresent),
         }
diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs
index af82c06a..960c5a46 100644
--- a/src/ser/raw/mod.rs
+++ b/src/ser/raw/mod.rs
@@ -259,11 +259,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     }
 
     #[inline]
-    fn serialize_newtype_struct<T: ?Sized>(
-        mut self,
-        name: &'static str,
-        value: &T,
-    ) -> Result<Self::Ok>
+    fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<Self::Ok>
     where
         T: serde::Serialize,
     {
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
index ada1ccc5..689c8a1a 100644
--- a/src/tests/modules/macros.rs
+++ b/src/tests/modules/macros.rs
@@ -143,19 +143,19 @@ fn recursive_macro() {
     };
 
     match doc.get("a") {
-        Some(&Bson::String(ref s)) => assert_eq!("foo", s),
+        Some(Bson::String(s)) => assert_eq!("foo", s),
         _ => panic!("String 'foo' was not inserted correctly."),
     }
 
     // Inner Doc 1
     match doc.get("b") {
-        Some(&Bson::Document(ref doc)) => {
+        Some(Bson::Document(doc)) => {
             // Inner doc 2
             match doc.get("bar") {
-                Some(&Bson::Document(ref inner_doc)) => {
+                Some(Bson::Document(inner_doc)) => {
                     // Inner array
                     match inner_doc.get("harbor") {
-                        Some(&Bson::Array(ref arr)) => {
+                        Some(Bson::Array(arr)) => {
                             assert_eq!(2, arr.len());
 
                             // Match array items
@@ -177,7 +177,7 @@ fn recursive_macro() {
 
                     // Inner floating point
                     match inner_doc.get("jelly") {
-                        Some(&Bson::Double(ref fp)) => assert_eq!(42.0, *fp),
+                        Some(Bson::Double(fp)) => assert_eq!(42.0, *fp),
                         _ => panic!("Floating point 42.0 was not inserted correctly."),
                     }
                 }
@@ -189,7 +189,7 @@ fn recursive_macro() {
 
     // Single-item array
     match doc.get("c") {
-        Some(&Bson::Array(ref arr)) => {
+        Some(Bson::Array(arr)) => {
             assert_eq!(1, arr.len());
 
             // Integer type
@@ -203,7 +203,7 @@ fn recursive_macro() {
 
     // Document nested in array
     match doc.get("d") {
-        Some(&Bson::Array(ref arr)) => {
+        Some(Bson::Array(arr)) => {
             assert_eq!(1, arr.len());
 
             // Nested document
@@ -211,7 +211,7 @@ fn recursive_macro() {
                 Some(Bson::Document(ref doc)) => {
                     // String
                     match doc.get("apple") {
-                        Some(&Bson::String(ref s)) => assert_eq!("ripe", s),
+                        Some(Bson::String(s)) => assert_eq!("ripe", s),
                         _ => panic!("String 'ripe' was not inserted correctly."),
                     }
                 }
@@ -223,10 +223,10 @@ fn recursive_macro() {
 
     // Single-item document
     match doc.get("e") {
-        Some(&Bson::Document(ref bdoc)) => {
+        Some(Bson::Document(bdoc)) => {
             // String
             match bdoc.get("single") {
-                Some(&Bson::String(ref s)) => assert_eq!("test", s),
+                Some(Bson::String(s)) => assert_eq!("test", s),
                 _ => panic!("String 'test' was not inserted correctly."),
             }
         }

From a87ed8f6afa8f04119561c6ccd0e50d97196ff53 Mon Sep 17 00:00:00 2001
From: Maxim De Clercq <maximdeclercq00@gmail.com>
Date: Fri, 4 Aug 2023 00:03:07 +0200
Subject: [PATCH 037/156] RUST-1714 Use serde traits when only `serde_with-3`
 is enabled (#423)

---
 src/datetime.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/datetime.rs b/src/datetime.rs
index 1b315bad..4c4469dc 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -16,7 +16,7 @@ use time::format_description::well_known::Rfc3339;
 #[cfg(feature = "chrono-0_4")]
 use chrono::{LocalResult, TimeZone, Utc};
 #[cfg(all(
-    feature = "serde_with",
+    any(feature = "serde_with", feature = "serde_with-3"),
     any(feature = "chrono-0_4", feature = "time-0_3")
 ))]
 use serde::{Deserialize, Deserializer, Serialize};

From 92e0dad93afc8aa8f8ec1e34dfa7fee14987ea2f Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 30 Aug 2023 15:07:24 -0400
Subject: [PATCH 038/156] minor: bump version from 2.7 release (#430)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 36a1167d..acdca236 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.6.0"
+version = "2.7.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index caa5eae3..f7bb0716 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.6.0"
+bson = "2.7.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 0ce92351..4321f858 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.6.0"
+//! bson = "2.7.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From 6b3ee6a45af4e1595801d453fb5fab955b573431 Mon Sep 17 00:00:00 2001
From: Valentin Kovalenko <valentin.male.kovalenko@gmail.com>
Date: Wed, 27 Sep 2023 14:22:17 -0600
Subject: [PATCH 039/156] RUST-1769 Fix check-rustdoc (#432)

---
 src/raw/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index ced3f1dd..29ddc6b0 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -82,7 +82,7 @@
 //!
 //! ### Iteration
 //!
-//! [`RawDocument`] implements [`IntoIterator`](std::iter::IntoIterator), which can also be
+//! [`RawDocument`] implements [`IntoIterator`], which can also be
 //! accessed via [`RawDocumentBuf::iter`].
 
 //! ```rust

From 283ecb3eb697ad03fe7ad603f1838a4fc3e5d7f3 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Wed, 18 Oct 2023 13:24:59 -0600
Subject: [PATCH 040/156] RUST-1132 Implement `DeserializeSeed` for owned and
 borrowed raw documents (#433)

---
 src/extjson/models.rs           |  31 +-
 src/raw/bson.rs                 |   2 +-
 src/raw/bson_ref.rs             |   2 +-
 src/raw/mod.rs                  |   2 +-
 src/raw/serde.rs                | 425 +++---------------------
 src/raw/serde/bson_visitor.rs   | 364 +++++++++++++++++++++
 src/raw/serde/seeded_visitor.rs | 564 ++++++++++++++++++++++++++++++++
 src/tests/spec/mod.rs           |  43 ++-
 8 files changed, 1033 insertions(+), 400 deletions(-)
 create mode 100644 src/raw/serde/bson_visitor.rs
 create mode 100644 src/raw/serde/seeded_visitor.rs

diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 48775113..efb57fff 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -5,8 +5,9 @@ use serde::{
     Deserialize,
     Serialize,
 };
+use std::borrow::Cow;
 
-use crate::{extjson, oid, spec::BinarySubtype, Bson};
+use crate::{extjson, oid, raw::serde::CowStr, spec::BinarySubtype, Bson};
 
 #[derive(Deserialize)]
 #[serde(deny_unknown_fields)]
@@ -370,3 +371,31 @@ impl Undefined {
         }
     }
 }
+
+#[derive(Debug, Deserialize)]
+pub(crate) struct BorrowedRegexBody<'a> {
+    #[serde(borrow)]
+    pub(crate) pattern: Cow<'a, str>,
+
+    #[serde(borrow)]
+    pub(crate) options: Cow<'a, str>,
+}
+
+#[derive(Debug, Deserialize)]
+pub(crate) struct BorrowedBinaryBody<'a> {
+    #[serde(borrow)]
+    pub(crate) bytes: Cow<'a, [u8]>,
+
+    #[serde(rename = "subType")]
+    pub(crate) subtype: u8,
+}
+
+#[derive(Deserialize)]
+pub(crate) struct BorrowedDbPointerBody<'a> {
+    #[serde(rename = "$ref")]
+    #[serde(borrow)]
+    pub(crate) ns: CowStr<'a>,
+
+    #[serde(rename = "$id")]
+    pub(crate) id: oid::ObjectId,
+}
diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index c216c8fd..7bb475a4 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -24,7 +24,7 @@ use crate::{
 };
 
 use super::{
-    serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor},
+    serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson},
     Error,
     Result,
 };
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index 4af7eb45..8241d879 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -5,7 +5,7 @@ use serde_bytes::Bytes;
 
 use super::{
     bson::RawBson,
-    serde::{OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor},
+    serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson},
     Error,
     RawArray,
     RawDocument,
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index 29ddc6b0..a96f6d13 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -120,7 +120,7 @@ mod document;
 mod document_buf;
 mod error;
 mod iter;
-mod serde;
+pub(crate) mod serde;
 #[cfg(test)]
 mod test;
 
diff --git a/src/raw/serde.rs b/src/raw/serde.rs
index ab99ef93..98341fbe 100644
--- a/src/raw/serde.rs
+++ b/src/raw/serde.rs
@@ -1,32 +1,28 @@
-use std::{borrow::Cow, fmt::Debug};
+pub(crate) mod bson_visitor;
+pub(crate) mod seeded_visitor;
 
-use serde::{de::Visitor, Deserialize};
-use serde_bytes::ByteBuf;
+use std::{borrow::Cow, convert::TryFrom, fmt::Debug};
+
+use serde::{de::Error as SerdeError, Deserialize};
 
 use crate::{
-    de::convert_unsigned_to_signed_raw,
-    extjson,
-    oid::ObjectId,
-    raw::{RawJavaScriptCodeWithScope, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     spec::BinarySubtype,
-    Binary,
-    DateTime,
-    DbPointer,
-    Decimal128,
     RawArray,
     RawArrayBuf,
-    RawBinaryRef,
     RawBsonRef,
-    RawDbPointerRef,
     RawDocument,
     RawDocumentBuf,
-    RawJavaScriptCodeWithScopeRef,
-    RawRegexRef,
-    Regex,
-    Timestamp,
 };
 
 use super::{bson::RawBson, RAW_BSON_NEWTYPE};
+use bson_visitor::*;
+use seeded_visitor::*;
+
+/// Wrapper around a `Cow<str>` to enable borrowed deserialization.
+/// The default [`Deserialize`] impl for [`Cow`] always uses the owned version.
+#[derive(Debug, Deserialize)]
+pub(crate) struct CowStr<'a>(#[serde(borrow)] Cow<'a, str>);
 
 /// A raw BSON value that may either be borrowed or owned.
 ///
@@ -67,11 +63,6 @@ impl<'a> From<RawBson> for OwnedOrBorrowedRawBson<'a> {
     }
 }
 
-/// Wrapper around a `Cow<str>` 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> {
@@ -88,6 +79,31 @@ impl<'a> OwnedOrBorrowedRawDocument<'a> {
     }
 }
 
+impl<'a> From<RawDocumentBuf> for OwnedOrBorrowedRawDocument<'a> {
+    fn from(doc: RawDocumentBuf) -> Self {
+        Self::Owned(doc)
+    }
+}
+
+impl<'a> From<&'a RawDocument> for OwnedOrBorrowedRawDocument<'a> {
+    fn from(doc: &'a RawDocument) -> Self {
+        Self::Borrowed(doc)
+    }
+}
+
+impl<'a, 'de: 'a> TryFrom<CowByteBuffer<'de>> for OwnedOrBorrowedRawDocument<'a> {
+    type Error = crate::raw::Error;
+
+    fn try_from(buffer: CowByteBuffer<'de>) -> Result<Self, Self::Error> {
+        let doc = match buffer.0 {
+            Some(Cow::Borrowed(borrowed)) => RawDocument::from_bytes(borrowed)?.into(),
+            Some(Cow::Owned(owned)) => RawDocumentBuf::from_bytes(owned)?.into(),
+            None => RawDocumentBuf::new().into(),
+        };
+        Ok(doc)
+    }
+}
+
 impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
@@ -100,24 +116,24 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> {
             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
+            // from them here too. For BSON, the deserializer will return an error if it
             // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document.
             OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
                 Ok(Self::Borrowed(
-                    RawDocument::from_bytes(b.bytes).map_err(serde::de::Error::custom)?,
+                    RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?,
                 ))
             }
             OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
                 Ok(Self::Owned(
-                    RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?,
+                    RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?,
                 ))
             }
 
-            o => Err(serde::de::Error::custom(format!(
+            o => Err(SerdeError::custom(format!(
                 "expected raw document, instead got {:?}",
                 o
             ))),
@@ -153,374 +169,25 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> {
             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
+            // from them here too. For BSON, the deserializer will return an error if it
             // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document.
             OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
-                let doc = RawDocument::from_bytes(b.bytes).map_err(serde::de::Error::custom)?;
+                let doc = RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?;
                 Ok(Self::Borrowed(RawArray::from_doc(doc)))
             }
             OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
-                let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(serde::de::Error::custom)?;
+                let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?;
                 Ok(Self::Owned(RawArrayBuf::from_raw_document_buf(doc)))
             }
 
-            o => Err(serde::de::Error::custom(format!(
+            o => Err(SerdeError::custom(format!(
                 "expected raw array, instead got {:?}",
                 o
             ))),
         }
     }
 }
-
-/// 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<E>(self, v: &'de str) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::String(v).into())
-    }
-
-    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBson::String(v.to_string()).into())
-    }
-
-    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBson::String(v).into())
-    }
-
-    fn visit_borrowed_bytes<E>(self, bytes: &'de [u8]) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Binary(RawBinaryRef {
-            bytes,
-            subtype: BinarySubtype::Generic,
-        })
-        .into())
-    }
-
-    fn visit_i8<E>(self, v: i8) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Int32(v.into()).into())
-    }
-
-    fn visit_i16<E>(self, v: i16) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Int32(v.into()).into())
-    }
-
-    fn visit_i32<E>(self, v: i32) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Int32(v).into())
-    }
-
-    fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Int64(v).into())
-    }
-
-    fn visit_u8<E>(self, value: u8) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(convert_unsigned_to_signed_raw(value.into())?.into())
-    }
-
-    fn visit_u16<E>(self, value: u16) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(convert_unsigned_to_signed_raw(value.into())?.into())
-    }
-
-    fn visit_u32<E>(self, value: u32) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(convert_unsigned_to_signed_raw(value.into())?.into())
-    }
-
-    fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(convert_unsigned_to_signed_raw(value)?.into())
-    }
-
-    fn visit_bool<E>(self, v: bool) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Boolean(v).into())
-    }
-
-    fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Double(v).into())
-    }
-
-    fn visit_none<E>(self) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Null.into())
-    }
-
-    fn visit_unit<E>(self) -> std::result::Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBsonRef::Null.into())
-    }
-
-    fn visit_newtype_struct<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        deserializer.deserialize_any(self)
-    }
-
-    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RawBson::Binary(Binary {
-            bytes: v,
-            subtype: BinarySubtype::Generic,
-        })
-        .into())
-    }
-
-    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
-    where
-        A: serde::de::SeqAccess<'de>,
-    {
-        let mut array = RawArrayBuf::new();
-        while let Some(v) = seq.next_element::<RawBson>()? {
-            array.push(v);
-        }
-        Ok(RawBson::Array(array).into())
-    }
-
-    fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
-    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,
-        ) -> std::result::Result<OwnedOrBorrowedRawBson<'de>, A::Error>
-        where
-            A: serde::de::MapAccess<'de>,
-        {
-            let mut doc = RawDocumentBuf::new();
-            let v: RawBson = map.next_value()?;
-            doc.append(first_key, v);
-
-            while let Some((k, v)) = map.next_entry::<CowStr, RawBson>()? {
-                doc.append(k.0, v);
-            }
-
-            Ok(RawBson::Document(doc).into())
-        }
-
-        let k = match map.next_key::<CowStr>()? {
-            Some(k) => k,
-            None => return Ok(RawBson::Document(RawDocumentBuf::new()).into()),
-        };
-
-        match k.0.as_ref() {
-            "$oid" => {
-                let oid: ObjectId = map.next_value()?;
-                Ok(RawBsonRef::ObjectId(oid).into())
-            }
-            "$symbol" => {
-                let s: CowStr = map.next_value()?;
-                match s.0 {
-                    Cow::Borrowed(s) => Ok(RawBsonRef::Symbol(s).into()),
-                    Cow::Owned(s) => Ok(RawBson::Symbol(s).into()),
-                }
-            }
-            "$numberDecimalBytes" => {
-                let bytes = map.next_value::<ByteBuf>()?;
-                return Ok(
-                    RawBsonRef::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(RawBsonRef::RegularExpression(RawRegexRef {
-                            pattern: p,
-                            options: o,
-                        })
-                        .into())
-                    }
-                    (p, o) => Ok(RawBson::RegularExpression(Regex {
-                        pattern: p.into_owned(),
-                        options: o.into_owned(),
-                    })
-                    .into()),
-                }
-            }
-            "$undefined" => {
-                let _: bool = map.next_value()?;
-                Ok(RawBsonRef::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::<BorrowedBinaryBody>()?;
-
-                if let Cow::Borrowed(bytes) = v.bytes {
-                    Ok(RawBsonRef::Binary(RawBinaryRef {
-                        bytes,
-                        subtype: v.subtype.into(),
-                    })
-                    .into())
-                } else {
-                    Ok(RawBson::Binary(Binary {
-                        bytes: v.bytes.into_owned(),
-                        subtype: v.subtype.into(),
-                    })
-                    .into())
-                }
-            }
-            "$date" => {
-                let v = map.next_value::<i64>()?;
-                Ok(RawBsonRef::DateTime(DateTime::from_millis(v)).into())
-            }
-            "$timestamp" => {
-                let v = map.next_value::<extjson::models::TimestampBody>()?;
-                Ok(RawBsonRef::Timestamp(Timestamp {
-                    time: v.t,
-                    increment: v.i,
-                })
-                .into())
-            }
-            "$minKey" => {
-                let _ = map.next_value::<i32>()?;
-                Ok(RawBsonRef::MinKey.into())
-            }
-            "$maxKey" => {
-                let _ = map.next_value::<i32>()?;
-                Ok(RawBsonRef::MaxKey.into())
-            }
-            "$code" => {
-                let code = map.next_value::<CowStr>()?;
-                if let Some(key) = map.next_key::<CowStr>()? {
-                    if key.0.as_ref() == "$scope" {
-                        let scope = map.next_value::<OwnedOrBorrowedRawDocument>()?;
-                        match (code.0, scope) {
-                            (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => {
-                                Ok(RawBsonRef::JavaScriptCodeWithScope(
-                                    RawJavaScriptCodeWithScopeRef { code, scope },
-                                )
-                                .into())
-                            }
-                            (code, scope) => Ok(RawBson::JavaScriptCodeWithScope(
-                                RawJavaScriptCodeWithScope {
-                                    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(RawBsonRef::JavaScriptCode(code).into())
-                } else {
-                    Ok(RawBson::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(RawBsonRef::DbPointer(RawDbPointerRef {
-                        namespace: ns,
-                        id: body.id,
-                    })
-                    .into())
-                } else {
-                    Ok(RawBson::DbPointer(DbPointer {
-                        namespace: body.ns.0.into_owned(),
-                        id: body.id,
-                    })
-                    .into())
-                }
-            }
-            RAW_DOCUMENT_NEWTYPE => {
-                let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::from_bytes(bson).map_err(serde::de::Error::custom)?;
-                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(RawBsonRef::Array(RawArray::from_doc(doc)).into())
-            }
-            k => build_doc(k, map),
-        }
-    }
-}
diff --git a/src/raw/serde/bson_visitor.rs b/src/raw/serde/bson_visitor.rs
new file mode 100644
index 00000000..ac2eb043
--- /dev/null
+++ b/src/raw/serde/bson_visitor.rs
@@ -0,0 +1,364 @@
+use std::{borrow::Cow, convert::TryFrom};
+
+use serde::de::{Error as SerdeError, Visitor};
+use serde_bytes::ByteBuf;
+
+use crate::{
+    de::convert_unsigned_to_signed_raw,
+    extjson::models::{
+        BorrowedBinaryBody,
+        BorrowedDbPointerBody,
+        BorrowedRegexBody,
+        TimestampBody,
+    },
+    oid::ObjectId,
+    raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    spec::BinarySubtype,
+    Binary,
+    DateTime,
+    DbPointer,
+    Decimal128,
+    RawArray,
+    RawArrayBuf,
+    RawBinaryRef,
+    RawBson,
+    RawBsonRef,
+    RawDbPointerRef,
+    RawDocument,
+    RawDocumentBuf,
+    RawJavaScriptCodeWithScope,
+    RawJavaScriptCodeWithScopeRef,
+    RawRegexRef,
+    Regex,
+    Timestamp,
+};
+
+use super::{
+    CowByteBuffer,
+    CowStr,
+    OwnedOrBorrowedRawBson,
+    OwnedOrBorrowedRawDocument,
+    SeededVisitor,
+};
+
+/// 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<E>(self, v: &'de str) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::String(v).into())
+    }
+
+    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBson::String(v.to_string()).into())
+    }
+
+    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBson::String(v).into())
+    }
+
+    fn visit_borrowed_bytes<E>(self, bytes: &'de [u8]) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Binary(RawBinaryRef {
+            bytes,
+            subtype: BinarySubtype::Generic,
+        })
+        .into())
+    }
+
+    fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Int32(v.into()).into())
+    }
+
+    fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Int32(v.into()).into())
+    }
+
+    fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Int32(v).into())
+    }
+
+    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Int64(v).into())
+    }
+
+    fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(convert_unsigned_to_signed_raw(value.into())?.into())
+    }
+
+    fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(convert_unsigned_to_signed_raw(value.into())?.into())
+    }
+
+    fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(convert_unsigned_to_signed_raw(value.into())?.into())
+    }
+
+    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(convert_unsigned_to_signed_raw(value)?.into())
+    }
+
+    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Boolean(v).into())
+    }
+
+    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Double(v).into())
+    }
+
+    fn visit_none<E>(self) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Null.into())
+    }
+
+    fn visit_unit<E>(self) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBsonRef::Null.into())
+    }
+
+    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        deserializer.deserialize_any(self)
+    }
+
+    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(RawBson::Binary(Binary {
+            bytes: v,
+            subtype: BinarySubtype::Generic,
+        })
+        .into())
+    }
+
+    fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+    where
+        A: serde::de::SeqAccess<'de>,
+    {
+        let mut buffer = CowByteBuffer::new();
+        let seeded_visitor = SeededVisitor::new(&mut buffer);
+        seeded_visitor.visit_seq(seq)?;
+
+        match OwnedOrBorrowedRawDocument::try_from(buffer).map_err(SerdeError::custom)? {
+            OwnedOrBorrowedRawDocument::Borrowed(borrowed) => {
+                let raw_array = RawArray::from_doc(borrowed);
+                Ok(RawBsonRef::Array(raw_array).into())
+            }
+            OwnedOrBorrowedRawDocument::Owned(owned) => {
+                let raw_array = RawArrayBuf::from_raw_document_buf(owned);
+                Ok(RawBson::Array(raw_array).into())
+            }
+        }
+    }
+
+    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+    where
+        A: serde::de::MapAccess<'de>,
+    {
+        let first_key = match map.next_key::<CowStr>()? {
+            Some(k) => k,
+            None => return Ok(RawBson::Document(RawDocumentBuf::new()).into()),
+        };
+
+        match first_key.0.as_ref() {
+            "$oid" => {
+                let oid: ObjectId = map.next_value()?;
+                Ok(RawBsonRef::ObjectId(oid).into())
+            }
+            "$symbol" => {
+                let s: CowStr = map.next_value()?;
+                match s.0 {
+                    Cow::Borrowed(s) => Ok(RawBsonRef::Symbol(s).into()),
+                    Cow::Owned(s) => Ok(RawBson::Symbol(s).into()),
+                }
+            }
+            "$numberDecimalBytes" => {
+                let bytes: ByteBuf = map.next_value()?;
+                return Ok(RawBsonRef::Decimal128(Decimal128::deserialize_from_slice(
+                    bytes.as_ref(),
+                )?)
+                .into());
+            }
+            "$regularExpression" => {
+                let body: BorrowedRegexBody = map.next_value()?;
+
+                match (body.pattern, body.options) {
+                    (Cow::Borrowed(p), Cow::Borrowed(o)) => {
+                        Ok(RawBsonRef::RegularExpression(RawRegexRef {
+                            pattern: p,
+                            options: o,
+                        })
+                        .into())
+                    }
+                    (p, o) => Ok(RawBson::RegularExpression(Regex {
+                        pattern: p.into_owned(),
+                        options: o.into_owned(),
+                    })
+                    .into()),
+                }
+            }
+            "$undefined" => {
+                let _: bool = map.next_value()?;
+                Ok(RawBsonRef::Undefined.into())
+            }
+            "$binary" => {
+                let v: BorrowedBinaryBody = map.next_value()?;
+
+                if let Cow::Borrowed(bytes) = v.bytes {
+                    Ok(RawBsonRef::Binary(RawBinaryRef {
+                        bytes,
+                        subtype: v.subtype.into(),
+                    })
+                    .into())
+                } else {
+                    Ok(RawBson::Binary(Binary {
+                        bytes: v.bytes.into_owned(),
+                        subtype: v.subtype.into(),
+                    })
+                    .into())
+                }
+            }
+            "$date" => {
+                let date: i64 = map.next_value()?;
+                Ok(RawBsonRef::DateTime(DateTime::from_millis(date)).into())
+            }
+            "$timestamp" => {
+                let timestamp: TimestampBody = map.next_value()?;
+                Ok(RawBsonRef::Timestamp(Timestamp {
+                    time: timestamp.t,
+                    increment: timestamp.i,
+                })
+                .into())
+            }
+            "$minKey" => {
+                let _ = map.next_value::<i32>()?;
+                Ok(RawBsonRef::MinKey.into())
+            }
+            "$maxKey" => {
+                let _ = map.next_value::<i32>()?;
+                Ok(RawBsonRef::MaxKey.into())
+            }
+            "$code" => {
+                let code = map.next_value::<CowStr>()?;
+                if let Some(key) = map.next_key::<CowStr>()? {
+                    if key.0.as_ref() == "$scope" {
+                        let scope = map.next_value::<OwnedOrBorrowedRawDocument>()?;
+                        match (code.0, scope) {
+                            (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => {
+                                Ok(RawBsonRef::JavaScriptCodeWithScope(
+                                    RawJavaScriptCodeWithScopeRef { code, scope },
+                                )
+                                .into())
+                            }
+                            (code, scope) => Ok(RawBson::JavaScriptCodeWithScope(
+                                RawJavaScriptCodeWithScope {
+                                    code: code.into_owned(),
+                                    scope: scope.into_owned(),
+                                },
+                            )
+                            .into()),
+                        }
+                    } else {
+                        Err(SerdeError::unknown_field(&key.0, &["$scope"]))
+                    }
+                } else if let Cow::Borrowed(code) = code.0 {
+                    Ok(RawBsonRef::JavaScriptCode(code).into())
+                } else {
+                    Ok(RawBson::JavaScriptCode(code.0.into_owned()).into())
+                }
+            }
+            "$dbPointer" => {
+                let db_pointer: BorrowedDbPointerBody = map.next_value()?;
+                if let Cow::Borrowed(ns) = db_pointer.ns.0 {
+                    Ok(RawBsonRef::DbPointer(RawDbPointerRef {
+                        namespace: ns,
+                        id: db_pointer.id,
+                    })
+                    .into())
+                } else {
+                    Ok(RawBson::DbPointer(DbPointer {
+                        namespace: db_pointer.ns.0.into_owned(),
+                        id: db_pointer.id,
+                    })
+                    .into())
+                }
+            }
+            RAW_DOCUMENT_NEWTYPE => {
+                let bson = map.next_value::<&[u8]>()?;
+                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
+                Ok(RawBsonRef::Document(doc).into())
+            }
+            RAW_ARRAY_NEWTYPE => {
+                let bson = map.next_value::<&[u8]>()?;
+                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
+                Ok(RawBsonRef::Array(RawArray::from_doc(doc)).into())
+            }
+            _ => {
+                let mut buffer = CowByteBuffer::new();
+                let seeded_visitor = SeededVisitor::new(&mut buffer);
+                seeded_visitor.iterate_map(first_key, map)?;
+
+                match OwnedOrBorrowedRawDocument::try_from(buffer).map_err(SerdeError::custom)? {
+                    OwnedOrBorrowedRawDocument::Borrowed(borrowed) => {
+                        Ok(RawBsonRef::Document(borrowed).into())
+                    }
+                    OwnedOrBorrowedRawDocument::Owned(owned) => Ok(RawBson::Document(owned).into()),
+                }
+            }
+        }
+    }
+}
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
new file mode 100644
index 00000000..e03ef7a6
--- /dev/null
+++ b/src/raw/serde/seeded_visitor.rs
@@ -0,0 +1,564 @@
+use std::{borrow::Cow, convert::TryFrom, fmt::Formatter, ops::Range};
+
+use serde::{
+    de::{DeserializeSeed, Error as SerdeError, MapAccess, SeqAccess, Visitor},
+    Deserializer,
+};
+use serde_bytes::ByteBuf;
+
+use crate::{
+    de::MIN_BSON_DOCUMENT_SIZE,
+    extjson::models::{
+        BorrowedBinaryBody,
+        BorrowedDbPointerBody,
+        BorrowedRegexBody,
+        TimestampBody,
+    },
+    oid::ObjectId,
+    raw::{RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    spec::{BinarySubtype, ElementType},
+    RawDocumentBuf,
+};
+
+use super::CowStr;
+
+/// A copy-on-write byte buffer containing raw BSON bytes. The inner value starts as `None` and
+/// transitions to either `Cow::Borrowed` or `Cow::Owned` depending upon the data visited.
+pub(crate) struct CowByteBuffer<'de>(pub(crate) Option<Cow<'de, [u8]>>);
+
+impl<'de> CowByteBuffer<'de> {
+    /// Creates an new empty buffer.
+    pub(crate) fn new() -> Self {
+        Self(None)
+    }
+
+    /// The length of the buffer.
+    fn len(&self) -> usize {
+        match &self.0 {
+            Some(buffer) => buffer.len(),
+            None => 0,
+        }
+    }
+
+    /// Gets a mutable reference to the inner buffer, allocating a `Vec<u8>` and transitioning the
+    /// buffer's state as necessary.
+    fn get_owned_buffer(&mut self) -> &mut Vec<u8> {
+        self.0
+            .get_or_insert_with(|| Cow::Owned(Vec::new()))
+            .to_mut()
+    }
+
+    /// Appends a single byte to the buffer.
+    fn push_byte(&mut self, byte: u8) {
+        let buffer = self.get_owned_buffer();
+        buffer.push(byte);
+    }
+
+    /// Appends a slice of bytes to the buffer.
+    fn append_bytes(&mut self, bytes: &[u8]) {
+        let buffer = self.get_owned_buffer();
+        buffer.extend_from_slice(bytes);
+    }
+
+    /// Appends a slice of borrowed bytes to the buffer. If the buffer is currently `None`, it will
+    /// store a reference to the borrowed bytes; otherwise, it will copy the bytes to the
+    /// existing buffer.
+    fn append_borrowed_bytes(&mut self, bytes: &'de [u8]) {
+        match &mut self.0 {
+            Some(buffer) => buffer.to_mut().extend_from_slice(bytes),
+            None => self.0 = Some(Cow::Borrowed(bytes)),
+        }
+    }
+
+    /// Copies a slice of bytes into the given range. This method will panic if the range is out of
+    /// bounds.
+    fn copy_from_slice(&mut self, range: Range<usize>, slice: &[u8]) {
+        let buffer = self.get_owned_buffer();
+        buffer[range].copy_from_slice(slice);
+    }
+
+    /// Removes the bytes in the given range from the buffer. This method will panic if the range is
+    /// out of bounds.
+    fn drain(&mut self, range: Range<usize>) {
+        let buffer = self.get_owned_buffer();
+        buffer.drain(range);
+    }
+}
+
+pub(crate) struct SeededVisitor<'a, 'de> {
+    buffer: &'a mut CowByteBuffer<'de>,
+}
+
+impl<'a, 'de> DeserializeSeed<'de> for SeededVisitor<'a, 'de> {
+    type Value = ElementType;
+
+    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        deserializer.deserialize_newtype_struct(RAW_BSON_NEWTYPE, self)
+    }
+}
+
+impl<'a, 'de> DeserializeSeed<'de> for &mut SeededVisitor<'a, 'de> {
+    type Value = ElementType;
+
+    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        deserializer.deserialize_newtype_struct(
+            RAW_BSON_NEWTYPE,
+            SeededVisitor {
+                buffer: self.buffer,
+            },
+        )
+    }
+}
+
+/// A visitor that builds up a raw BSON value in a single buffer. This visitor will only produce
+/// valid BSON if the value being deserialized is a byte buffer, slice of bytes, map, or sequence.
+/// Implementations using this visitor should check the `ElementType` returned from `deserialize` to
+/// validate that a valid BSON type was visited.
+impl<'a, 'de> SeededVisitor<'a, 'de> {
+    pub(crate) fn new(buffer: &'a mut CowByteBuffer<'de>) -> Self {
+        Self { buffer }
+    }
+
+    /// Appends a cstring to the buffer. Returns an error if the given string contains a null byte.
+    fn append_cstring(&mut self, key: &str) -> Result<(), String> {
+        let key_bytes = key.as_bytes();
+        if key_bytes.contains(&0) {
+            return Err(format!("key contains interior null byte: {}", key));
+        }
+
+        self.buffer.append_bytes(key_bytes);
+        self.buffer.push_byte(0);
+
+        Ok(())
+    }
+
+    /// Appends a string and its length to the buffer.
+    fn append_string(&mut self, s: &str) {
+        let bytes = s.as_bytes();
+
+        // Add 1 to account for null byte.
+        self.append_length_bytes((bytes.len() + 1) as i32);
+
+        self.buffer.append_bytes(bytes);
+        self.buffer.push_byte(0);
+    }
+
+    /// Converts the given length into little-endian bytes and appends the bytes to the buffer.
+    fn append_length_bytes(&mut self, length: i32) {
+        self.buffer.append_bytes(&length.to_le_bytes());
+    }
+
+    /// Appends an owned byte buffer to the buffer. If the buffer is currently empty (i.e. the byte
+    /// buffer was the top-level value provided to the deserializer), the buffer will be updated to
+    /// contain an owned copy of the bytes provided. Otherwise (i.e. when the value is embedded),
+    /// the bytes and their corresponding length and subtype bytes will be appended to the
+    /// buffer.
+    fn append_owned_binary(&mut self, bytes: Vec<u8>, subtype: u8) {
+        match &mut self.buffer.0 {
+            Some(_) => self.append_embedded_binary(&bytes, subtype),
+            None => self.buffer.0 = Some(Cow::Owned(bytes)),
+        }
+    }
+
+    /// Appends a slice of bytes to the buffer. If the buffer is currently empty (i.e. the byte
+    /// buffer was the top-level value provided to the deserializer), the buffer will be updated to
+    /// contain a reference to the slice of bytes. Otherwise (i.e. when the value is embedded),
+    /// the bytes and their corresponding length and subtype will be appended to the buffer.
+    fn append_borrowed_binary(&mut self, bytes: &'de [u8], subtype: u8) {
+        match &self.buffer.0 {
+            Some(_) => self.append_embedded_binary(bytes, subtype),
+            None => self.buffer.0 = Some(Cow::Borrowed(bytes)),
+        }
+    }
+
+    /// Appends the given bytes and their corresponding length and subtype to the buffer.
+    fn append_embedded_binary(&mut self, bytes: &[u8], subtype: impl Into<u8>) {
+        self.append_length_bytes(bytes.len() as i32);
+        self.buffer.push_byte(subtype.into());
+        self.buffer.append_bytes(bytes);
+    }
+
+    /// Appends 1 byte to the buffer as a placeholder for an element type. This byte should be
+    /// overwritten by a call to append_element after the element has been written to the buffer.
+    fn pad_element_type(&mut self) -> usize {
+        let index = self.buffer.len();
+        self.buffer.push_byte(0);
+        index
+    }
+
+    /// Writes the given element_type at the given index, which should be obtained from
+    /// pad_element_type.
+    fn write_element_type(&mut self, element_type: ElementType, index: usize) {
+        self.buffer
+            .copy_from_slice(index..index + 1, &[element_type as u8]);
+    }
+
+    /// Appends 4 bytes to the buffer as a placeholder for the length of a document. These bytes
+    /// should be overwritten by a call to finish_document after the data in the document has been
+    /// written.
+    fn pad_document_length(&mut self) -> usize {
+        let index = self.buffer.len();
+        self.buffer.append_bytes(&[0; 4]);
+        index
+    }
+
+    /// Writes the length of a document at the given index, which should be obtained from
+    /// pad_document_length, and appends the final null byte of the document. Returns an error if
+    /// the size does not fit into an i32.
+    fn finish_document(&mut self, length_index: usize) -> Result<(), String> {
+        self.buffer.push_byte(0);
+
+        let length_bytes = match i32::try_from(self.buffer.len() - length_index) {
+            Ok(length) => length.to_le_bytes(),
+            Err(_) => return Err("value exceeds maximum length".to_string()),
+        };
+
+        self.buffer
+            .copy_from_slice(length_index..length_index + 4, &length_bytes);
+
+        Ok(())
+    }
+
+    /// Iterates the given `MapAccess` and appends its keys and values to the buffer. The given map
+    /// must have had `next_key` called exactly once, and the value returned from that call must be
+    /// provided as `first_key`. `next_value` must not have been called on the map.
+    pub(crate) fn iterate_map<A>(mut self, first_key: CowStr, mut map: A) -> Result<(), A::Error>
+    where
+        A: MapAccess<'de>,
+    {
+        let length_index = self.pad_document_length();
+
+        let mut current_key = first_key;
+        loop {
+            let element_type_index = self.pad_element_type();
+            self.append_cstring(current_key.0.as_ref())
+                .map_err(SerdeError::custom)?;
+            let element_type = map.next_value_seed(&mut self)?;
+            self.write_element_type(element_type, element_type_index);
+
+            match map.next_key::<CowStr>()? {
+                Some(next_key) => current_key = next_key,
+                None => break,
+            }
+        }
+
+        self.finish_document(length_index)
+            .map_err(SerdeError::custom)?;
+        Ok(())
+    }
+}
+
+impl<'a, 'de> Visitor<'de> for SeededVisitor<'a, 'de> {
+    type Value = ElementType;
+
+    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
+        formatter.write_str("a raw BSON value")
+    }
+
+    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        deserializer.deserialize_any(self)
+    }
+
+    fn visit_map<A>(mut self, mut map: A) -> Result<Self::Value, A::Error>
+    where
+        A: MapAccess<'de>,
+    {
+        let first_key = match map.next_key::<CowStr>()? {
+            Some(key) => key,
+            None => {
+                self.buffer
+                    .append_bytes(&MIN_BSON_DOCUMENT_SIZE.to_le_bytes());
+                self.buffer.push_byte(0);
+                return Ok(ElementType::EmbeddedDocument);
+            }
+        };
+
+        match first_key.0.as_ref() {
+            "$oid" => {
+                let oid: ObjectId = map.next_value()?;
+                self.buffer.append_bytes(&oid.bytes());
+                Ok(ElementType::ObjectId)
+            }
+            "$symbol" => {
+                let s: &str = map.next_value()?;
+                self.append_string(s);
+                Ok(ElementType::Symbol)
+            }
+            "$numberDecimalBytes" => {
+                let bytes: ByteBuf = map.next_value()?;
+                self.buffer.append_bytes(&bytes.into_vec());
+                Ok(ElementType::Decimal128)
+            }
+            "$regularExpression" => {
+                let regex: BorrowedRegexBody = map.next_value()?;
+                let pattern = regex.pattern.as_ref();
+                let options = regex.options.as_ref();
+
+                self.append_cstring(pattern).map_err(SerdeError::custom)?;
+                self.append_cstring(options).map_err(SerdeError::custom)?;
+
+                Ok(ElementType::RegularExpression)
+            }
+            "$undefined" => {
+                let _: bool = map.next_value()?;
+                Ok(ElementType::Undefined)
+            }
+            "$binary" => {
+                let binary: BorrowedBinaryBody = map.next_value()?;
+                match binary.bytes {
+                    Cow::Borrowed(borrowed_bytes) => {
+                        self.append_borrowed_binary(borrowed_bytes, binary.subtype);
+                    }
+                    Cow::Owned(owned_bytes) => {
+                        self.append_owned_binary(owned_bytes, binary.subtype);
+                    }
+                }
+
+                Ok(ElementType::Binary)
+            }
+            "$date" => {
+                let date: i64 = map.next_value()?;
+                self.buffer.append_bytes(&date.to_le_bytes());
+                Ok(ElementType::DateTime)
+            }
+            "$timestamp" => {
+                let timestamp: TimestampBody = map.next_value()?;
+                self.buffer.append_bytes(&timestamp.i.to_le_bytes());
+                self.buffer.append_bytes(&timestamp.t.to_le_bytes());
+                Ok(ElementType::Timestamp)
+            }
+            "$minKey" => {
+                let _: i32 = map.next_value()?;
+                Ok(ElementType::MinKey)
+            }
+            "$maxKey" => {
+                let _: i32 = map.next_value()?;
+                Ok(ElementType::MaxKey)
+            }
+            "$code" => {
+                let code: CowStr = map.next_value()?;
+                if let Some(key) = map.next_key::<CowStr>()? {
+                    let key = key.0.as_ref();
+                    if key == "$scope" {
+                        let length_index = self.pad_document_length();
+                        self.append_string(code.0.as_ref());
+
+                        let scope: RawDocumentBuf = map.next_value()?;
+                        self.buffer.append_bytes(scope.as_bytes());
+
+                        let length_bytes =
+                            ((self.buffer.len() - length_index) as i32).to_le_bytes();
+                        self.buffer
+                            .copy_from_slice(length_index..length_index + 4, &length_bytes);
+
+                        Ok(ElementType::JavaScriptCodeWithScope)
+                    } else {
+                        Err(SerdeError::unknown_field(key, &["$scope"]))
+                    }
+                } else {
+                    self.append_string(code.0.as_ref());
+                    Ok(ElementType::JavaScriptCode)
+                }
+            }
+            "$dbPointer" => {
+                let db_pointer: BorrowedDbPointerBody = map.next_value()?;
+
+                self.append_string(db_pointer.ns.0.as_ref());
+                self.buffer.append_bytes(&db_pointer.id.bytes());
+
+                Ok(ElementType::DbPointer)
+            }
+            RAW_DOCUMENT_NEWTYPE => {
+                let document_bytes: &[u8] = map.next_value()?;
+                self.buffer.append_borrowed_bytes(document_bytes);
+                Ok(ElementType::EmbeddedDocument)
+            }
+            RAW_ARRAY_NEWTYPE => {
+                let array_bytes: &[u8] = map.next_value()?;
+                self.buffer.append_borrowed_bytes(array_bytes);
+                Ok(ElementType::Array)
+            }
+            _ => {
+                self.iterate_map(first_key, map)?;
+                Ok(ElementType::EmbeddedDocument)
+            }
+        }
+    }
+
+    fn visit_seq<A>(mut self, mut seq: A) -> Result<Self::Value, A::Error>
+    where
+        A: SeqAccess<'de>,
+    {
+        let length_index = self.pad_document_length();
+
+        let mut i = 0u32;
+        loop {
+            let element_type_index = self.pad_element_type();
+            let key = i.to_string();
+            self.append_cstring(&key).map_err(SerdeError::custom)?;
+
+            let element_type = match seq.next_element_seed(&mut self)? {
+                Some(element_type) => element_type,
+                None => {
+                    // Remove the additional key and padding for the element that was not present.
+                    self.buffer.drain(element_type_index..self.buffer.len());
+                    break;
+                }
+            };
+
+            self.write_element_type(element_type, element_type_index);
+            i += 1;
+        }
+
+        self.finish_document(length_index)
+            .map_err(SerdeError::custom)?;
+        Ok(ElementType::Array)
+    }
+
+    // visit_string and visit_borrowed_str will forward to this method.
+    fn visit_str<E>(mut self, s: &str) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.append_string(s);
+        Ok(ElementType::String)
+    }
+
+    fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.push_byte(b as u8);
+        Ok(ElementType::Boolean)
+    }
+
+    fn visit_i8<E>(self, n: i8) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&(n as i32).to_le_bytes());
+        Ok(ElementType::Int32)
+    }
+
+    fn visit_i16<E>(self, n: i16) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&(n as i32).to_le_bytes());
+        Ok(ElementType::Int32)
+    }
+
+    fn visit_i32<E>(self, n: i32) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&n.to_le_bytes());
+        Ok(ElementType::Int32)
+    }
+
+    fn visit_i64<E>(self, n: i64) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&n.to_le_bytes());
+        Ok(ElementType::Int64)
+    }
+
+    fn visit_u8<E>(self, n: u8) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&(n as i32).to_le_bytes());
+        Ok(ElementType::Int32)
+    }
+
+    fn visit_u16<E>(self, n: u16) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&(n as i32).to_le_bytes());
+        Ok(ElementType::Int32)
+    }
+
+    fn visit_u32<E>(self, n: u32) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        match i32::try_from(n) {
+            Ok(n) => {
+                self.buffer.append_bytes(&n.to_le_bytes());
+                Ok(ElementType::Int32)
+            }
+            Err(_) => {
+                self.buffer.append_bytes(&(n as i64).to_le_bytes());
+                Ok(ElementType::Int64)
+            }
+        }
+    }
+
+    fn visit_u64<E>(self, n: u64) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        if let Ok(n) = i32::try_from(n) {
+            self.buffer.append_bytes(&n.to_le_bytes());
+            Ok(ElementType::Int32)
+        } else if let Ok(n) = i64::try_from(n) {
+            self.buffer.append_bytes(&n.to_le_bytes());
+            Ok(ElementType::Int64)
+        } else {
+            Err(SerdeError::custom(format!(
+                "number is too large for BSON: {}",
+                n
+            )))
+        }
+    }
+
+    fn visit_f64<E>(self, n: f64) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.buffer.append_bytes(&n.to_le_bytes());
+        Ok(ElementType::Double)
+    }
+
+    fn visit_none<E>(self) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(ElementType::Null)
+    }
+
+    fn visit_unit<E>(self) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        Ok(ElementType::Null)
+    }
+
+    // visit_byte_buf will forward to this method.
+    fn visit_bytes<E>(mut self, bytes: &[u8]) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.append_owned_binary(bytes.to_owned(), BinarySubtype::Generic.into());
+        Ok(ElementType::Binary)
+    }
+
+    fn visit_borrowed_bytes<E>(mut self, bytes: &'de [u8]) -> Result<Self::Value, E>
+    where
+        E: SerdeError,
+    {
+        self.append_borrowed_binary(bytes, BinarySubtype::Generic.into());
+        Ok(ElementType::Binary)
+    }
+}
diff --git a/src/tests/spec/mod.rs b/src/tests/spec/mod.rs
index c0a4306b..36ff825e 100644
--- a/src/tests/spec/mod.rs
+++ b/src/tests/spec/mod.rs
@@ -1,15 +1,14 @@
 mod corpus;
 
 use std::{
-    convert::TryFrom,
+    any::type_name,
     ffi::OsStr,
     fs::{self, File},
     path::PathBuf,
 };
 
-use crate::{from_bson, Bson};
+use crate::RawDocumentBuf;
 use serde::de::DeserializeOwned;
-use serde_json::Value;
 
 pub(crate) fn run_spec_test<T, F>(spec: &[&str], run_test_file: F)
 where
@@ -21,22 +20,32 @@ where
         .chain(spec.iter())
         .collect();
 
-    for entry in fs::read_dir(&base_path).unwrap() {
-        let test_file = entry.unwrap();
-
-        if !test_file.file_type().unwrap().is_file() {
+    for entry in fs::read_dir(&base_path)
+        .unwrap_or_else(|e| panic!("Failed to read directory at {:?}: {}", base_path, e))
+    {
+        let path = entry.unwrap().path();
+        if path.extension() != Some(OsStr::new("json")) {
             continue;
         }
 
-        let test_file_path = PathBuf::from(test_file.file_name());
-        if test_file_path.extension().and_then(OsStr::to_str) != Some("json") {
-            continue;
-        }
-
-        let test_file_full_path = base_path.join(&test_file_path);
-        let json: Value =
-            serde_json::from_reader(File::open(test_file_full_path.as_path()).unwrap()).unwrap();
-
-        run_test_file(from_bson(Bson::try_from(json).unwrap()).unwrap())
+        let file = File::open(&path)
+            .unwrap_or_else(|e| panic!("Failed to open file at {:?}: {}", path, e));
+
+        let test_bson: RawDocumentBuf = serde_json::from_reader(file).unwrap_or_else(|e| {
+            panic!(
+                "Failed to deserialize test JSON to BSON in {:?}: {}",
+                path, e
+            )
+        });
+        let test: T = crate::from_slice(test_bson.as_bytes()).unwrap_or_else(|e| {
+            panic!(
+                "Failed to deserialize test BSON to {} in {:?}: {}",
+                type_name::<T>(),
+                path,
+                e
+            )
+        });
+
+        run_test_file(test)
     }
 }

From a73ee9d4f3e2c980d83cf02b57d22fa2f5951f7c Mon Sep 17 00:00:00 2001
From: Valentin Kovalenko <valentin.kovalenko@mongodb.com>
Date: Wed, 25 Oct 2023 09:51:13 -0600
Subject: [PATCH 041/156] RUST-1780 Bump MSRV to 1.61.0, upgrade `ahash` to
 0.8.5 in `Cargo.lock.msrv` (#436)

---
 .evergreen/Cargo.lock.msrv | 27 ++++++++++++++++++++++++---
 .evergreen/config.yml      |  4 ++--
 README.md                  |  2 +-
 clippy.toml                |  2 +-
 src/lib.rs                 |  4 ++--
 5 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/.evergreen/Cargo.lock.msrv b/.evergreen/Cargo.lock.msrv
index d7c8b742..98545ca3 100644
--- a/.evergreen/Cargo.lock.msrv
+++ b/.evergreen/Cargo.lock.msrv
@@ -4,14 +4,15 @@ version = 3
 
 [[package]]
 name = "ahash"
-version = "0.8.0"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57e6e951cfbb2db8de1828d49073a113a29fd7117b1596caa781a258c7e38d72"
+checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d"
 dependencies = [
  "cfg-if",
  "getrandom",
  "once_cell",
  "version_check",
+ "zerocopy",
 ]
 
 [[package]]
@@ -102,7 +103,7 @@ dependencies = [
 
 [[package]]
 name = "bson"
-version = "2.6.0"
+version = "2.7.0"
 dependencies = [
  "ahash",
  "assert_matches",
@@ -1406,3 +1407,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
 dependencies = [
  "tap",
 ]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a7af71d8643341260a65f89fa60c0eeaa907f34544d8f6d9b0df72f069b5e74"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9731702e2f0617ad526794ae28fbc6f6ca8849b5ba729666c2a5bc4b6ddee2cd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.16",
+]
diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index ffb6f432..9dfe4af8 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -195,9 +195,9 @@ axes:
   - id: "extra-rust-versions"
     values:
       - id: "min"
-        display_name: "1.60 (minimum supported version)"
+        display_name: "1.61 (minimum supported version)"
         variables:
-          RUST_VERSION: "1.60.0"
+          RUST_VERSION: "1.61.0"
           MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
diff --git a/README.md b/README.md
index f7bb0716..c8d288be 100644
--- a/README.md
+++ b/README.md
@@ -257,7 +257,7 @@ This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `
 
 ## Minimum supported Rust version (MSRV)
 
-The MSRV for this crate is currently 1.48.0. This will be rarely be increased, and if it ever is,
+The MSRV for this crate is currently 1.61.0. This will be rarely be increased, and if it ever is,
 it will only happen in a minor or major version release.
 
 ## Contributing
diff --git a/clippy.toml b/clippy.toml
index 59d02545..f6c82f96 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1 +1 @@
-msrv = "1.60.0"
\ No newline at end of file
+msrv = "1.61.0"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 4321f858..be000914 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,7 +43,7 @@
 //!
 //! ## Installation
 //! ### Requirements
-//! - Rust 1.60+
+//! - Rust 1.61+
 //!
 //! ### Importing
 //! This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application,
@@ -267,7 +267,7 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.60.0. This will be rarely be increased, and if it ever is,
+//! The MSRV for this crate is currently 1.61.0. This will be rarely be increased, and if it ever is,
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]

From f2cd720d4546527edf78b8963464bf930fc18b92 Mon Sep 17 00:00:00 2001
From: Prashant Deva <prashant.deva@gmail.com>
Date: Tue, 7 Nov 2023 09:28:15 -0800
Subject: [PATCH 042/156] minor: use random() directly in gen_process_id (#438)

---
 src/oid.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/oid.rs b/src/oid.rs
index 1e5f7ad5..47dc3907 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -14,7 +14,7 @@ use std::{convert::TryInto, time::SystemTime};
 
 use hex::{self, FromHexError};
 use once_cell::sync::Lazy;
-use rand::{thread_rng, Rng};
+use rand::{random, thread_rng, Rng};
 
 const TIMESTAMP_SIZE: usize = 4;
 const PROCESS_ID_SIZE: usize = 5;
@@ -253,7 +253,7 @@ impl ObjectId {
 
     /// Generate a random 5-byte array.
     fn gen_process_id() -> [u8; 5] {
-        static BUF: Lazy<[u8; 5]> = Lazy::new(|| thread_rng().gen());
+        static BUF: Lazy<[u8; 5]> = Lazy::new(random);
 
         *BUF
     }

From 412e45678fde89cee4616c6358f486cbc14b85c2 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 30 Nov 2023 10:12:59 -0500
Subject: [PATCH 043/156] RUST-1805 Only use js-sys with unknown os (#442)

---
 Cargo.toml | 2 +-
 src/oid.rs | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index acdca236..14dc32c6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -70,7 +70,7 @@ serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
 
-[target.'cfg(target_arch = "wasm32")'.dependencies]
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
 js-sys = "0.3"
 [dev-dependencies]
 assert_matches = "1.2"
diff --git a/src/oid.rs b/src/oid.rs
index 47dc3907..a8cc3448 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -239,9 +239,9 @@ impl ObjectId {
     /// Generates a new timestamp representing the current seconds since epoch.
     /// Represented in Big Endian.
     fn gen_timestamp() -> [u8; 4] {
-        #[cfg(target_arch = "wasm32")]
+        #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
         let timestamp: u32 = (js_sys::Date::now() / 1000.0) as u32;
-        #[cfg(not(target_arch = "wasm32"))]
+        #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
         let timestamp: u32 = SystemTime::now()
             .duration_since(SystemTime::UNIX_EPOCH)
             .expect("system clock is before 1970")

From 6981c342c7799c39dd049d49d341da3f26a18db2 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 11 Dec 2023 11:49:50 -0500
Subject: [PATCH 044/156] release v2.8.0 (#443) (#444)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 14dc32c6..ac515f24 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.7.0"
+version = "2.8.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index c8d288be..87e89fb4 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.7.0"
+bson = "2.8.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index be000914..811f0f0a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.7.0"
+//! bson = "2.8.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From 4af5805248a063285e9add84adc7ff11934b04e5 Mon Sep 17 00:00:00 2001
From: Kai Ren <tyranron@gmail.com>
Date: Tue, 12 Dec 2023 16:56:12 +0100
Subject: [PATCH 045/156] Fix compilation on `wasm32-wasi` target (#445)

---
 .evergreen/compile-only.sh |  9 +++++++--
 .evergreen/config.yml      | 15 ++++++++++++++-
 Cargo.toml                 |  4 +++-
 src/oid.rs                 |  2 +-
 4 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index babe64f4..9dda7345 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -5,9 +5,14 @@ set -o errexit
 . ~/.cargo/env
 rustup update $RUST_VERSION
 
+if [ ! -z "$TARGET" ]; then
+    rustup target add $TARGET --toolchain $RUST_VERSION
+    TARGET="--target=$TARGET"
+fi
+
 # pin all dependencies when checking msrv compilation
-if [  "$MSRV" = "true" ]; then
+if [ "$MSRV" = "true" ]; then
     cp .evergreen/Cargo.lock.msrv Cargo.lock
 fi
 
-rustup run $RUST_VERSION cargo build
+rustup run $RUST_VERSION cargo build $TARGET
diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 9dfe4af8..a41831ab 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -90,7 +90,7 @@ functions:
         working_dir: "src"
         script: |
           ${PREPARE_SHELL}
-          RUST_VERSION=${RUST_VERSION} MSRV=${MSRV} .evergreen/compile-only.sh
+          RUST_VERSION=${RUST_VERSION} MSRV=${MSRV} TARGET=${TARGET} .evergreen/compile-only.sh
 
   "check rustfmt":
     - command: shell.exec
@@ -203,6 +203,18 @@ axes:
         display_name: "nightly"
         variables:
           RUST_VERSION: "nightly"
+  - id: "extra-targets"
+    values:
+      - id: "current"
+        display_name: "current target"
+      - id: "wasi"
+        display_name: "WASI"
+        variables:
+          TARGET: "wasm32-wasi"
+      - id: "wasm"
+        display_name: "WASM"
+        variables:
+          TARGET: "wasm32-unknown-unknown"
 
 buildvariants:
 -
@@ -216,6 +228,7 @@ buildvariants:
 - matrix_name: "compile only"
   matrix_spec:
     extra-rust-versions: "*"
+    extra-targets: "*"
   display_name: "Compile on Rust ${extra-rust-versions}"
   run_on:
     - ubuntu1804-test
diff --git a/Cargo.toml b/Cargo.toml
index ac515f24..df7e6a2b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -69,9 +69,9 @@ serde_with = { version = "1.3.1", optional = true }
 serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
-
 [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
 js-sys = "0.3"
+
 [dev-dependencies]
 assert_matches = "1.2"
 criterion = "0.3.0"
@@ -79,6 +79,8 @@ pretty_assertions = "0.6.1"
 proptest = "1.0.0"
 serde_bytes = "0.11"
 chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false }
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
+getrandom = { version = "0.2", features = ["js"] }
 
 [package.metadata.docs.rs]
 all-features = true
diff --git a/src/oid.rs b/src/oid.rs
index a8cc3448..89374a7e 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -9,7 +9,7 @@ use std::{
     sync::atomic::{AtomicUsize, Ordering},
 };
 
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 use std::{convert::TryInto, time::SystemTime};
 
 use hex::{self, FromHexError};

From d044889a9fbfac8846d35cdfcac1b08dc76bcffe Mon Sep 17 00:00:00 2001
From: Nathan Froyd <froydnj@gmail.com>
Date: Tue, 9 Jan 2024 12:52:05 -0500
Subject: [PATCH 046/156] minor: bump indexmap to `2.1.0` (#448)

---------

Co-authored-by: Isabel Atkinson <isabel.atkinson@mongodb.com>
---
 .evergreen/config.yml | 4 ++--
 Cargo.toml            | 2 +-
 README.md             | 4 ++--
 clippy.toml           | 2 +-
 src/bson.rs           | 9 ++-------
 src/lib.rs            | 4 ++--
 6 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index a41831ab..d27fca57 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -195,9 +195,9 @@ axes:
   - id: "extra-rust-versions"
     values:
       - id: "min"
-        display_name: "1.61 (minimum supported version)"
+        display_name: "1.64 (minimum supported version)"
         variables:
-          RUST_VERSION: "1.61.0"
+          RUST_VERSION: "1.64.0"
           MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
diff --git a/Cargo.toml b/Cargo.toml
index df7e6a2b..21d66256 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,7 +58,7 @@ chrono = { version = "0.4.15", features = ["std"], default-features = false, opt
 rand = "0.8"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", features = ["preserve_order"] }
-indexmap = "1.6.2"
+indexmap = "2.1.0"
 hex = "0.4.2"
 base64 = "0.13.0"
 once_cell = "1.5.1"
diff --git a/README.md b/README.md
index 87e89fb4..b0aaaf95 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
 | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
 | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
-| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.  Requires Rust 1.61. | serde_with         | no      |
+| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 ## Overview of the BSON Format
 
 BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents.
@@ -257,7 +257,7 @@ This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `
 
 ## Minimum supported Rust version (MSRV)
 
-The MSRV for this crate is currently 1.61.0. This will be rarely be increased, and if it ever is,
+The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever is,
 it will only happen in a minor or major version release.
 
 ## Contributing
diff --git a/clippy.toml b/clippy.toml
index f6c82f96..3eb5fd06 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1 +1 @@
-msrv = "1.61.0"
\ No newline at end of file
+msrv = "1.64.0"
\ No newline at end of file
diff --git a/src/bson.rs b/src/bson.rs
index 92f93a8b..07a424a3 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -37,7 +37,7 @@ use crate::{
 };
 
 /// Possible BSON value types.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Default, PartialEq)]
 pub enum Bson {
     /// 64-bit binary floating point
     Double(f64),
@@ -50,6 +50,7 @@ pub enum Bson {
     /// Boolean value
     Boolean(bool),
     /// Null value
+    #[default]
     Null,
     /// Regular expression
     RegularExpression(Regex),
@@ -86,12 +87,6 @@ pub enum Bson {
 /// Alias for `Vec<Bson>`.
 pub type Array = Vec<Bson>;
 
-impl Default for Bson {
-    fn default() -> Self {
-        Bson::Null
-    }
-}
-
 impl Display for Bson {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match *self {
diff --git a/src/lib.rs b/src/lib.rs
index 811f0f0a..1f5dda48 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,7 +43,7 @@
 //!
 //! ## Installation
 //! ### Requirements
-//! - Rust 1.61+
+//! - Rust 1.64+
 //!
 //! ### Importing
 //! This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application,
@@ -267,7 +267,7 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.61.0. This will be rarely be increased, and if it ever is,
+//! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever is,
 //! it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]

From 9294ee5b458c46966e518ddc29fa414e8318d86f Mon Sep 17 00:00:00 2001
From: Sam Kleinman <garen@tychoish.com>
Date: Thu, 18 Jan 2024 10:14:27 -0500
Subject: [PATCH 047/156] provide lazy iterator implementation (#449)

---
 src/raw/array.rs        |  11 +-
 src/raw/document.rs     |  28 ++-
 src/raw/document_buf.rs |  25 +-
 src/raw/error.rs        |   8 +
 src/raw/iter.rs         | 508 +++++++++++++++++++++++-----------------
 src/raw/mod.rs          |  28 +--
 6 files changed, 359 insertions(+), 249 deletions(-)

diff --git a/src/raw/array.rs b/src/raw/array.rs
index a77002ec..497e820c 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -6,10 +6,10 @@ use super::{
     error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
     serde::OwnedOrBorrowedRawArray,
     Error,
-    Iter,
     RawBinaryRef,
     RawBsonRef,
     RawDocument,
+    RawIter,
     RawRegexRef,
     Result,
 };
@@ -260,14 +260,14 @@ impl<'a> IntoIterator for &'a RawArray {
 
     fn into_iter(self) -> RawArrayIter<'a> {
         RawArrayIter {
-            inner: self.doc.into_iter(),
+            inner: RawIter::new(&self.doc),
         }
     }
 }
 
 /// An iterator over borrowed raw BSON array values.
 pub struct RawArrayIter<'a> {
-    inner: Iter<'a>,
+    inner: RawIter<'a>,
 }
 
 impl<'a> Iterator for RawArrayIter<'a> {
@@ -275,7 +275,10 @@ impl<'a> Iterator for RawArrayIter<'a> {
 
     fn next(&mut self) -> Option<Result<RawBsonRef<'a>>> {
         match self.inner.next() {
-            Some(Ok((_, v))) => Some(Ok(v)),
+            Some(Ok(elem)) => match elem.value() {
+                Ok(value) => Some(Ok(value)),
+                Err(e) => Some(Err(e)),
+            },
             Some(Err(e)) => Some(Err(e)),
             None => None,
         }
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 57a42f10..51ca6530 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -15,12 +15,14 @@ use crate::{
 use super::{
     error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
     i32_from_slice,
+    iter::Iter,
+    try_to_str,
     Error,
-    Iter,
     RawArray,
     RawBinaryRef,
     RawBsonRef,
     RawDocumentBuf,
+    RawIter,
     RawRegexRef,
     Result,
 };
@@ -170,10 +172,10 @@ impl RawDocument {
     /// # Ok::<(), Error>(())
     /// ```
     pub fn get(&self, key: impl AsRef<str>) -> Result<Option<RawBsonRef<'_>>> {
-        for result in self.into_iter() {
-            let (k, v) = result?;
-            if key.as_ref() == k {
-                return Ok(Some(v));
+        for elem in RawIter::new(self) {
+            let elem = elem?;
+            if key.as_ref() == elem.key() {
+                return Ok(Some(elem.try_into()?));
             }
         }
         Ok(None)
@@ -492,6 +494,22 @@ impl RawDocument {
     pub fn is_empty(&self) -> bool {
         self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize
     }
+
+    pub(crate) fn read_cstring_at(&self, start_at: usize) -> Result<&str> {
+        let buf = &self.as_bytes()[start_at..];
+
+        let mut splits = buf.splitn(2, |x| *x == 0);
+        let value = splits
+            .next()
+            .ok_or_else(|| Error::new_without_key(ErrorKind::new_malformed("no value")))?;
+        if splits.next().is_some() {
+            Ok(try_to_str(value)?)
+        } else {
+            Err(Error::new_without_key(ErrorKind::new_malformed(
+                "expected null terminator",
+            )))
+        }
+    }
 }
 
 impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 978de443..525ebc44 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -17,12 +17,13 @@ use crate::{
 
 use super::{
     bson::RawBson,
+    iter::Iter,
     serde::OwnedOrBorrowedRawDocument,
     Error,
     ErrorKind,
-    Iter,
     RawBsonRef,
     RawDocument,
+    RawIter,
     Result,
 };
 
@@ -147,7 +148,27 @@ impl RawDocumentBuf {
     /// elements that might need to allocate, you must explicitly convert
     /// them to owned types yourself.
     pub fn iter(&self) -> Iter<'_> {
-        self.into_iter()
+        Iter::new(self)
+    }
+
+    /// Gets an iterator over the elements in the [`RawDocumentBuf`],
+    /// which yields `Result<RawElement<'_>>` values. These hold a
+    /// reference to the underlying document but do not explicitly
+    /// resolve the values.
+    ///
+    /// This iterator, which underpins the implementation of the
+    /// default iterator, produces `RawElement` objects, which
+    /// hold a view onto the document but do not parse out or
+    /// construct values until the `.value()` or `.try_into()` methods
+    /// are called.
+    ///
+    /// # Note:
+    ///
+    /// There is no owning iterator for [`RawDocumentBuf`]. If you
+    /// need ownership over elements that might need to allocate, you
+    /// must explicitly convert them to owned types yourself.
+    pub fn iter_elements(&self) -> RawIter<'_> {
+        RawIter::new(self)
     }
 
     /// Return the contained data as a `Vec<u8>`
diff --git a/src/raw/error.rs b/src/raw/error.rs
index 556b7fa0..b29fe280 100644
--- a/src/raw/error.rs
+++ b/src/raw/error.rs
@@ -48,6 +48,14 @@ pub enum ErrorKind {
     Utf8EncodingError(Utf8Error),
 }
 
+impl ErrorKind {
+    pub(crate) fn new_malformed(e: impl ToString) -> Self {
+        ErrorKind::MalformedValue {
+            message: e.to_string(),
+        }
+    }
+}
+
 impl std::fmt::Display for Error {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         let p = self
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 7588090a..1208b7ee 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -5,30 +5,61 @@ use crate::{
     oid::ObjectId,
     raw::{Error, ErrorKind, Result},
     spec::{BinarySubtype, ElementType},
+    Bson,
     DateTime,
     Decimal128,
+    RawArray,
+    RawBinaryRef,
+    RawBson,
+    RawDbPointerRef,
+    RawJavaScriptCodeWithScopeRef,
+    RawRegexRef,
     Timestamp,
 };
 
 use super::{
-    bson_ref::RawDbPointerRef,
     checked_add,
     error::try_with_key,
     f64_from_slice,
     i32_from_slice,
     i64_from_slice,
-    read_lenencoded,
-    read_nullterminated,
-    RawArray,
-    RawBinaryRef,
+    read_len,
+    read_lenencode,
+    try_to_str,
     RawBsonRef,
     RawDocument,
-    RawJavaScriptCodeWithScopeRef,
-    RawRegexRef,
 };
 
 /// An iterator over the document's entries.
 pub struct Iter<'a> {
+    inner: RawIter<'a>,
+}
+
+impl<'a> Iter<'a> {
+    pub(crate) fn new(doc: &'a RawDocument) -> Self {
+        Iter {
+            inner: RawIter::new(doc),
+        }
+    }
+}
+
+impl<'a> Iterator for Iter<'a> {
+    type Item = Result<(&'a str, RawBsonRef<'a>)>;
+
+    fn next(&mut self) -> Option<Result<(&'a str, RawBsonRef<'a>)>> {
+        match self.inner.next() {
+            Some(Ok(elem)) => match elem.value() {
+                Err(e) => Some(Err(e)),
+                Ok(value) => Some(Ok((elem.key, value))),
+            },
+            Some(Err(e)) => Some(Err(e)),
+            None => None,
+        }
+    }
+}
+
+/// An iterator over the document's elements.
+pub struct RawIter<'a> {
     doc: &'a RawDocument,
     offset: usize,
 
@@ -37,7 +68,7 @@ pub struct Iter<'a> {
     valid: bool,
 }
 
-impl<'a> Iter<'a> {
+impl<'a> RawIter<'a> {
     pub(crate) fn new(doc: &'a RawDocument) -> Self {
         Self {
             doc,
@@ -49,56 +80,223 @@ impl<'a> Iter<'a> {
     fn verify_enough_bytes(&self, start: usize, num_bytes: usize) -> Result<()> {
         let end = checked_add(start, num_bytes)?;
         if self.doc.as_bytes().get(start..end).is_none() {
-            return Err(Error::new_without_key(ErrorKind::MalformedValue {
-                message: format!(
-                    "length exceeds remaining length of buffer: {} vs {}",
-                    num_bytes,
-                    self.doc.as_bytes().len() - start
-                ),
-            }));
+            return Err(Error::new_without_key(ErrorKind::new_malformed(format!(
+                "length exceeds remaining length of buffer: {} vs {}",
+                num_bytes,
+                self.doc.as_bytes().len() - start
+            ))));
         }
         Ok(())
     }
 
-    fn next_oid(&self, starting_at: usize) -> Result<ObjectId> {
-        self.verify_enough_bytes(starting_at, 12)?;
-        let oid = ObjectId::from_bytes(
-            self.doc.as_bytes()[starting_at..(starting_at + 12)]
-                .try_into()
-                .unwrap(), // ok because we know slice is 12 bytes long
-        );
-        Ok(oid)
-    }
-
-    fn next_document(&self, starting_at: usize) -> Result<&'a RawDocument> {
+    fn next_document_len(&self, starting_at: usize) -> Result<usize> {
         self.verify_enough_bytes(starting_at, MIN_BSON_DOCUMENT_SIZE as usize)?;
         let size = i32_from_slice(&self.doc.as_bytes()[starting_at..])? as usize;
 
         if size < MIN_BSON_DOCUMENT_SIZE as usize {
-            return Err(Error::new_without_key(ErrorKind::MalformedValue {
-                message: format!("document too small: {} bytes", size),
-            }));
+            return Err(Error::new_without_key(ErrorKind::new_malformed(format!(
+                "document too small: {} bytes",
+                size
+            ))));
         }
 
         self.verify_enough_bytes(starting_at, size)?;
-        let end = starting_at + size;
-
-        if self.doc.as_bytes()[end - 1] != 0 {
-            return Err(Error {
-                key: None,
-                kind: ErrorKind::MalformedValue {
-                    message: "not null terminated".into(),
-                },
-            });
+
+        if self.doc.as_bytes()[starting_at + size - 1] != 0 {
+            return Err(Error::new_without_key(ErrorKind::new_malformed(
+                "not null terminated",
+            )));
         }
-        RawDocument::from_bytes(&self.doc.as_bytes()[starting_at..end])
+        Ok(size)
     }
 }
 
-impl<'a> Iterator for Iter<'a> {
-    type Item = Result<(&'a str, RawBsonRef<'a>)>;
+#[derive(Clone)]
+pub struct RawElement<'a> {
+    key: &'a str,
+    kind: ElementType,
+    doc: &'a RawDocument,
+    start_at: usize,
+    size: usize,
+}
 
-    fn next(&mut self) -> Option<Result<(&'a str, RawBsonRef<'a>)>> {
+impl<'a> TryInto<RawBsonRef<'a>> for RawElement<'a> {
+    type Error = Error;
+
+    fn try_into(self) -> Result<RawBsonRef<'a>> {
+        self.value()
+    }
+}
+
+impl<'a> TryInto<RawBson> for RawElement<'a> {
+    type Error = Error;
+
+    fn try_into(self) -> Result<RawBson> {
+        Ok(self.value()?.to_raw_bson())
+    }
+}
+
+impl<'a> TryInto<Bson> for RawElement<'a> {
+    type Error = Error;
+
+    fn try_into(self) -> Result<Bson> {
+        self.value()?.to_raw_bson().try_into()
+    }
+}
+
+impl<'a> RawElement<'a> {
+    pub fn len(&self) -> usize {
+        self.size
+    }
+
+    pub fn key(&self) -> &str {
+        self.key
+    }
+
+    pub fn element_type(&self) -> ElementType {
+        self.kind
+    }
+
+    pub fn value(&self) -> Result<RawBsonRef<'a>> {
+        Ok(match self.kind {
+            ElementType::Null => RawBsonRef::Null,
+            ElementType::Undefined => RawBsonRef::Undefined,
+            ElementType::MinKey => RawBsonRef::MinKey,
+            ElementType::MaxKey => RawBsonRef::MaxKey,
+            ElementType::ObjectId => RawBsonRef::ObjectId(self.get_oid_at(self.start_at)?),
+            ElementType::Int32 => RawBsonRef::Int32(i32_from_slice(self.slice())?),
+            ElementType::Int64 => RawBsonRef::Int64(i64_from_slice(self.slice())?),
+            ElementType::Double => RawBsonRef::Double(f64_from_slice(self.slice())?),
+            ElementType::String => RawBsonRef::String(self.read_str()?),
+            ElementType::EmbeddedDocument => {
+                RawBsonRef::Document(RawDocument::from_bytes(self.slice())?)
+            }
+            ElementType::Array => {
+                RawBsonRef::Array(RawArray::from_doc(RawDocument::from_bytes(self.slice())?))
+            }
+            ElementType::Boolean => {
+                RawBsonRef::Boolean(read_bool(self.slice()).map_err(|e| self.malformed_error(e))?)
+            }
+            ElementType::DateTime => {
+                RawBsonRef::DateTime(DateTime::from_millis(i64_from_slice(self.slice())?))
+            }
+            ElementType::Decimal128 => RawBsonRef::Decimal128(Decimal128::from_bytes(
+                self.slice()
+                    .try_into()
+                    .map_err(|e| self.malformed_error(e))?,
+            )),
+            ElementType::JavaScriptCode => RawBsonRef::JavaScriptCode(self.read_str()?),
+            ElementType::Symbol => RawBsonRef::Symbol(self.read_str()?),
+            ElementType::DbPointer => RawBsonRef::DbPointer(RawDbPointerRef {
+                namespace: read_lenencode(self.slice())?,
+                id: self.get_oid_at(self.start_at + (self.size - 12))?,
+            }),
+            ElementType::RegularExpression => {
+                let pattern = self.doc.read_cstring_at(self.start_at)?;
+                RawBsonRef::RegularExpression(RawRegexRef {
+                    pattern,
+                    options: self
+                        .doc
+                        .read_cstring_at(self.start_at + pattern.len() + 1)?,
+                })
+            }
+            ElementType::Timestamp => RawBsonRef::Timestamp(
+                Timestamp::from_reader(self.slice()).map_err(|e| self.malformed_error(e))?,
+            ),
+            ElementType::Binary => {
+                let len = self.size.checked_sub(4 + 1).ok_or_else(|| {
+                    self.malformed_error(format!("length exceeds maximum: {}", self.size))
+                })?;
+
+                let data_start = self.start_at + 4 + 1;
+
+                if self.size >= i32::MAX as usize {
+                    return Err(
+                        self.malformed_error(format!("binary length exceeds maximum: {}", len))
+                    );
+                }
+
+                let subtype = BinarySubtype::from(self.doc.as_bytes()[self.start_at + 4]);
+                let data = match subtype {
+                    BinarySubtype::BinaryOld => {
+                        if len < 4 {
+                            return Err(self.malformed_error(
+                                "old binary subtype has no inner declared length",
+                            ));
+                        }
+                        let oldlength =
+                            i32_from_slice(&self.doc.as_bytes()[data_start..])? as usize;
+                        if checked_add(oldlength, 4)? != len {
+                            return Err(self.malformed_error(
+                                "old binary subtype has wrong inner declared length",
+                            ));
+                        }
+                        self.slice_bounds(data_start + 4, len - 4)
+                    }
+                    _ => self.slice_bounds(data_start, len),
+                };
+                RawBsonRef::Binary(RawBinaryRef {
+                    subtype,
+                    bytes: data,
+                })
+            }
+            ElementType::JavaScriptCodeWithScope => {
+                if self.size < MIN_CODE_WITH_SCOPE_SIZE as usize {
+                    return Err(self.malformed_error("code with scope length too small"));
+                }
+
+                let slice = self.slice();
+                let code = read_lenencode(&slice[4..])?;
+                let scope_start = 4 + 4 + code.len() + 1;
+                let scope = RawDocument::from_bytes(&slice[scope_start..])?;
+
+                RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { code, scope })
+            }
+        })
+    }
+
+    fn malformed_error(&self, e: impl ToString) -> Error {
+        Error::new_with_key(self.key, ErrorKind::new_malformed(e))
+    }
+
+    fn slice(&self) -> &'a [u8] {
+        self.slice_bounds(self.start_at, self.size)
+    }
+
+    fn slice_bounds(&self, start_at: usize, size: usize) -> &'a [u8] {
+        &self.doc.as_bytes()[start_at..(start_at + size)]
+    }
+
+    fn read_str(&self) -> Result<&'a str> {
+        try_to_str(self.slice_bounds(self.start_at + 4, self.size - 4 - 1))
+    }
+
+    fn get_oid_at(&self, start_at: usize) -> Result<ObjectId> {
+        Ok(ObjectId::from_bytes(
+            self.doc.as_bytes()[start_at..(start_at + 12)]
+                .try_into()
+                .map_err(|e| Error::new_with_key(self.key, ErrorKind::new_malformed(e)))?,
+        ))
+    }
+}
+
+impl<'a> RawIter<'a> {
+    fn get_next_length_at(&self, start_at: usize) -> Result<usize> {
+        let len = i32_from_slice(&self.doc.as_bytes()[start_at..])?;
+        if len < 0 {
+            Err(Error::new_without_key(ErrorKind::new_malformed(
+                "lengths can't be negative",
+            )))
+        } else {
+            Ok(len as usize)
+        }
+    }
+}
+
+impl<'a> Iterator for RawIter<'a> {
+    type Item = Result<RawElement<'a>>;
+
+    fn next(&mut self) -> Option<Result<RawElement<'a>>> {
         if !self.valid {
             return None;
         } else if self.offset == self.doc.as_bytes().len() - 1 {
@@ -107,21 +305,18 @@ impl<'a> Iterator for Iter<'a> {
                 return None;
             } else {
                 self.valid = false;
-                return Some(Err(Error {
-                    key: None,
-                    kind: ErrorKind::MalformedValue {
-                        message: "document not null terminated".into(),
-                    },
-                }));
+                return Some(Err(Error::new_without_key(ErrorKind::new_malformed(
+                    "document not null terminated",
+                ))));
             }
         } else if self.offset >= self.doc.as_bytes().len() {
             self.valid = false;
-            return Some(Err(Error::new_without_key(ErrorKind::MalformedValue {
-                message: "iteration overflowed document".to_string(),
-            })));
+            return Some(Err(Error::new_without_key(ErrorKind::new_malformed(
+                "iteration overflowed document",
+            ))));
         }
 
-        let key = match read_nullterminated(&self.doc.as_bytes()[self.offset + 1..]) {
+        let key = match self.doc.read_cstring_at(self.offset + 1) {
             Ok(k) => k,
             Err(e) => {
                 self.valid = false;
@@ -129,193 +324,68 @@ impl<'a> Iterator for Iter<'a> {
             }
         };
 
+        let offset = self.offset + 1 + key.len() + 1; // type specifier + key + \0
         let kvp_result = try_with_key(key, || {
-            let valueoffset = self.offset + 1 + key.len() + 1; // type specifier + key + \0
-
             let element_type = match ElementType::from(self.doc.as_bytes()[self.offset]) {
                 Some(et) => et,
                 None => {
                     return Err(Error::new_with_key(
                         key,
-                        ErrorKind::MalformedValue {
-                            message: format!("invalid tag: {}", self.doc.as_bytes()[self.offset]),
-                        },
+                        ErrorKind::new_malformed(format!(
+                            "invalid tag: {}",
+                            self.doc.as_bytes()[self.offset]
+                        )),
                     ))
                 }
             };
 
-            let (element, element_size) = match element_type {
-                ElementType::Int32 => {
-                    let i = i32_from_slice(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::Int32(i), 4)
-                }
-                ElementType::Int64 => {
-                    let i = i64_from_slice(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::Int64(i), 8)
-                }
-                ElementType::Double => {
-                    let f = f64_from_slice(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::Double(f), 8)
-                }
-                ElementType::String => {
-                    let s = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::String(s), 4 + s.len() + 1)
-                }
-                ElementType::EmbeddedDocument => {
-                    let doc = self.next_document(valueoffset)?;
-                    (RawBsonRef::Document(doc), doc.as_bytes().len())
-                }
-                ElementType::Array => {
-                    let doc = self.next_document(valueoffset)?;
-                    (
-                        RawBsonRef::Array(RawArray::from_doc(doc)),
-                        doc.as_bytes().len(),
-                    )
-                }
-                ElementType::Binary => {
-                    let len = i32_from_slice(&self.doc.as_bytes()[valueoffset..])? as usize;
-                    let data_start = valueoffset + 4 + 1;
-
-                    if len >= i32::MAX as usize {
-                        return Err(Error::new_without_key(ErrorKind::MalformedValue {
-                            message: format!("binary length exceeds maximum: {}", len),
-                        }));
-                    }
-
-                    self.verify_enough_bytes(valueoffset + 4, len + 1)?;
-                    let subtype = BinarySubtype::from(self.doc.as_bytes()[valueoffset + 4]);
-                    let data = match subtype {
-                        BinarySubtype::BinaryOld => {
-                            if len < 4 {
-                                return Err(Error::new_without_key(ErrorKind::MalformedValue {
-                                    message: "old binary subtype has no inner declared length"
-                                        .into(),
-                                }));
-                            }
-                            let oldlength =
-                                i32_from_slice(&self.doc.as_bytes()[data_start..])? as usize;
-                            if checked_add(oldlength, 4)? != len {
-                                return Err(Error::new_without_key(ErrorKind::MalformedValue {
-                                    message: "old binary subtype has wrong inner declared length"
-                                        .into(),
-                                }));
-                            }
-                            &self.doc.as_bytes()[(data_start + 4)..(data_start + len)]
-                        }
-                        _ => &self.doc.as_bytes()[data_start..(data_start + len)],
-                    };
-                    (
-                        RawBsonRef::Binary(RawBinaryRef {
-                            subtype,
-                            bytes: data,
-                        }),
-                        4 + 1 + len,
-                    )
-                }
-                ElementType::ObjectId => {
-                    let oid = self.next_oid(valueoffset)?;
-                    (RawBsonRef::ObjectId(oid), 12)
-                }
-                ElementType::Boolean => {
-                    let b = read_bool(&self.doc.as_bytes()[valueoffset..]).map_err(|e| {
-                        Error::new_with_key(
-                            key,
-                            ErrorKind::MalformedValue {
-                                message: e.to_string(),
-                            },
-                        )
-                    })?;
-                    (RawBsonRef::Boolean(b), 1)
-                }
-                ElementType::DateTime => {
-                    let ms = i64_from_slice(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::DateTime(DateTime::from_millis(ms)), 8)
-                }
+            let element_size = match element_type {
+                ElementType::Boolean => 1,
+                ElementType::Int32 => 4,
+                ElementType::Int64 => 8,
+                ElementType::Double => 8,
+                ElementType::DateTime => 8,
+                ElementType::Timestamp => 8,
+                ElementType::ObjectId => 12,
+                ElementType::Decimal128 => 16,
+                ElementType::Null => 0,
+                ElementType::Undefined => 0,
+                ElementType::MinKey => 0,
+                ElementType::MaxKey => 0,
+                ElementType::String => read_len(&self.doc.as_bytes()[offset..])?,
+                ElementType::EmbeddedDocument => self.next_document_len(offset)?,
+                ElementType::Array => self.next_document_len(offset)?,
+                ElementType::Binary => self.get_next_length_at(offset)? + 4 + 1,
                 ElementType::RegularExpression => {
-                    let pattern = read_nullterminated(&self.doc.as_bytes()[valueoffset..])?;
-                    let options = read_nullterminated(
-                        &self.doc.as_bytes()[(valueoffset + pattern.len() + 1)..],
-                    )?;
-                    (
-                        RawBsonRef::RegularExpression(RawRegexRef { pattern, options }),
-                        pattern.len() + 1 + options.len() + 1,
-                    )
-                }
-                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| {
-                            Error::new_without_key(ErrorKind::MalformedValue {
-                                message: e.to_string(),
-                            })
-                        },
-                    )?;
-                    (RawBsonRef::Timestamp(ts), 8)
-                }
-                ElementType::JavaScriptCode => {
-                    let code = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::JavaScriptCode(code), 4 + code.len() + 1)
-                }
-                ElementType::JavaScriptCodeWithScope => {
-                    let length = i32_from_slice(&self.doc.as_bytes()[valueoffset..])? as usize;
-
-                    if length < MIN_CODE_WITH_SCOPE_SIZE as usize {
-                        return Err(Error::new_without_key(ErrorKind::MalformedValue {
-                            message: "code with scope length too small".to_string(),
-                        }));
-                    }
-
-                    self.verify_enough_bytes(valueoffset, length)?;
-                    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::from_bytes(&slice[scope_start..])?;
-                    (
-                        RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef {
-                            code,
-                            scope,
-                        }),
-                        length,
-                    )
-                }
-                ElementType::DbPointer => {
-                    let namespace = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?;
-                    let id = self.next_oid(valueoffset + 4 + namespace.len() + 1)?;
-                    (
-                        RawBsonRef::DbPointer(RawDbPointerRef { namespace, id }),
-                        4 + namespace.len() + 1 + 12,
-                    )
-                }
-                ElementType::Symbol => {
-                    let s = read_lenencoded(&self.doc.as_bytes()[valueoffset..])?;
-                    (RawBsonRef::Symbol(s), 4 + s.len() + 1)
-                }
-                ElementType::Decimal128 => {
-                    self.verify_enough_bytes(valueoffset, 16)?;
-                    (
-                        RawBsonRef::Decimal128(Decimal128::from_bytes(
-                            self.doc.as_bytes()[valueoffset..(valueoffset + 16)]
-                                .try_into()
-                                .unwrap(),
-                        )),
-                        16,
-                    )
+                    let pattern = self.doc.read_cstring_at(offset)?;
+                    let options = self.doc.read_cstring_at(offset + pattern.len() + 1)?;
+                    pattern.len() + 1 + options.len() + 1
                 }
-                ElementType::MinKey => (RawBsonRef::MinKey, 0),
-                ElementType::MaxKey => (RawBsonRef::MaxKey, 0),
+                ElementType::DbPointer => read_len(&self.doc.as_bytes()[offset..])? + 12,
+                ElementType::Symbol => read_len(&self.doc.as_bytes()[offset..])?,
+                ElementType::JavaScriptCode => read_len(&self.doc.as_bytes()[offset..])?,
+                ElementType::JavaScriptCodeWithScope => self.get_next_length_at(offset)?,
             };
 
-            self.offset = valueoffset + element_size;
-            self.verify_enough_bytes(valueoffset, element_size)?;
+            self.verify_enough_bytes(offset, element_size)?;
+            self.offset = offset + element_size;
 
-            Ok((key, element))
+            Ok((element_type, element_size))
         });
 
         if kvp_result.is_err() {
             self.valid = false;
         }
 
-        Some(kvp_result)
+        Some(match kvp_result {
+            Ok((kind, size)) => Ok(RawElement {
+                key,
+                kind,
+                doc: self.doc,
+                start_at: offset,
+                size,
+            }),
+            Err(e) => Err(e),
+        })
     }
 }
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index a96f6d13..56c6e130 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -142,7 +142,7 @@ pub use self::{
     document::RawDocument,
     document_buf::RawDocumentBuf,
     error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
-    iter::Iter,
+    iter::RawIter,
 };
 
 /// Special newtype name indicating that the type being (de)serialized is a raw BSON document.
@@ -196,23 +196,7 @@ fn i64_from_slice(val: &[u8]) -> Result<i64> {
     Ok(i64::from_le_bytes(arr))
 }
 
-fn read_nullterminated(buf: &[u8]) -> Result<&str> {
-    let mut splits = buf.splitn(2, |x| *x == 0);
-    let value = splits.next().ok_or_else(|| {
-        Error::new_without_key(ErrorKind::MalformedValue {
-            message: "no value".into(),
-        })
-    })?;
-    if splits.next().is_some() {
-        Ok(try_to_str(value)?)
-    } else {
-        Err(Error::new_without_key(ErrorKind::MalformedValue {
-            message: "expected null terminator".into(),
-        }))
-    }
-}
-
-fn read_lenencoded(buf: &[u8]) -> Result<&str> {
+fn read_len(buf: &[u8]) -> Result<usize> {
     if buf.len() < 4 {
         return Err(Error::new_without_key(ErrorKind::MalformedValue {
             message: format!(
@@ -250,7 +234,13 @@ fn read_lenencoded(buf: &[u8]) -> Result<&str> {
         }));
     }
 
-    // exclude null byte
+    Ok(length as usize + 4)
+}
+
+fn read_lenencode(buf: &[u8]) -> Result<&str> {
+    let end = read_len(buf)?;
+
+    // exclude length-prefix and null byte suffix
     try_to_str(&buf[4..(end - 1)])
 }
 

From 7e114303aeb0b9622615c31e378c774ae86123cb Mon Sep 17 00:00:00 2001
From: Asger Hautop Drewsen <asger@tyilo.com>
Date: Thu, 18 Jan 2024 17:10:19 +0100
Subject: [PATCH 048/156] Allow using the {,raw}{bson,doc} with types
 implementing Into<{,Raw}Bson> (#450)

---
 src/macros.rs               |  4 ++--
 src/tests/modules/macros.rs | 31 +++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/macros.rs b/src/macros.rs
index 875ce839..3a0cb77b 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -181,7 +181,7 @@ macro_rules! bson {
     // Any Into<Bson> type.
     // Must be below every other rule.
     ($other:expr) => {
-        $crate::Bson::from($other)
+        <_ as ::std::convert::Into<$crate::Bson>>::into($other)
     };
 }
 
@@ -392,7 +392,7 @@ macro_rules! rawbson {
     // Any Into<RawBson> type.
     // Must be below every other rule.
     ($other:expr) => {
-        $crate::RawBson::from($other)
+        <_ as ::std::convert::Into<$crate::RawBson>>::into($other)
     };
 }
 
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
index 689c8a1a..7e94a726 100644
--- a/src/tests/modules/macros.rs
+++ b/src/tests/modules/macros.rs
@@ -242,3 +242,34 @@ fn recursive_macro() {
 
     assert_eq!(rawdoc.into_bytes(), crate::to_vec(&doc).unwrap());
 }
+
+#[test]
+#[allow(clippy::from_over_into)]
+fn can_use_macro_with_into_bson() {
+    struct Custom;
+
+    impl Into<Bson> for Custom {
+        fn into(self) -> Bson {
+            "foo".into()
+        }
+    }
+
+    impl Into<RawBson> for Custom {
+        fn into(self) -> RawBson {
+            "foo".into()
+        }
+    }
+
+    _ = bson!({
+        "a": Custom,
+    });
+    _ = doc! {
+        "a": Custom,
+    };
+    _ = rawbson!({
+        "a": Custom,
+    });
+    _ = rawdoc! {
+        "a": Custom,
+    };
+}

From 622007da1d84325e71bc3b4dab919af182875c50 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 18 Jan 2024 13:18:24 -0500
Subject: [PATCH 049/156] minor: update clippy to 1.75 (#451)

---
 .evergreen/check-clippy.sh  |  2 +-
 src/tests/modules/bson.rs   | 11 +++++++----
 src/tests/modules/macros.rs |  6 +++---
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index 99b02c10..9a809142 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.71.0
+CLIPPY_VERSION=1.75.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 67b8f4db..8bb66f8b 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -179,10 +179,13 @@ fn from_impls() {
 
     // References
     assert_eq!(Bson::from(&24i32), Bson::Int32(24));
-    assert_eq!(
-        Bson::try_from(&String::from("data")).unwrap(),
-        Bson::String(String::from("data"))
-    );
+    #[allow(clippy::unnecessary_fallible_conversions)]
+    {
+        assert_eq!(
+            Bson::try_from(&String::from("data")).unwrap(),
+            Bson::String(String::from("data"))
+        );
+    }
     assert_eq!(Bson::from(&oid), Bson::ObjectId(oid));
     assert_eq!(
         Bson::from(&doc! {"a": "b"}),
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
index 7e94a726..150e22d2 100644
--- a/src/tests/modules/macros.rs
+++ b/src/tests/modules/macros.rs
@@ -159,7 +159,7 @@ fn recursive_macro() {
                             assert_eq!(2, arr.len());
 
                             // Match array items
-                            match arr.get(0) {
+                            match arr.first() {
                                 Some(Bson::String(ref s)) => assert_eq!("seal", s),
                                 _ => panic!(
                                     "String 'seal' was not inserted into inner array correctly."
@@ -193,7 +193,7 @@ fn recursive_macro() {
             assert_eq!(1, arr.len());
 
             // Integer type
-            match arr.get(0) {
+            match arr.first() {
                 Some(Bson::Int32(ref i)) => assert_eq!(-7, *i),
                 _ => panic!("I32 '-7' was not inserted correctly."),
             }
@@ -207,7 +207,7 @@ fn recursive_macro() {
             assert_eq!(1, arr.len());
 
             // Nested document
-            match arr.get(0) {
+            match arr.first() {
                 Some(Bson::Document(ref doc)) => {
                     // String
                     match doc.get("apple") {

From 8247d271b2570c3e1d4a9ab13374d94a6e50ed6e Mon Sep 17 00:00:00 2001
From: Asger Hautop Drewsen <asger@tyilo.com>
Date: Fri, 19 Jan 2024 17:42:57 +0100
Subject: [PATCH 050/156] Implement From<&mut T> for Bson (#452)

---
 src/bson.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/bson.rs b/src/bson.rs
index 07a424a3..3a455f4e 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -237,6 +237,15 @@ where
     }
 }
 
+impl<T> From<&mut T> for Bson
+where
+    for<'a> &'a T: Into<Bson>,
+{
+    fn from(t: &mut T) -> Bson {
+        (&*t).into()
+    }
+}
+
 impl<T> From<Vec<T>> for Bson
 where
     T: Into<Bson>,

From 81a98950899f96b138699e008e4d1703ed0f8fb5 Mon Sep 17 00:00:00 2001
From: Jonas Bushart <jonas@bushart.org>
Date: Mon, 22 Jan 2024 17:44:15 +0100
Subject: [PATCH 051/156] Fix feature name for serde_with Uuid implementation
 (#453)

---
 src/uuid/mod.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs
index 7e5fc44f..cfb7120e 100644
--- a/src/uuid/mod.rs
+++ b/src/uuid/mod.rs
@@ -522,8 +522,8 @@ macro_rules! trait_impls {
             }
         }
 
-        #[cfg(all($feat, feature = "serde_with_3"))]
-        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with_3"))))]
+        #[cfg(all($feat, feature = "serde_with-3"))]
+        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))]
         impl serde_with_3::SerializeAs<$u> for crate::Uuid {
             fn serialize_as<S>(source: &$u, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where

From 230dab13f5d57ae81be81a77a2c7ac7cc703c78a Mon Sep 17 00:00:00 2001
From: Kyle Kloberdanz <kyle.kloberdanz@mongodb.com>
Date: Tue, 23 Jan 2024 15:32:48 -0600
Subject: [PATCH 052/156] RUST-1716 Add BSON Binary Data subtype Sensitive
 (#454)

- Sync BSON corpus test
- Implement and test BinarySubtype::Sensitive which maps to 0x08
---
 src/spec.rs                                 | 4 ++++
 src/tests/binary_subtype.rs                 | 1 +
 src/tests/spec/json/bson-corpus/binary.json | 5 +++++
 3 files changed, 10 insertions(+)

diff --git a/src/spec.rs b/src/spec.rs
index 1d2d6853..04ec7708 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -54,6 +54,7 @@ const BINARY_SUBTYPE_UUID: u8 = 0x04;
 const BINARY_SUBTYPE_MD5: u8 = 0x05;
 const BINARY_SUBTYPE_ENCRYPTED: u8 = 0x06;
 const BINARY_SUBTYPE_COLUMN: u8 = 0x07;
+const BINARY_SUBTYPE_SENSITIVE: u8 = 0x08;
 const BINARY_SUBTYPE_USER_DEFINED: u8 = 0x80;
 
 /// All available BSON element types.
@@ -153,6 +154,7 @@ pub enum BinarySubtype {
     Md5,
     Encrypted,
     Column,
+    Sensitive,
     UserDefined(u8),
     Reserved(u8),
 }
@@ -169,6 +171,7 @@ impl From<BinarySubtype> for u8 {
             BinarySubtype::Md5 => BINARY_SUBTYPE_MD5,
             BinarySubtype::Encrypted => BINARY_SUBTYPE_ENCRYPTED,
             BinarySubtype::Column => BINARY_SUBTYPE_COLUMN,
+            BinarySubtype::Sensitive => BINARY_SUBTYPE_SENSITIVE,
             BinarySubtype::UserDefined(x) => x,
             BinarySubtype::Reserved(x) => x,
         }
@@ -187,6 +190,7 @@ impl From<u8> for BinarySubtype {
             BINARY_SUBTYPE_MD5 => BinarySubtype::Md5,
             BINARY_SUBTYPE_ENCRYPTED => BinarySubtype::Encrypted,
             BINARY_SUBTYPE_COLUMN => BinarySubtype::Column,
+            BINARY_SUBTYPE_SENSITIVE => BinarySubtype::Sensitive,
             _ if t < BINARY_SUBTYPE_USER_DEFINED => BinarySubtype::Reserved(t),
             _ => BinarySubtype::UserDefined(t),
         }
diff --git a/src/tests/binary_subtype.rs b/src/tests/binary_subtype.rs
index cd96cc95..71f2d714 100644
--- a/src/tests/binary_subtype.rs
+++ b/src/tests/binary_subtype.rs
@@ -7,6 +7,7 @@ fn from_u8() {
     assert_eq!(BinarySubtype::from(0x00), BinarySubtype::Generic);
     assert_eq!(BinarySubtype::from(0x06), BinarySubtype::Encrypted);
     assert_eq!(BinarySubtype::from(0x07), BinarySubtype::Column);
+    assert_eq!(BinarySubtype::from(0x08), BinarySubtype::Sensitive);
     assert_eq!(BinarySubtype::from(0x7F), BinarySubtype::Reserved(0x7F));
     assert_eq!(BinarySubtype::from(0x80), BinarySubtype::UserDefined(0x80));
     assert_eq!(BinarySubtype::from(0xFF), BinarySubtype::UserDefined(0xFF));
diff --git a/src/tests/spec/json/bson-corpus/binary.json b/src/tests/spec/json/bson-corpus/binary.json
index beb2e07a..20aaef74 100644
--- a/src/tests/spec/json/bson-corpus/binary.json
+++ b/src/tests/spec/json/bson-corpus/binary.json
@@ -55,6 +55,11 @@
             "canonical_bson": "1D000000057800100000000773FFD26444B34C6990E8E7D1DFC035D400",
             "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"07\"}}}"
         },
+        {
+            "description": "subtype 0x08",
+            "canonical_bson": "1D000000057800100000000873FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"08\"}}}"
+        },
         {
             "description": "subtype 0x80",
             "canonical_bson": "0F0000000578000200000080FFFF00",

From 72035bc6e03ee22bd3c414768b406bb5eaf4a5f2 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 25 Jan 2024 15:24:41 -0500
Subject: [PATCH 053/156] release v2.9.0 (#455) (#456)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 21d66256..fb724f6f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.8.0"
+version = "2.9.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index b0aaaf95..e5843591 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.8.0"
+bson = "2.9.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 1f5dda48..480caff6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.8.0"
+//! bson = "2.9.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From 1f688231fbe74120f6958d8eb2449e46088acd06 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 15 Feb 2024 15:37:03 -0500
Subject: [PATCH 054/156] RUST-1837 Avoid logging secrets when publishing
 (#458)

---
 .evergreen/release-danger-do-not-run-manually.sh | 6 +++---
 .evergreen/releases.yml                          | 3 ++-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/.evergreen/release-danger-do-not-run-manually.sh b/.evergreen/release-danger-do-not-run-manually.sh
index ca40a9f8..9e443d68 100644
--- a/.evergreen/release-danger-do-not-run-manually.sh
+++ b/.evergreen/release-danger-do-not-run-manually.sh
@@ -16,8 +16,8 @@ if [[ -z "$TAG" ]]; then
 	exit 1
 fi
 
-if [[ -z "$TOKEN" ]]; then
-	>&2 echo "\$TOKEN must be set to the crates.io authentication token"
+if [[ -z "$CRATES_IO_TOKEN" ]]; then
+	>&2 echo "\$CRATES_IO_TOKEN must be set to the crates.io authentication token"
 	exit 1
 fi
 
@@ -26,4 +26,4 @@ git checkout $TAG
 
 . ~/.cargo/env
 
-cargo publish --token $TOKEN
+cargo publish --token $CRATES_IO_TOKEN
diff --git a/.evergreen/releases.yml b/.evergreen/releases.yml
index 4579d330..7381a2fe 100644
--- a/.evergreen/releases.yml
+++ b/.evergreen/releases.yml
@@ -20,11 +20,12 @@ functions:
       type: test
       params:
         working_dir: "src"
+        include_expansions_in_env:
+          - CRATES_IO_TOKEN
         script: |
           set +x
 
           TAG=${GIT_TAG}           \
-          TOKEN=${CRATES_IO_TOKEN} \
             bash .evergreen/release-danger-do-not-run-manually.sh
 
 tasks:

From 32f3dc30e9c01cdf38d2626f6ce9688b0b8961df Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 21 Feb 2024 15:10:23 -0500
Subject: [PATCH 055/156] RUST-1850 Fix a fuzzer failure (#460)

---
 src/de/raw.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/de/raw.rs b/src/de/raw.rs
index 874d025e..e338bf7d 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -1316,14 +1316,14 @@ impl<'de, 'a> CodeWithScopeDeserializer<'de, 'a> {
         F: FnOnce(&mut Self) -> Result<O>,
     {
         let start_bytes = self.root_deserializer.bytes.bytes_read();
-        let out = f(self);
+        let out = f(self)?;
         let bytes_read = self.root_deserializer.bytes.bytes_read() - start_bytes;
         self.length_remaining -= bytes_read as i32;
 
         if self.length_remaining < 0 {
             return Err(Error::custom("length of CodeWithScope too short"));
         }
-        out
+        Ok(out)
     }
 }
 

From c89e1377582aee903b826fbec00ef62b58447781 Mon Sep 17 00:00:00 2001
From: Sam Kleinman <garen@tychoish.com>
Date: Fri, 1 Mar 2024 18:07:11 -0500
Subject: [PATCH 056/156] fix: access iterators from RawDocument without
 needing to convert to RawDocumentBuf (#462)

---
 src/raw/document.rs     | 22 +++++++++++++++++++++-
 src/raw/document_buf.rs | 10 +++++-----
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/src/raw/document.rs b/src/raw/document.rs
index 51ca6530..7132db92 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -181,6 +181,26 @@ impl RawDocument {
         Ok(None)
     }
 
+    /// Gets an iterator over the elements in the [`RawDocument`] that yields
+    /// `Result<(&str, RawBson<'_>)>`.
+    pub fn iter(&self) -> Iter<'_> {
+        Iter::new(self)
+    }
+
+    /// Gets an iterator over the elements in the [`RawDocument`],
+    /// which yields `Result<RawElement<'_>>` values. These hold a
+    /// reference to the underlying document but do not explicitly
+    /// resolve the values.
+    ///
+    /// This iterator, which underpins the implementation of the
+    /// default iterator, produces `RawElement` objects that hold a
+    /// view onto the document but do not parse out or construct
+    /// values until the `.value()` or `.try_into()` methods are
+    /// called.
+    pub fn iter_elements(&self) -> RawIter<'_> {
+        RawIter::new(self)
+    }
+
     fn get_with<'a, T>(
         &'a self,
         key: impl AsRef<str>,
@@ -599,6 +619,6 @@ impl<'a> IntoIterator for &'a RawDocument {
     type Item = Result<(&'a str, RawBsonRef<'a>)>;
 
     fn into_iter(self) -> Iter<'a> {
-        Iter::new(self)
+        self.iter()
     }
 }
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 525ebc44..23981064 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -157,10 +157,10 @@ impl RawDocumentBuf {
     /// resolve the values.
     ///
     /// This iterator, which underpins the implementation of the
-    /// default iterator, produces `RawElement` objects, which
-    /// hold a view onto the document but do not parse out or
-    /// construct values until the `.value()` or `.try_into()` methods
-    /// are called.
+    /// default iterator, produces `RawElement` objects that hold a
+    /// view onto the document but do not parse out or construct
+    /// values until the `.value()` or `.try_into()` methods are
+    /// called.
     ///
     /// # Note:
     ///
@@ -394,7 +394,7 @@ impl<'a> IntoIterator for &'a RawDocumentBuf {
     type Item = Result<(&'a str, RawBsonRef<'a>)>;
 
     fn into_iter(self) -> Iter<'a> {
-        Iter::new(self)
+        self.iter()
     }
 }
 

From 5890071b554e3e7fad54c1d113a58b81f8034ff8 Mon Sep 17 00:00:00 2001
From: Sam Kleinman <garen@tychoish.com>
Date: Mon, 4 Mar 2024 10:34:19 -0500
Subject: [PATCH 057/156] fix: export RawElement type (#461)

---
 src/raw/iter.rs | 1 +
 src/raw/mod.rs  | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 1208b7ee..9180df7a 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -144,6 +144,7 @@ impl<'a> TryInto<Bson> for RawElement<'a> {
     }
 }
 
+#[allow(clippy::len_without_is_empty)]
 impl<'a> RawElement<'a> {
     pub fn len(&self) -> usize {
         self.size
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index 56c6e130..8a503634 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -142,7 +142,7 @@ pub use self::{
     document::RawDocument,
     document_buf::RawDocumentBuf,
     error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
-    iter::RawIter,
+    iter::{RawElement, RawIter},
 };
 
 /// Special newtype name indicating that the type being (de)serialized is a raw BSON document.

From 546fbeafcf0f9577976e177f2c75de97eee595f2 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 18 Mar 2024 16:09:26 -0400
Subject: [PATCH 058/156] RUST-1512 Provide a method to append a borrowed value
 (#463)

---
 src/raw/array_buf.rs    |  4 --
 src/raw/document_buf.rs | 89 ++++++++++++++++++++---------------------
 2 files changed, 44 insertions(+), 49 deletions(-)

diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index fa696783..96797996 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -96,10 +96,6 @@ impl RawArrayBuf {
         self.inner.append(self.len.to_string(), value);
         self.len += 1;
     }
-
-    pub(crate) fn into_vec(self) -> Vec<u8> {
-        self.inner.into_bytes()
-    }
 }
 
 impl Debug for RawArrayBuf {
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 23981064..63e4f4bf 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -7,13 +7,7 @@ use std::{
 
 use serde::{Deserialize, Serialize};
 
-use crate::{
-    de::MIN_BSON_DOCUMENT_SIZE,
-    spec::BinarySubtype,
-    Document,
-    RawBinaryRef,
-    RawJavaScriptCodeWithScopeRef,
-};
+use crate::{de::MIN_BSON_DOCUMENT_SIZE, spec::BinarySubtype, Document};
 
 use super::{
     bson::RawBson,
@@ -215,6 +209,18 @@ impl RawDocumentBuf {
     /// # Ok::<(), Error>(())
     /// ```
     pub fn append(&mut self, key: impl AsRef<str>, value: impl Into<RawBson>) {
+        let value = value.into();
+        self.append_ref(key, value.as_raw_bson_ref())
+    }
+
+    /// 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.
+    pub fn append_ref<'a>(&mut self, key: impl AsRef<str>, value: impl Into<RawBsonRef<'a>>) {
         fn append_string(doc: &mut RawDocumentBuf, value: &str) {
             doc.data
                 .extend(((value.as_bytes().len() + 1) as i32).to_le_bytes());
@@ -240,24 +246,20 @@ impl RawDocumentBuf {
         let element_type = value.element_type();
 
         match value {
-            RawBson::Int32(i) => {
+            RawBsonRef::Int32(i) => {
                 self.data.extend(i.to_le_bytes());
             }
-            RawBson::String(s) => {
-                append_string(self, s.as_str());
+            RawBsonRef::String(s) => {
+                append_string(self, s);
             }
-            RawBson::Document(d) => {
-                self.data.extend(d.into_bytes());
+            RawBsonRef::Document(d) => {
+                self.data.extend(d.as_bytes());
             }
-            RawBson::Array(a) => {
-                self.data.extend(a.into_vec());
+            RawBsonRef::Array(a) => {
+                self.data.extend(a.as_bytes());
             }
-            RawBson::Binary(b) => {
-                let len = RawBinaryRef {
-                    bytes: b.bytes.as_slice(),
-                    subtype: b.subtype,
-                }
-                .len();
+            RawBsonRef::Binary(b) => {
+                let len = b.len();
                 self.data.extend(len.to_le_bytes());
                 self.data.push(b.subtype.into());
                 if let BinarySubtype::BinaryOld = b.subtype {
@@ -265,53 +267,50 @@ impl RawDocumentBuf {
                 }
                 self.data.extend(b.bytes);
             }
-            RawBson::Boolean(b) => {
+            RawBsonRef::Boolean(b) => {
                 self.data.push(b as u8);
             }
-            RawBson::DateTime(dt) => {
+            RawBsonRef::DateTime(dt) => {
                 self.data.extend(dt.timestamp_millis().to_le_bytes());
             }
-            RawBson::DbPointer(dbp) => {
-                append_string(self, dbp.namespace.as_str());
+            RawBsonRef::DbPointer(dbp) => {
+                append_string(self, dbp.namespace);
                 self.data.extend(dbp.id.bytes());
             }
-            RawBson::Decimal128(d) => {
+            RawBsonRef::Decimal128(d) => {
                 self.data.extend(d.bytes());
             }
-            RawBson::Double(d) => {
+            RawBsonRef::Double(d) => {
                 self.data.extend(d.to_le_bytes());
             }
-            RawBson::Int64(i) => {
+            RawBsonRef::Int64(i) => {
                 self.data.extend(i.to_le_bytes());
             }
-            RawBson::RegularExpression(re) => {
-                append_cstring(self, re.pattern.as_str());
-                append_cstring(self, re.options.as_str());
+            RawBsonRef::RegularExpression(re) => {
+                append_cstring(self, re.pattern);
+                append_cstring(self, re.options);
             }
-            RawBson::JavaScriptCode(js) => {
-                append_string(self, js.as_str());
+            RawBsonRef::JavaScriptCode(js) => {
+                append_string(self, js);
             }
-            RawBson::JavaScriptCodeWithScope(code_w_scope) => {
-                let len = RawJavaScriptCodeWithScopeRef {
-                    code: code_w_scope.code.as_str(),
-                    scope: &code_w_scope.scope,
-                }
-                .len();
+            RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => {
+                let len = code_w_scope.len();
                 self.data.extend(len.to_le_bytes());
-                append_string(self, code_w_scope.code.as_str());
-                self.data.extend(code_w_scope.scope.into_bytes());
+                append_string(self, code_w_scope.code);
+                self.data.extend(code_w_scope.scope.as_bytes());
             }
-            RawBson::Timestamp(ts) => {
+            RawBsonRef::Timestamp(ts) => {
                 self.data.extend(ts.to_le_i64().to_le_bytes());
             }
-            RawBson::ObjectId(oid) => {
+            RawBsonRef::ObjectId(oid) => {
                 self.data.extend(oid.bytes());
             }
-            RawBson::Symbol(s) => {
-                append_string(self, s.as_str());
+            RawBsonRef::Symbol(s) => {
+                append_string(self, s);
             }
-            RawBson::Null | RawBson::Undefined | RawBson::MinKey | RawBson::MaxKey => {}
+            RawBsonRef::Null | RawBsonRef::Undefined | RawBsonRef::MinKey | RawBsonRef::MaxKey => {}
         }
+
         // update element type
         self.data[original_len - 1] = element_type as u8;
         // append trailing null byte

From 3fc1879eeacac1a35dfa4f3e76a1e5895a28103e Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 26 Mar 2024 12:59:58 -0400
Subject: [PATCH 059/156] RUST-1892 Fix timestamp [de]serialization on
 big-endian machines (#465)

---
 src/bson.rs             |  24 +++--
 src/de/mod.rs           | 231 ++--------------------------------------
 src/document.rs         |  54 +++-------
 src/extjson/models.rs   |   2 +-
 src/raw/document_buf.rs |   2 +-
 src/ser/mod.rs          |  82 +-------------
 6 files changed, 38 insertions(+), 357 deletions(-)

diff --git a/src/bson.rs b/src/bson.rs
index 3a455f4e..6c8c905e 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -1029,19 +1029,21 @@ impl Display for Timestamp {
 }
 
 impl Timestamp {
-    pub(crate) fn to_le_i64(self) -> i64 {
-        let upper = (self.time.to_le() as u64) << 32;
-        let lower = self.increment.to_le() as u64;
-
-        (upper | lower) as i64
+    pub(crate) fn to_le_bytes(self) -> [u8; 8] {
+        let mut out = [0; 8];
+        out[0..4].copy_from_slice(&self.increment.to_le_bytes());
+        out[4..8].copy_from_slice(&self.time.to_le_bytes());
+        out
     }
 
-    pub(crate) fn from_le_i64(val: i64) -> Self {
-        let ts = val.to_le();
-
-        Timestamp {
-            time: ((ts as u64) >> 32) as u32,
-            increment: (ts & 0xFFFF_FFFF) as u32,
+    pub(crate) fn from_le_bytes(bytes: [u8; 8]) -> Self {
+        let mut inc_bytes = [0; 4];
+        inc_bytes.copy_from_slice(&bytes[0..4]);
+        let mut time_bytes = [0; 4];
+        time_bytes.copy_from_slice(&bytes[4..8]);
+        Self {
+            increment: u32::from_le_bytes(inc_bytes),
+            time: u32::from_le_bytes(time_bytes),
         }
     }
 }
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 909b71cd..eeaf6beb 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -33,12 +33,11 @@ pub use self::{
 use std::io::Read;
 
 use crate::{
-    bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
-    oid::{self, ObjectId},
+    bson::{Bson, Document, Timestamp},
+    oid::ObjectId,
     raw::RawBinaryRef,
     ser::write_i32,
-    spec::{self, BinarySubtype},
-    Binary,
+    spec::BinarySubtype,
     Decimal128,
 };
 
@@ -49,7 +48,6 @@ use ::serde::{
 
 pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor};
 
-#[cfg(test)]
 pub(crate) use self::raw::Deserializer as RawDeserializer;
 
 pub(crate) const MAX_BSON_SIZE: i32 = 16 * 1024 * 1024;
@@ -73,30 +71,6 @@ enum DeserializerHint {
     RawBson,
 }
 
-/// Run the provided closure, ensuring that over the course of its execution, exactly `length` bytes
-/// were read from the reader.
-pub(crate) fn ensure_read_exactly<F, R>(
-    reader: &mut R,
-    length: usize,
-    error_message: &str,
-    func: F,
-) -> Result<()>
-where
-    F: FnOnce(&mut std::io::Cursor<Vec<u8>>) -> Result<()>,
-    R: Read + ?Sized,
-{
-    let mut buf = vec![0u8; length];
-    reader.read_exact(&mut buf)?;
-    let mut cursor = std::io::Cursor::new(buf);
-
-    func(&mut cursor)?;
-
-    if cursor.position() != length as u64 {
-        return Err(Error::invalid_length(length, &error_message));
-    }
-    Ok(())
-}
-
 pub(crate) fn read_string<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> Result<String> {
     let len = read_i32(reader)?;
 
@@ -141,20 +115,6 @@ pub(crate) fn read_bool<R: Read>(mut reader: R) -> Result<bool> {
     Ok(val != 0)
 }
 
-fn read_cstring<R: Read + ?Sized>(reader: &mut R) -> Result<String> {
-    let mut v = Vec::new();
-
-    loop {
-        let c = read_u8(reader)?;
-        if c == 0 {
-            break;
-        }
-        v.push(c);
-    }
-
-    Ok(String::from_utf8(v)?)
-}
-
 #[inline]
 pub(crate) fn read_u8<R: Read + ?Sized>(reader: &mut R) -> Result<u8> {
     let mut buf = [0; 1];
@@ -192,138 +152,6 @@ fn read_f128<R: Read + ?Sized>(reader: &mut R) -> Result<Decimal128> {
     Ok(Decimal128 { bytes: buf })
 }
 
-fn deserialize_array<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> Result<Array> {
-    let mut arr = Array::new();
-    let length = read_i32(reader)?;
-
-    if !(MIN_BSON_DOCUMENT_SIZE..=MAX_BSON_SIZE).contains(&length) {
-        return Err(Error::invalid_length(
-            length as usize,
-            &format!(
-                "array length must be between {} and {}",
-                MIN_BSON_DOCUMENT_SIZE, MAX_BSON_SIZE
-            )
-            .as_str(),
-        ));
-    }
-
-    ensure_read_exactly(
-        reader,
-        (length as usize) - 4,
-        "array length longer than contents",
-        |cursor| {
-            loop {
-                let tag = read_u8(cursor)?;
-                if tag == 0 {
-                    break;
-                }
-
-                let (_, val) = deserialize_bson_kvp(cursor, tag, utf8_lossy)?;
-                arr.push(val)
-            }
-            Ok(())
-        },
-    )?;
-
-    Ok(arr)
-}
-
-pub(crate) fn deserialize_bson_kvp<R: Read + ?Sized>(
-    reader: &mut R,
-    tag: u8,
-    utf8_lossy: bool,
-) -> Result<(String, Bson)> {
-    use spec::ElementType;
-    let key = read_cstring(reader)?;
-
-    let val = match ElementType::from(tag) {
-        Some(ElementType::Double) => Bson::Double(read_f64(reader)?),
-        Some(ElementType::String) => read_string(reader, utf8_lossy).map(Bson::String)?,
-        Some(ElementType::EmbeddedDocument) => Document::from_reader(reader).map(Bson::Document)?,
-        Some(ElementType::Array) => deserialize_array(reader, utf8_lossy).map(Bson::Array)?,
-        Some(ElementType::Binary) => Bson::Binary(Binary::from_reader(reader)?),
-        Some(ElementType::ObjectId) => {
-            let mut objid = [0; 12];
-            for x in &mut objid {
-                *x = read_u8(reader)?;
-            }
-            Bson::ObjectId(oid::ObjectId::from_bytes(objid))
-        }
-        Some(ElementType::Boolean) => Bson::Boolean(read_bool(reader)?),
-        Some(ElementType::Null) => Bson::Null,
-        Some(ElementType::RegularExpression) => {
-            Bson::RegularExpression(Regex::from_reader(reader)?)
-        }
-        Some(ElementType::JavaScriptCode) => {
-            read_string(reader, utf8_lossy).map(Bson::JavaScriptCode)?
-        }
-        Some(ElementType::JavaScriptCodeWithScope) => {
-            Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope::from_reader(reader, utf8_lossy)?)
-        }
-        Some(ElementType::Int32) => read_i32(reader).map(Bson::Int32)?,
-        Some(ElementType::Int64) => read_i64(reader).map(Bson::Int64)?,
-        Some(ElementType::Timestamp) => Bson::Timestamp(Timestamp::from_reader(reader)?),
-        Some(ElementType::DateTime) => {
-            // The int64 is UTC milliseconds since the Unix epoch.
-            let time = read_i64(reader)?;
-            Bson::DateTime(crate::DateTime::from_millis(time))
-        }
-        Some(ElementType::Symbol) => read_string(reader, utf8_lossy).map(Bson::Symbol)?,
-        Some(ElementType::Decimal128) => read_f128(reader).map(Bson::Decimal128)?,
-        Some(ElementType::Undefined) => Bson::Undefined,
-        Some(ElementType::DbPointer) => Bson::DbPointer(DbPointer::from_reader(reader)?),
-        Some(ElementType::MaxKey) => Bson::MaxKey,
-        Some(ElementType::MinKey) => Bson::MinKey,
-        None => {
-            return Err(Error::UnrecognizedDocumentElementType {
-                key,
-                element_type: tag,
-            })
-        }
-    };
-
-    Ok((key, val))
-}
-
-impl Binary {
-    pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
-        let mut len = read_i32(&mut reader)?;
-        if !(0..=MAX_BSON_SIZE).contains(&len) {
-            return Err(Error::invalid_length(
-                len as usize,
-                &format!("binary length must be between 0 and {}", MAX_BSON_SIZE).as_str(),
-            ));
-        }
-        let subtype = BinarySubtype::from(read_u8(&mut reader)?);
-
-        // Skip length data in old binary.
-        if let BinarySubtype::BinaryOld = subtype {
-            let data_len = read_i32(&mut reader)?;
-
-            if !(0..=(MAX_BSON_SIZE - 4)).contains(&data_len) {
-                return Err(Error::invalid_length(
-                    data_len as usize,
-                    &format!("0x02 length must be between 0 and {}", MAX_BSON_SIZE - 4).as_str(),
-                ));
-            }
-
-            if data_len + 4 != len {
-                return Err(Error::invalid_length(
-                    data_len as usize,
-                    &"0x02 length did not match top level binary length",
-                ));
-            }
-
-            len -= 4;
-        }
-
-        let mut bytes = Vec::with_capacity(len as usize);
-
-        reader.take(len as u64).read_to_end(&mut bytes)?;
-        Ok(Binary { subtype, bytes })
-    }
-}
-
 impl<'a> RawBinaryRef<'a> {
     pub(crate) fn from_slice_with_len_and_payload(
         mut bytes: &'a [u8],
@@ -368,29 +196,11 @@ impl<'a> RawBinaryRef<'a> {
     }
 }
 
-impl DbPointer {
-    pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
-        let ns = read_string(&mut reader, false)?;
-        let oid = ObjectId::from_reader(&mut reader)?;
-        Ok(DbPointer {
-            namespace: ns,
-            id: oid,
-        })
-    }
-}
-
-impl Regex {
-    pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
-        let pattern = read_cstring(&mut reader)?;
-        let options = read_cstring(&mut reader)?;
-
-        Ok(Regex { pattern, options })
-    }
-}
-
 impl Timestamp {
     pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
-        read_i64(&mut reader).map(Timestamp::from_le_i64)
+        let mut bytes = [0; 8];
+        reader.read_exact(&mut bytes)?;
+        Ok(Timestamp::from_le_bytes(bytes))
     }
 }
 
@@ -402,35 +212,6 @@ impl ObjectId {
     }
 }
 
-impl JavaScriptCodeWithScope {
-    pub(crate) fn from_reader<R: Read>(mut reader: R, utf8_lossy: bool) -> Result<Self> {
-        let length = read_i32(&mut reader)?;
-        if length < MIN_CODE_WITH_SCOPE_SIZE {
-            return Err(Error::invalid_length(
-                length as usize,
-                &format!(
-                    "code with scope length must be at least {}",
-                    MIN_CODE_WITH_SCOPE_SIZE
-                )
-                .as_str(),
-            ));
-        } else if length > MAX_BSON_SIZE {
-            return Err(Error::invalid_length(
-                length as usize,
-                &"code with scope length too large",
-            ));
-        }
-
-        let mut buf = vec![0u8; (length - 4) as usize];
-        reader.read_exact(&mut buf)?;
-
-        let mut slice = buf.as_slice();
-        let code = read_string(&mut slice, utf8_lossy)?;
-        let scope = Document::from_reader(&mut slice)?;
-        Ok(JavaScriptCodeWithScope { code, scope })
-    }
-}
-
 /// Deserialize a `T` from the provided [`Bson`] value.
 ///
 /// The [`Deserializer`] used by this function presents itself as human readable, whereas the
diff --git a/src/document.rs b/src/document.rs
index 9b0e982b..f11643d9 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -1,22 +1,21 @@
 //! A BSON document represented as an associative HashMap with insertion ordering.
 
 use std::{
+    convert::TryInto,
     error,
     fmt::{self, Debug, Display, Formatter},
     io::{Read, Write},
     iter::{Extend, FromIterator, IntoIterator},
-    mem,
 };
 
 use ahash::RandomState;
 use indexmap::IndexMap;
-use serde::de::Error;
+use serde::{de::Error, Deserialize};
 
 use crate::{
     bson::{Array, Bson, Timestamp},
-    de::{deserialize_bson_kvp, ensure_read_exactly, read_i32, MIN_BSON_DOCUMENT_SIZE},
+    de::{read_i32, MIN_BSON_DOCUMENT_SIZE},
     oid::ObjectId,
-    ser::{serialize_bson, write_i32},
     spec::BinarySubtype,
     Binary,
     Decimal128,
@@ -543,23 +542,12 @@ impl Document {
     /// # }
     /// ```
     pub fn to_writer<W: Write>(&self, mut writer: W) -> crate::ser::Result<()> {
-        let mut buf = Vec::new();
-        for (key, val) in self.into_iter() {
-            serialize_bson(&mut buf, key.as_ref(), val)?;
-        }
-
-        write_i32(
-            &mut writer,
-            (buf.len() + mem::size_of::<i32>() + mem::size_of::<u8>()) as i32,
-        )?;
+        let buf = crate::to_vec(self)?;
         writer.write_all(&buf)?;
-        writer.write_all(&[0])?;
         Ok(())
     }
 
     fn decode<R: Read + ?Sized>(reader: &mut R, utf_lossy: bool) -> crate::de::Result<Document> {
-        let mut doc = Document::new();
-
         let length = read_i32(reader)?;
         if length < MIN_BSON_DOCUMENT_SIZE {
             return Err(crate::de::Error::invalid_length(
@@ -567,29 +555,17 @@ impl Document {
                 &"document length must be at least 5",
             ));
         }
-
-        ensure_read_exactly(
-            reader,
-            (length as usize) - 4,
-            "document length longer than contents",
-            |cursor| {
-                loop {
-                    let mut tag_byte = [0];
-                    cursor.read_exact(&mut tag_byte)?;
-                    let tag = tag_byte[0];
-
-                    if tag == 0 {
-                        break;
-                    }
-
-                    let (key, val) = deserialize_bson_kvp(cursor, tag, utf_lossy)?;
-                    doc.insert(key, val);
-                }
-                Ok(())
-            },
-        )?;
-
-        Ok(doc)
+        let ulen: usize =
+            length
+                .try_into()
+                .map_err(|e| crate::de::Error::DeserializationError {
+                    message: format!("invalid document length: {}", e),
+                })?;
+        let mut buf = vec![0u8; ulen];
+        buf[0..4].copy_from_slice(&length.to_le_bytes());
+        reader.read_exact(&mut buf[4..])?;
+        let mut deserializer = crate::de::RawDeserializer::new(&buf, utf_lossy);
+        Document::deserialize(&mut deserializer)
     }
 
     /// Attempts to deserialize a [`Document`] from a byte stream.
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index efb57fff..0bae6249 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -225,7 +225,7 @@ pub(crate) struct Timestamp {
     body: TimestampBody,
 }
 
-#[derive(Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Debug)]
 #[serde(deny_unknown_fields)]
 pub(crate) struct TimestampBody {
     #[serde(serialize_with = "crate::serde_helpers::serialize_u32_as_i64")]
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 63e4f4bf..6a508a35 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -300,7 +300,7 @@ impl RawDocumentBuf {
                 self.data.extend(code_w_scope.scope.as_bytes());
             }
             RawBsonRef::Timestamp(ts) => {
-                self.data.extend(ts.to_le_i64().to_le_bytes());
+                self.data.extend(ts.to_le_bytes());
             }
             RawBsonRef::ObjectId(oid) => {
                 self.data.extend(oid.bytes());
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index a15065e8..6adf87ec 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -30,13 +30,12 @@ pub use self::{
     serde::{Serializer, SerializerOptions},
 };
 
-use std::{io::Write, iter::FromIterator, mem};
+use std::io::Write;
 
 use crate::{
-    bson::{Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex},
+    bson::{Bson, Document},
     de::MAX_BSON_SIZE,
     spec::BinarySubtype,
-    Binary,
     RawDocumentBuf,
 };
 use ::serde::{ser::Error as SerdeError, Serialize};
@@ -106,83 +105,6 @@ fn write_binary<W: Write>(mut writer: W, bytes: &[u8], subtype: BinarySubtype) -
     writer.write_all(bytes).map_err(From::from)
 }
 
-fn serialize_array<W: Write + ?Sized>(writer: &mut W, arr: &[Bson]) -> Result<()> {
-    let mut buf = Vec::new();
-    for (key, val) in arr.iter().enumerate() {
-        serialize_bson(&mut buf, &key.to_string(), val)?;
-    }
-
-    write_i32(
-        writer,
-        (buf.len() + mem::size_of::<i32>() + mem::size_of::<u8>()) as i32,
-    )?;
-    writer.write_all(&buf)?;
-    writer.write_all(b"\0")?;
-    Ok(())
-}
-
-pub(crate) fn serialize_bson<W: Write + ?Sized>(
-    writer: &mut W,
-    key: &str,
-    val: &Bson,
-) -> Result<()> {
-    writer.write_all(&[val.element_type() as u8])?;
-    write_cstring(writer, key)?;
-
-    match *val {
-        Bson::Double(v) => write_f64(writer, v),
-        Bson::String(ref v) => write_string(writer, v),
-        Bson::Array(ref v) => serialize_array(writer, v),
-        Bson::Document(ref v) => v.to_writer(writer),
-        Bson::Boolean(v) => writer.write_all(&[v as u8]).map_err(From::from),
-        Bson::RegularExpression(Regex {
-            ref pattern,
-            ref options,
-        }) => {
-            write_cstring(writer, pattern)?;
-
-            let mut chars: Vec<char> = options.chars().collect();
-            chars.sort_unstable();
-
-            write_cstring(writer, String::from_iter(chars).as_str())
-        }
-        Bson::JavaScriptCode(ref code) => write_string(writer, code),
-        Bson::ObjectId(ref id) => writer.write_all(&id.bytes()).map_err(From::from),
-        Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
-            ref code,
-            ref scope,
-        }) => {
-            let mut buf = Vec::new();
-            write_string(&mut buf, code)?;
-            scope.to_writer(&mut buf)?;
-
-            write_i32(writer, buf.len() as i32 + 4)?;
-            writer.write_all(&buf).map_err(From::from)
-        }
-        Bson::Int32(v) => write_i32(writer, v),
-        Bson::Int64(v) => write_i64(writer, v),
-        Bson::Timestamp(ts) => write_i64(writer, ts.to_le_i64()),
-        Bson::Binary(Binary { subtype, ref bytes }) => write_binary(writer, bytes, subtype),
-        Bson::DateTime(ref v) => write_i64(writer, v.timestamp_millis()),
-        Bson::Null => Ok(()),
-        Bson::Symbol(ref v) => write_string(writer, v),
-        Bson::Decimal128(ref v) => {
-            writer.write_all(&v.bytes)?;
-            Ok(())
-        }
-        Bson::Undefined => Ok(()),
-        Bson::MinKey => Ok(()),
-        Bson::MaxKey => Ok(()),
-        Bson::DbPointer(DbPointer {
-            ref namespace,
-            ref id,
-        }) => {
-            write_string(writer, namespace)?;
-            writer.write_all(&id.bytes()).map_err(From::from)
-        }
-    }
-}
-
 /// Encode a `T` Serializable into a [`Bson`] value.
 ///
 /// The [`Serializer`] used by this function presents itself as human readable, whereas the

From 0bec43e2f14cba42c53b46412a6968cdaf728fbe Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 1 Apr 2024 14:57:52 -0600
Subject: [PATCH 060/156] RUST-1899 Fix UUID string deserialization (#468)

---
 src/de/raw.rs    |  9 ---------
 src/de/serde.rs  | 11 +++++------
 src/uuid/test.rs | 21 +++++++++++++++++++++
 3 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/src/de/raw.rs b/src/de/raw.rs
index e338bf7d..a5f23717 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -208,15 +208,6 @@ impl<'de> Deserializer<'de> {
     where
         V: serde::de::Visitor<'de>,
     {
-        if let DeserializerHint::BinarySubtype(expected_st) = hint {
-            if self.current_type != ElementType::Binary {
-                return Err(Error::custom(format!(
-                    "expected Binary with subtype {:?}, instead got {:?}",
-                    expected_st, self.current_type
-                )));
-            }
-        }
-
         match self.current_type {
             ElementType::Int32 => visitor.visit_i32(read_i32(&mut self.bytes)?),
             ElementType::Int64 => visitor.visit_i64(read_i64(&mut self.bytes)?),
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 0ab77187..06ba351e 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -637,13 +637,12 @@ impl Deserializer {
 
         let is_rawbson = matches!(hint, DeserializerHint::RawBson);
 
-        if let DeserializerHint::BinarySubtype(expected_st) = hint {
-            match value {
-                Bson::Binary(ref b) if b.subtype == expected_st => {}
-                ref b => {
+        if let DeserializerHint::BinarySubtype(expected_subtype) = hint {
+            if let Bson::Binary(ref binary) = value {
+                if binary.subtype != expected_subtype {
                     return Err(Error::custom(format!(
-                        "expected Binary with subtype {:?}, instead got {:?}",
-                        expected_st, b
+                        "expected Binary with subtype {:?}, instead got subtype {:?}",
+                        expected_subtype, binary.subtype
                     )));
                 }
             }
diff --git a/src/uuid/test.rs b/src/uuid/test.rs
index d33c02db..5118270a 100644
--- a/src/uuid/test.rs
+++ b/src/uuid/test.rs
@@ -1,4 +1,6 @@
 use crate::{
+    from_document,
+    from_slice,
     spec::BinarySubtype,
     uuid::{Uuid, UuidRepresentation},
     Binary,
@@ -269,3 +271,22 @@ fn interop_1() {
     let d_uuid = doc! { "uuid": uuid_uuid };
     assert_eq!(d_bson, d_uuid);
 }
+
+#[test]
+fn deserialize_uuid_from_string() {
+    #[derive(Deserialize)]
+    struct UuidWrapper {
+        uuid: Uuid,
+    }
+
+    let uuid = Uuid::new();
+
+    let doc = doc! { "uuid": uuid.to_string() };
+    let wrapper: UuidWrapper = from_document(doc).expect("failed to deserialize document");
+    assert_eq!(wrapper.uuid, uuid);
+
+    let raw_doc = rawdoc! { "uuid": uuid.to_string() };
+    let wrapper: UuidWrapper =
+        from_slice(raw_doc.as_bytes()).expect("failed to deserialize raw document");
+    assert_eq!(wrapper.uuid, uuid);
+}

From c5be9503ebf481a0e10ff3c5e73a3b7bd0bdf53a Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 2 Apr 2024 14:32:36 -0400
Subject: [PATCH 061/156] release v2.10.0 (#469) (#470)

---
 Cargo.toml |  2 +-
 README.md  |  2 +-
 src/lib.rs | 65 ++++++++++++++++++++++++++++++++++++------------------
 3 files changed, 46 insertions(+), 23 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index fb724f6f..efa92379 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.9.0"
+version = "2.10.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index e5843591..410f6c76 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.9.0"
+bson = "2.10.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 480caff6..2f5ffad2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.9.0"
+//! bson = "2.10.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in
@@ -208,25 +208,26 @@
 //! let redacted_bson = bson::to_bson(&person).unwrap();
 //! ```
 //!
-//! Any types that implement [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) can be used in this way. Doing so helps
-//! separate the "business logic" that operates over the data from the (de)serialization logic that
-//! translates the data to/from its serialized form. This can lead to more clear and concise code
-//! that is also less error prone.
+//! Any types that implement [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize)
+//! can be used in this way. Doing so helps separate the "business logic" that operates over the
+//! data from the (de)serialization logic that translates the data to/from its serialized form. This
+//! can lead to more clear and concise code that is also less error prone.
 //!
 //! ## Working with datetimes
 //!
 //! The BSON format includes a datetime type, which is modeled in this crate by the
 //! [`DateTime`] struct, and the
-//! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations for this struct produce and parse BSON datetimes
-//! when serializing to or deserializing from BSON. The popular crate [`chrono`](docs.rs/chrono)
-//! also provides a [`DateTime`] type, but its [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations operate
+//! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations for this
+//! struct produce and parse BSON datetimes when serializing to or deserializing from BSON. The
+//! popular crate [`chrono`](docs.rs/chrono) also provides a [`DateTime`] type, but its
+//! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations operate
 //! on strings instead, so when using it with BSON, the BSON datetime type is not used. To work
 //! around this, the `chrono-0_4` feature flag can be enabled. This flag exposes a number of
-//! convenient conversions between [`bson::DateTime`](crate::DateTime) and [`chrono::DateTime`], including the
-//! [`serde_helpers::chrono_datetime_as_bson_datetime`]
-//! serde helper, which can be used to (de)serialize [`chrono::DateTime`]s to/from BSON datetimes, and
-//! the `From<chrono::DateTime>` implementation for [`Bson`], which allows [`chrono::DateTime`] values
-//! to be used in the `doc!` and `bson!` macros.
+//! convenient conversions between [`bson::DateTime`](crate::DateTime) and [`chrono::DateTime`],
+//! including the [`serde_helpers::chrono_datetime_as_bson_datetime`]
+//! serde helper, which can be used to (de)serialize [`chrono::DateTime`]s to/from BSON datetimes,
+//! and the `From<chrono::DateTime>` implementation for [`Bson`], which allows [`chrono::DateTime`]
+//! values to be used in the `doc!` and `bson!` macros.
 //!
 //! e.g.
 //! ``` rust
@@ -267,8 +268,8 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever is,
-//! it will only happen in a minor or major version release.
+//! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever
+//! is, it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
 #![doc(html_root_url = "https://docs.rs/bson/2.6.0")]
@@ -280,18 +281,40 @@ pub use self::{
     bson::{Array, 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,
+        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, RawBinaryRef, RawBson, RawBsonRef, RawDbPointerRef, RawDocument,
-        RawDocumentBuf, RawJavaScriptCodeWithScope, RawJavaScriptCodeWithScopeRef, RawRegexRef,
+        RawArray,
+        RawArrayBuf,
+        RawBinaryRef,
+        RawBson,
+        RawBsonRef,
+        RawDbPointerRef,
+        RawDocument,
+        RawDocumentBuf,
+        RawJavaScriptCodeWithScope,
+        RawJavaScriptCodeWithScopeRef,
+        RawRegexRef,
     },
     ser::{
-        to_bson, to_bson_with_options, to_document, to_document_with_options, to_raw_document_buf,
-        to_vec, Serializer, SerializerOptions,
+        to_bson,
+        to_bson_with_options,
+        to_document,
+        to_document_with_options,
+        to_raw_document_buf,
+        to_vec,
+        Serializer,
+        SerializerOptions,
     },
     uuid::{Uuid, UuidRepresentation},
 };

From 9c4b963a1054c94471a1c5fc9f8ad5b508c5664c Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 5 Apr 2024 14:42:44 -0400
Subject: [PATCH 062/156] RUST-1764 Add `HumanReadable` convenience wrapper
 (#471)

---
 rustfmt.toml               |   1 -
 src/de/raw.rs              |  15 +++-
 src/de/serde.rs            |  12 +++-
 src/ser/raw/mod.rs         |  13 +++-
 src/ser/serde.rs           |  12 +++-
 src/serde_helpers.rs       |  45 +++++++++++-
 src/tests/mod.rs           |   1 +
 src/tests/serde_helpers.rs | 137 +++++++++++++++++++++++++++++++++++++
 8 files changed, 229 insertions(+), 7 deletions(-)
 create mode 100644 src/tests/serde_helpers.rs

diff --git a/rustfmt.toml b/rustfmt.toml
index ff7209cf..4dd91d4c 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -2,7 +2,6 @@ combine_control_expr = false
 comment_width = 100
 condense_wildcard_suffixes = true
 format_strings = true
-normalize_comments = true
 use_try_shorthand = true
 wrap_comments = true
 imports_layout = "HorizontalVertical"
diff --git a/src/de/raw.rs b/src/de/raw.rs
index a5f23717..c9dcb602 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -14,6 +14,7 @@ use serde::{
 use crate::{
     oid::ObjectId,
     raw::{RawBinaryRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
     uuid::UUID_NEWTYPE_NAME,
     Bson,
@@ -51,6 +52,8 @@ pub(crate) struct Deserializer<'de> {
     /// but given that there's no difference between deserializing an embedded document and a
     /// top level one, the distinction isn't necessary.
     current_type: ElementType,
+
+    human_readable: bool,
 }
 
 /// Enum used to determine what the type of document being deserialized is in
@@ -65,6 +68,7 @@ impl<'de> Deserializer<'de> {
         Self {
             bytes: BsonBuf::new(buf, utf8_lossy),
             current_type: ElementType::EmbeddedDocument,
+            human_readable: false,
         }
     }
 
@@ -291,6 +295,7 @@ impl<'de> Deserializer<'de> {
                         let doc = Bson::JavaScriptCode(code).into_extended_document(false);
                         visitor.visit_map(MapDeserializer::new(
                             doc,
+                            #[allow(deprecated)]
                             DeserializerOptions::builder().human_readable(false).build(),
                         ))
                     }
@@ -348,6 +353,7 @@ impl<'de> Deserializer<'de> {
                         let doc = Bson::Symbol(symbol).into_extended_document(false);
                         visitor.visit_map(MapDeserializer::new(
                             doc,
+                            #[allow(deprecated)]
                             DeserializerOptions::builder().human_readable(false).build(),
                         ))
                     }
@@ -454,12 +460,19 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
 
                 self.deserialize_next(visitor, DeserializerHint::RawBson)
             }
+            HUMAN_READABLE_NEWTYPE => {
+                let old = self.human_readable;
+                self.human_readable = true;
+                let result = visitor.visit_newtype_struct(&mut *self);
+                self.human_readable = old;
+                result
+            }
             _ => visitor.visit_newtype_struct(self),
         }
     }
 
     fn is_human_readable(&self) -> bool {
-        false
+        self.human_readable
     }
 
     forward_to_deserialize_any! {
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 06ba351e..e3b31f5e 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -26,6 +26,7 @@ use crate::{
     document::{Document, IntoIter},
     oid::ObjectId,
     raw::{RawBsonRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::BinarySubtype,
     uuid::UUID_NEWTYPE_NAME,
     Binary,
@@ -578,6 +579,7 @@ pub struct Deserializer {
 pub struct DeserializerOptions {
     /// Whether the [`Deserializer`] should present itself as human readable or not.
     /// The default is true.
+    #[deprecated = "use bson::serde_helpers::HumanReadable"]
     pub human_readable: Option<bool>,
 }
 
@@ -597,6 +599,8 @@ pub struct DeserializerOptionsBuilder {
 
 impl DeserializerOptionsBuilder {
     /// Set the value for [`DeserializerOptions::human_readable`].
+    #[deprecated = "use bson::serde_helpers::HumanReadable"]
+    #[allow(deprecated)]
     pub fn human_readable(mut self, val: impl Into<Option<bool>>) -> Self {
         self.options.human_readable = val.into();
         self
@@ -716,6 +720,7 @@ macro_rules! forward_to_deserialize {
 impl<'de> de::Deserializer<'de> for Deserializer {
     type Error = crate::de::Error;
 
+    #[allow(deprecated)]
     fn is_human_readable(&self) -> bool {
         self.options.human_readable.unwrap_or(true)
     }
@@ -815,7 +820,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
 
     #[inline]
     fn deserialize_newtype_struct<V>(
-        self,
+        mut self,
         name: &'static str,
         visitor: V,
     ) -> crate::de::Result<V::Value>
@@ -848,6 +853,11 @@ impl<'de> de::Deserializer<'de> for Deserializer {
 
                 self.deserialize_next(visitor, DeserializerHint::RawBson)
             }
+            #[allow(deprecated)]
+            HUMAN_READABLE_NEWTYPE => {
+                self.options.human_readable = Some(true);
+                visitor.visit_newtype_struct(self)
+            }
             _ => visitor.visit_newtype_struct(self),
         }
     }
diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs
index 960c5a46..2fb739c3 100644
--- a/src/ser/raw/mod.rs
+++ b/src/ser/raw/mod.rs
@@ -14,6 +14,7 @@ use super::{write_binary, write_cstring, write_f64, write_i32, write_i64, write_
 use crate::{
     raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     ser::{Error, Result},
+    serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
     uuid::UUID_NEWTYPE_NAME,
 };
@@ -30,6 +31,8 @@ pub(crate) struct Serializer {
 
     /// Hint provided by the type being serialized.
     hint: SerializerHint,
+
+    human_readable: bool,
 }
 
 /// Various bits of information that the serialized type can provide to the serializer to
@@ -60,6 +63,7 @@ impl Serializer {
             bytes: Vec::new(),
             type_index: 0,
             hint: SerializerHint::None,
+            human_readable: false,
         }
     }
 
@@ -115,7 +119,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     type SerializeStructVariant = VariantSerializer<'a>;
 
     fn is_human_readable(&self) -> bool {
-        false
+        self.human_readable
     }
 
     #[inline]
@@ -267,6 +271,13 @@ impl<'a> serde::Serializer for &'a mut Serializer {
             UUID_NEWTYPE_NAME => self.hint = SerializerHint::Uuid,
             RAW_DOCUMENT_NEWTYPE => self.hint = SerializerHint::RawDocument,
             RAW_ARRAY_NEWTYPE => self.hint = SerializerHint::RawArray,
+            HUMAN_READABLE_NEWTYPE => {
+                let old = self.human_readable;
+                self.human_readable = true;
+                let result = value.serialize(&mut *self);
+                self.human_readable = old;
+                return result;
+            }
             _ => {}
         }
         value.serialize(self)
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index e2866a54..fee2b5f3 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -18,6 +18,7 @@ use crate::{
     extjson,
     oid::ObjectId,
     raw::{RawDbPointerRef, RawRegexRef, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::BinarySubtype,
     uuid::UUID_NEWTYPE_NAME,
     Binary,
@@ -120,6 +121,7 @@ pub struct Serializer {
 pub struct SerializerOptions {
     /// Whether the [`Serializer`] should present itself as human readable or not.
     /// The default value is true.
+    #[deprecated = "use bson::serde_helpers::HumanReadable"]
     pub human_readable: Option<bool>,
 }
 
@@ -139,6 +141,8 @@ pub struct SerializerOptionsBuilder {
 
 impl SerializerOptionsBuilder {
     /// Set the value for [`SerializerOptions::is_human_readable`].
+    #[deprecated = "use bson::serde_helpers::HumanReadable"]
+    #[allow(deprecated)]
     pub fn human_readable(mut self, value: impl Into<Option<bool>>) -> Self {
         self.options.human_readable = value.into();
         self
@@ -296,7 +300,7 @@ impl ser::Serializer for Serializer {
 
     #[inline]
     fn serialize_newtype_struct<T: ?Sized>(
-        self,
+        mut self,
         name: &'static str,
         value: &T,
     ) -> crate::ser::Result<Bson>
@@ -348,6 +352,11 @@ impl ser::Serializer for Serializer {
                     b
                 ))),
             },
+            #[allow(deprecated)]
+            HUMAN_READABLE_NEWTYPE => {
+                self.options.human_readable = Some(true);
+                value.serialize(self)
+            }
             _ => value.serialize(self),
         }
     }
@@ -447,6 +456,7 @@ impl ser::Serializer for Serializer {
         })
     }
 
+    #[allow(deprecated)]
     fn is_human_readable(&self) -> bool {
         self.options.human_readable.unwrap_or(true)
     }
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 42c1657f..c9472184 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -1,8 +1,8 @@
 //! Collection of helper functions for serializing to and deserializing from BSON using Serde
 
-use std::{convert::TryFrom, result::Result};
+use std::{convert::TryFrom, marker::PhantomData, result::Result};
 
-use serde::{ser, Serialize, Serializer};
+use serde::{de::Visitor, ser, Deserialize, Serialize, Serializer};
 
 use crate::oid::ObjectId;
 
@@ -794,3 +794,44 @@ pub mod timestamp_as_u32 {
         Ok(Timestamp { time, increment: 0 })
     }
 }
+
+/// Wrapping a type in `HumanReadable` signals to the BSON serde integration that it and all
+/// recursively contained types should be handled as if
+/// [`SerializerOptions::human_readable`](crate::SerializerOptions::human_readable) and
+/// [`DeserializerOptions::human_readable`](crate::DeserializerOptions::human_readable) are
+/// set to `true`.
+#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct HumanReadable<T>(pub T);
+
+pub(crate) const HUMAN_READABLE_NEWTYPE: &str = "$__bson_private_human_readable";
+
+impl<T: Serialize> Serialize for HumanReadable<T> {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        serializer.serialize_newtype_struct(HUMAN_READABLE_NEWTYPE, &self.0)
+    }
+}
+
+impl<'de, T: Deserialize<'de>> Deserialize<'de> for HumanReadable<T> {
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        struct V<T>(PhantomData<fn() -> T>);
+        impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
+            type Value = HumanReadable<T>;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+                formatter.write_str("HumanReadable wrapper")
+            }
+            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                T::deserialize(deserializer).map(HumanReadable)
+            }
+        }
+        deserializer.deserialize_newtype_struct(HUMAN_READABLE_NEWTYPE, V(PhantomData))
+    }
+}
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
index 23deeea5..a3134674 100644
--- a/src/tests/mod.rs
+++ b/src/tests/mod.rs
@@ -2,6 +2,7 @@ mod binary_subtype;
 mod datetime;
 mod modules;
 mod serde;
+mod serde_helpers;
 mod spec;
 
 use modules::TestLock;
diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs
new file mode 100644
index 00000000..2e6453c1
--- /dev/null
+++ b/src/tests/serde_helpers.rs
@@ -0,0 +1,137 @@
+use serde::{de::Visitor, Deserialize, Serialize};
+
+use crate::serde_helpers::HumanReadable;
+
+#[test]
+fn human_readable_wrapper() {
+    #[derive(PartialEq, Eq, Debug)]
+    struct Detector {
+        serialized_as: bool,
+        deserialized_as: bool,
+    }
+    impl Detector {
+        fn new() -> Self {
+            Detector {
+                serialized_as: false,
+                deserialized_as: false,
+            }
+        }
+    }
+    impl Serialize for Detector {
+        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: serde::Serializer,
+        {
+            let s = if serializer.is_human_readable() {
+                "human readable"
+            } else {
+                "not human readable"
+            };
+            serializer.serialize_str(s)
+        }
+    }
+    impl<'de> Deserialize<'de> for Detector {
+        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+        where
+            D: serde::Deserializer<'de>,
+        {
+            struct V;
+            impl<'de> Visitor<'de> for V {
+                type Value = bool;
+
+                fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+                    formatter.write_str("Detector")
+                }
+
+                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+                where
+                    E: serde::de::Error,
+                {
+                    match v {
+                        "human readable" => Ok(true),
+                        "not human readable" => Ok(false),
+                        _ => Err(E::custom(format!("invalid detector string {:?}", v))),
+                    }
+                }
+            }
+            let deserialized_as = deserializer.is_human_readable();
+            let serialized_as = deserializer.deserialize_str(V)?;
+            Ok(Detector {
+                serialized_as,
+                deserialized_as,
+            })
+        }
+    }
+    #[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
+    struct Data {
+        first: HumanReadable<Detector>,
+        outer: Detector,
+        wrapped: HumanReadable<Detector>,
+        inner: HumanReadable<SubData>,
+    }
+    #[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
+    struct SubData {
+        value: Detector,
+    }
+    let data = Data {
+        first: HumanReadable(Detector::new()),
+        outer: Detector::new(),
+        wrapped: HumanReadable(Detector::new()),
+        inner: HumanReadable(SubData {
+            value: Detector::new(),
+        }),
+    };
+    let bson = crate::to_bson_with_options(
+        &data,
+        #[allow(deprecated)]
+        crate::SerializerOptions::builder()
+            .human_readable(false)
+            .build(),
+    )
+    .unwrap();
+    assert_eq!(
+        bson.as_document().unwrap(),
+        &doc! {
+            "first": "human readable",
+            "outer": "not human readable",
+            "wrapped": "human readable",
+            "inner": {
+                "value": "human readable",
+            }
+        }
+    );
+
+    let tripped: Data = crate::from_bson_with_options(
+        bson,
+        #[allow(deprecated)]
+        crate::DeserializerOptions::builder()
+            .human_readable(false)
+            .build(),
+    )
+    .unwrap();
+    let expected = Data {
+        first: HumanReadable(Detector {
+            serialized_as: true,
+            deserialized_as: true,
+        }),
+        outer: Detector {
+            serialized_as: false,
+            deserialized_as: false,
+        },
+        wrapped: HumanReadable(Detector {
+            serialized_as: true,
+            deserialized_as: true,
+        }),
+        inner: HumanReadable(SubData {
+            value: Detector {
+                serialized_as: true,
+                deserialized_as: true,
+            },
+        }),
+    };
+    assert_eq!(&tripped, &expected);
+
+    let bytes = crate::to_vec(&data).unwrap();
+    let raw_tripped: Data = crate::from_slice(&bytes).unwrap();
+    assert_eq!(&raw_tripped, &expected);
+}

From 8ecf27af32ac3d14af768b3c8f370f44945914ad Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 14 May 2024 12:36:21 -0400
Subject: [PATCH 063/156] minor: fix lifetime of RawElement::key (#473)

---
 src/raw/iter.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 9180df7a..01667b87 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -150,7 +150,7 @@ impl<'a> RawElement<'a> {
         self.size
     }
 
-    pub fn key(&self) -> &str {
+    pub fn key(&self) -> &'a str {
         self.key
     }
 

From 343a7ce6696b9d5c0d37334ec0b4da37c152b571 Mon Sep 17 00:00:00 2001
From: Matthew Chiaravalloti <matthew.chiaravalloti@mongodb.com>
Date: Thu, 23 May 2024 10:58:33 -0400
Subject: [PATCH 064/156] RUST-1933: Support deserializing $uuid extended JSON
 syntax (#474)

---
 src/de/serde.rs       |  8 ++++++++
 src/extjson/models.rs |  2 +-
 src/tests/serde.rs    | 15 +++++++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/src/de/serde.rs b/src/de/serde.rs
index e3b31f5e..4b73859d 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -381,6 +381,14 @@ impl<'de> Visitor<'de> for BsonVisitor {
                     ));
                 }
 
+                "$uuid" => {
+                    let v: String = visitor.next_value()?;
+                    let uuid = extjson::models::Uuid { value: v }
+                        .parse()
+                        .map_err(Error::custom)?;
+                    return Ok(Bson::Binary(uuid));
+                }
+
                 "$code" => {
                     let code = visitor.next_value::<String>()?;
                     if let Some(key) = visitor.next_key::<String>()? {
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 0bae6249..8e738c35 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -188,7 +188,7 @@ impl Binary {
 #[serde(deny_unknown_fields)]
 pub(crate) struct Uuid {
     #[serde(rename = "$uuid")]
-    value: String,
+    pub(crate) value: String,
 }
 
 impl Uuid {
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 29d3253f..b89ad79e 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -650,6 +650,21 @@ fn test_serde_legacy_uuid_1() {
     assert_eq!(foo.csharp_legacy, uuid);
 }
 
+#[test]
+fn test_de_uuid_extjson_string() {
+    let _guard = LOCK.run_concurrently();
+
+    let uuid_bson_bytes =
+        hex::decode("1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400").unwrap();
+    let uuid_document = Document::from_reader(uuid_bson_bytes.as_slice()).unwrap();
+    let expected_uuid_bson = Bson::from_extended_document(uuid_document);
+
+    let ext_json_uuid = "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}";
+    let actual_uuid_bson: Bson = serde_json::from_str(ext_json_uuid).unwrap();
+
+    assert_eq!(actual_uuid_bson, expected_uuid_bson);
+}
+
 #[test]
 fn test_de_oid_string() {
     let _guard = LOCK.run_concurrently();

From a8b595978f71b0f5cf22c58191456d43d1fc1184 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 5 Jun 2024 13:00:10 -0400
Subject: [PATCH 065/156] minor: fix bson clippy (#478)

---
 serde-tests/options.rs | 2 ++
 serde-tests/test.rs    | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/serde-tests/options.rs b/serde-tests/options.rs
index 2032f800..63324dc0 100644
--- a/serde-tests/options.rs
+++ b/serde-tests/options.rs
@@ -177,6 +177,7 @@ impl<'de> Deserialize<'de> for Seq {
 
 #[test]
 fn to_bson_with_options() {
+    #[allow(deprecated)]
     let options = SerializerOptions::builder().human_readable(false).build();
 
     let mut hm = HashMap::new();
@@ -199,6 +200,7 @@ fn to_bson_with_options() {
 
 #[test]
 fn from_bson_with_options() {
+    #[allow(deprecated)]
     let options = DeserializerOptions::builder().human_readable(false).build();
 
     let doc = doc! {
diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index 0e4e17d3..44d55ac0 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -88,6 +88,7 @@ where
 
     let non_human_readable_doc = bson::to_document_with_options(
         &expected_value,
+        #[allow(deprecated)]
         SerializerOptions::builder().human_readable(false).build(),
     )
     .expect(description);
@@ -96,6 +97,7 @@ where
         expected_value,
         &bson::from_document_with_options::<T>(
             non_human_readable_doc,
+            #[allow(deprecated)]
             DeserializerOptions::builder().human_readable(false).build()
         )
         .expect(description),
@@ -1388,6 +1390,7 @@ fn non_human_readable() {
     let human_readable = bson::to_bson(&val).unwrap();
     let non_human_readable = bson::to_bson_with_options(
         &val,
+        #[allow(deprecated)]
         SerializerOptions::builder().human_readable(false).build(),
     )
     .unwrap();

From 4114d03dd4922b2b5c6d74413ab11bb967560ef2 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 5 Jun 2024 13:00:21 -0400
Subject: [PATCH 066/156] release v2.11.0 (#476) (#477)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index efa92379..7c013ff7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.10.0"
+version = "2.11.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index 410f6c76..993bcc36 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.10.0"
+bson = "2.11.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 2f5ffad2..8e70d2fe 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.10.0"
+//! bson = "2.11.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From f525546b400e1904f724ea5d725db37432505ffe Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 3 Jul 2024 13:12:36 -0400
Subject: [PATCH 067/156] RUST-426 Fix Decimal128 human-readable serialization
 (#479)

---
 src/de/raw.rs            |  7 ++-----
 src/decimal128.rs        |  2 +-
 src/ser/serde.rs         | 18 ++++++------------
 src/tests/spec/corpus.rs | 28 +++++++++++++++++-----------
 4 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/src/de/raw.rs b/src/de/raw.rs
index c9dcb602..a7893f9d 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -17,7 +17,6 @@ use crate::{
     serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
     uuid::UUID_NEWTYPE_NAME,
-    Bson,
     DateTime,
     Decimal128,
     DeserializerOptions,
@@ -292,9 +291,8 @@ impl<'de> Deserializer<'de> {
                     )),
                     _ => {
                         let code = read_string(&mut self.bytes, utf8_lossy)?;
-                        let doc = Bson::JavaScriptCode(code).into_extended_document(false);
                         visitor.visit_map(MapDeserializer::new(
-                            doc,
+                            doc! { "$code": code },
                             #[allow(deprecated)]
                             DeserializerOptions::builder().human_readable(false).build(),
                         ))
@@ -350,9 +348,8 @@ impl<'de> Deserializer<'de> {
                     )),
                     _ => {
                         let symbol = read_string(&mut self.bytes, utf8_lossy)?;
-                        let doc = Bson::Symbol(symbol).into_extended_document(false);
                         visitor.visit_map(MapDeserializer::new(
-                            doc,
+                            doc! { "$symbol": symbol },
                             #[allow(deprecated)]
                             DeserializerOptions::builder().human_readable(false).build(),
                         ))
diff --git a/src/decimal128.rs b/src/decimal128.rs
index fecd0f16..7316c790 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -48,7 +48,7 @@ impl Decimal128 {
 
 impl fmt::Debug for Decimal128 {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Decimal128(...)")
+        write!(f, "Decimal128({})", hex::encode(self.bytes))
     }
 }
 
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index fee2b5f3..b3a2389c 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -10,7 +10,6 @@ use serde::ser::{
     SerializeTupleStruct,
     SerializeTupleVariant,
 };
-use serde_bytes::Bytes;
 
 use crate::{
     bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
@@ -85,11 +84,7 @@ impl Serialize for Bson {
             }
             Bson::RegularExpression(re) => re.serialize(serializer),
             Bson::Timestamp(t) => t.serialize(serializer),
-            Bson::Decimal128(d) => {
-                let mut state = serializer.serialize_struct("$numberDecimal", 1)?;
-                state.serialize_field("$numberDecimalBytes", Bytes::new(&d.bytes))?;
-                state.end()
-            }
+            Bson::Decimal128(d) => d.serialize(serializer),
             Bson::Undefined => {
                 let mut state = serializer.serialize_struct("$undefined", 1)?;
                 state.serialize_field("$undefined", &true)?;
@@ -705,15 +700,14 @@ impl Serialize for Decimal128 {
     where
         S: ser::Serializer,
     {
-        if serializer.is_human_readable() {
-            let mut state = serializer.serialize_map(Some(1))?;
-            state.serialize_entry("$numberDecimal", &self.to_string())?;
-            state.end()
+        let human_readable = serializer.is_human_readable();
+        let mut state = serializer.serialize_struct("$numberDecimal", 1)?;
+        if human_readable {
+            state.serialize_field("$numberDecimal", &self.to_string())?;
         } else {
-            let mut state = serializer.serialize_struct("$numberDecimal", 1)?;
             state.serialize_field("$numberDecimalBytes", serde_bytes::Bytes::new(&self.bytes))?;
-            state.end()
         }
+        state.end()
     }
 }
 
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 88d872ca..98fc23a0 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -267,12 +267,15 @@ fn run_test(test: TestFile) {
             description,
         );
 
-        assert_eq!(
-            hex::encode(documenttowriter_todocument_documentfromreader_cb).to_lowercase(),
-            valid.canonical_bson.to_lowercase(),
-            "{}",
-            description,
-        );
+        // bson::to_document(&Document) may be lossy due to round-tripping extjson
+        if valid.lossy != Some(true) {
+            assert_eq!(
+                hex::encode(documenttowriter_todocument_documentfromreader_cb).to_lowercase(),
+                valid.canonical_bson.to_lowercase(),
+                "{}",
+                description,
+            );
+        }
 
         assert_eq!(
             hex::encode(tovec_documentfromreader_cb).to_lowercase(),
@@ -313,11 +316,14 @@ fn run_test(test: TestFile) {
                 description
             );
 
-            assert_eq!(
-                documentfromreader_cb, todocument_documentfromreader_cb,
-                "{}",
-                description
-            );
+            // bson::to_document(&Document) may be lossy due to round-tripping extjson
+            if valid.lossy != Some(true) {
+                assert_eq!(
+                    documentfromreader_cb, todocument_documentfromreader_cb,
+                    "{}",
+                    description
+                );
+            }
 
             assert_eq!(
                 document_from_raw_document, documentfromreader_cb,

From 0ed3635fe44b5ea9184143fa355756e21ef8de32 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 9 Jul 2024 13:46:27 -0400
Subject: [PATCH 068/156] RUST-1773 Merge duplicate extjson map parsing between
 OwnedOrBorrowedRawBsonVisitor and SeededVisitor (#480)

---
 src/datetime.rs                 |   4 +
 src/raw/serde.rs                |  12 ++
 src/raw/serde/bson_visitor.rs   | 296 +++++++++++++++++---------------
 src/raw/serde/seeded_visitor.rs | 211 ++++++++++-------------
 4 files changed, 261 insertions(+), 262 deletions(-)

diff --git a/src/datetime.rs b/src/datetime.rs
index 4c4469dc..f52b16e9 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -405,6 +405,10 @@ impl crate::DateTime {
         self.checked_duration_since(earlier)
             .unwrap_or(Duration::ZERO)
     }
+
+    pub(crate) fn as_le_bytes(&self) -> [u8; 8] {
+        self.0.to_le_bytes()
+    }
 }
 
 impl fmt::Debug for crate::DateTime {
diff --git a/src/raw/serde.rs b/src/raw/serde.rs
index 98341fbe..1f877c1d 100644
--- a/src/raw/serde.rs
+++ b/src/raw/serde.rs
@@ -33,6 +33,18 @@ pub(crate) enum OwnedOrBorrowedRawBson<'a> {
     Borrowed(RawBsonRef<'a>),
 }
 
+impl<'a> OwnedOrBorrowedRawBson<'a> {
+    pub(crate) fn as_ref<'b>(&'b self) -> RawBsonRef<'b>
+    where
+        'a: 'b,
+    {
+        match self {
+            Self::Borrowed(r) => *r,
+            Self::Owned(bson) => bson.as_raw_bson_ref(),
+        }
+    }
+}
+
 impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawBson<'a> {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
diff --git a/src/raw/serde/bson_visitor.rs b/src/raw/serde/bson_visitor.rs
index ac2eb043..24d7af35 100644
--- a/src/raw/serde/bson_visitor.rs
+++ b/src/raw/serde/bson_visitor.rs
@@ -44,6 +44,160 @@ use super::{
 /// A visitor used to deserialize types backed by raw BSON.
 pub(crate) struct OwnedOrBorrowedRawBsonVisitor;
 
+pub(super) enum MapParse<'de> {
+    Leaf(OwnedOrBorrowedRawBson<'de>),
+    Aggregate(CowStr<'de>),
+}
+
+impl OwnedOrBorrowedRawBsonVisitor {
+    pub(super) fn parse_map<'de, A>(map: &mut A) -> Result<MapParse<'de>, A::Error>
+    where
+        A: serde::de::MapAccess<'de>,
+    {
+        let first_key = match map.next_key::<CowStr>()? {
+            Some(k) => k,
+            None => {
+                return Ok(MapParse::Leaf(
+                    RawBson::Document(RawDocumentBuf::new()).into(),
+                ))
+            }
+        };
+        Ok(MapParse::Leaf(match first_key.0.as_ref() {
+            "$oid" => {
+                let oid: ObjectId = map.next_value()?;
+                RawBsonRef::ObjectId(oid).into()
+            }
+            "$symbol" => {
+                let s: CowStr = map.next_value()?;
+                match s.0 {
+                    Cow::Borrowed(s) => RawBsonRef::Symbol(s).into(),
+                    Cow::Owned(s) => RawBson::Symbol(s).into(),
+                }
+            }
+            "$numberDecimalBytes" => {
+                let bytes: ByteBuf = map.next_value()?;
+                RawBsonRef::Decimal128(Decimal128::deserialize_from_slice(bytes.as_ref())?).into()
+            }
+            "$regularExpression" => {
+                let body: BorrowedRegexBody = map.next_value()?;
+
+                match (body.pattern, body.options) {
+                    (Cow::Borrowed(p), Cow::Borrowed(o)) => {
+                        RawBsonRef::RegularExpression(RawRegexRef {
+                            pattern: p,
+                            options: o,
+                        })
+                        .into()
+                    }
+                    (p, o) => RawBson::RegularExpression(Regex {
+                        pattern: p.into_owned(),
+                        options: o.into_owned(),
+                    })
+                    .into(),
+                }
+            }
+            "$undefined" => {
+                let _: bool = map.next_value()?;
+                RawBsonRef::Undefined.into()
+            }
+            "$binary" => {
+                let v: BorrowedBinaryBody = map.next_value()?;
+
+                if let Cow::Borrowed(bytes) = v.bytes {
+                    RawBsonRef::Binary(RawBinaryRef {
+                        bytes,
+                        subtype: v.subtype.into(),
+                    })
+                    .into()
+                } else {
+                    RawBson::Binary(Binary {
+                        bytes: v.bytes.into_owned(),
+                        subtype: v.subtype.into(),
+                    })
+                    .into()
+                }
+            }
+            "$date" => {
+                let date: i64 = map.next_value()?;
+                RawBsonRef::DateTime(DateTime::from_millis(date)).into()
+            }
+            "$timestamp" => {
+                let timestamp: TimestampBody = map.next_value()?;
+                RawBsonRef::Timestamp(Timestamp {
+                    time: timestamp.t,
+                    increment: timestamp.i,
+                })
+                .into()
+            }
+            "$minKey" => {
+                let _ = map.next_value::<i32>()?;
+                RawBsonRef::MinKey.into()
+            }
+            "$maxKey" => {
+                let _ = map.next_value::<i32>()?;
+                RawBsonRef::MaxKey.into()
+            }
+            "$code" => {
+                let code = map.next_value::<CowStr>()?;
+                if let Some(key) = map.next_key::<CowStr>()? {
+                    if key.0.as_ref() == "$scope" {
+                        let scope = map.next_value::<OwnedOrBorrowedRawDocument>()?;
+                        match (code.0, scope) {
+                            (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => {
+                                RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef {
+                                    code,
+                                    scope,
+                                })
+                                .into()
+                            }
+                            (code, scope) => {
+                                RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope {
+                                    code: code.into_owned(),
+                                    scope: scope.into_owned(),
+                                })
+                                .into()
+                            }
+                        }
+                    } else {
+                        return Err(SerdeError::unknown_field(&key.0, &["$scope"]));
+                    }
+                } else if let Cow::Borrowed(code) = code.0 {
+                    RawBsonRef::JavaScriptCode(code).into()
+                } else {
+                    RawBson::JavaScriptCode(code.0.into_owned()).into()
+                }
+            }
+            "$dbPointer" => {
+                let db_pointer: BorrowedDbPointerBody = map.next_value()?;
+                if let Cow::Borrowed(ns) = db_pointer.ns.0 {
+                    RawBsonRef::DbPointer(RawDbPointerRef {
+                        namespace: ns,
+                        id: db_pointer.id,
+                    })
+                    .into()
+                } else {
+                    RawBson::DbPointer(DbPointer {
+                        namespace: db_pointer.ns.0.into_owned(),
+                        id: db_pointer.id,
+                    })
+                    .into()
+                }
+            }
+            RAW_DOCUMENT_NEWTYPE => {
+                let bson = map.next_value::<&[u8]>()?;
+                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
+                RawBsonRef::Document(doc).into()
+            }
+            RAW_ARRAY_NEWTYPE => {
+                let bson = map.next_value::<&[u8]>()?;
+                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
+                RawBsonRef::Array(RawArray::from_doc(doc)).into()
+            }
+            _ => return Ok(MapParse::Aggregate(first_key)),
+        }))
+    }
+}
+
 impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor {
     type Value = OwnedOrBorrowedRawBson<'de>;
 
@@ -209,145 +363,9 @@ impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor {
     where
         A: serde::de::MapAccess<'de>,
     {
-        let first_key = match map.next_key::<CowStr>()? {
-            Some(k) => k,
-            None => return Ok(RawBson::Document(RawDocumentBuf::new()).into()),
-        };
-
-        match first_key.0.as_ref() {
-            "$oid" => {
-                let oid: ObjectId = map.next_value()?;
-                Ok(RawBsonRef::ObjectId(oid).into())
-            }
-            "$symbol" => {
-                let s: CowStr = map.next_value()?;
-                match s.0 {
-                    Cow::Borrowed(s) => Ok(RawBsonRef::Symbol(s).into()),
-                    Cow::Owned(s) => Ok(RawBson::Symbol(s).into()),
-                }
-            }
-            "$numberDecimalBytes" => {
-                let bytes: ByteBuf = map.next_value()?;
-                return Ok(RawBsonRef::Decimal128(Decimal128::deserialize_from_slice(
-                    bytes.as_ref(),
-                )?)
-                .into());
-            }
-            "$regularExpression" => {
-                let body: BorrowedRegexBody = map.next_value()?;
-
-                match (body.pattern, body.options) {
-                    (Cow::Borrowed(p), Cow::Borrowed(o)) => {
-                        Ok(RawBsonRef::RegularExpression(RawRegexRef {
-                            pattern: p,
-                            options: o,
-                        })
-                        .into())
-                    }
-                    (p, o) => Ok(RawBson::RegularExpression(Regex {
-                        pattern: p.into_owned(),
-                        options: o.into_owned(),
-                    })
-                    .into()),
-                }
-            }
-            "$undefined" => {
-                let _: bool = map.next_value()?;
-                Ok(RawBsonRef::Undefined.into())
-            }
-            "$binary" => {
-                let v: BorrowedBinaryBody = map.next_value()?;
-
-                if let Cow::Borrowed(bytes) = v.bytes {
-                    Ok(RawBsonRef::Binary(RawBinaryRef {
-                        bytes,
-                        subtype: v.subtype.into(),
-                    })
-                    .into())
-                } else {
-                    Ok(RawBson::Binary(Binary {
-                        bytes: v.bytes.into_owned(),
-                        subtype: v.subtype.into(),
-                    })
-                    .into())
-                }
-            }
-            "$date" => {
-                let date: i64 = map.next_value()?;
-                Ok(RawBsonRef::DateTime(DateTime::from_millis(date)).into())
-            }
-            "$timestamp" => {
-                let timestamp: TimestampBody = map.next_value()?;
-                Ok(RawBsonRef::Timestamp(Timestamp {
-                    time: timestamp.t,
-                    increment: timestamp.i,
-                })
-                .into())
-            }
-            "$minKey" => {
-                let _ = map.next_value::<i32>()?;
-                Ok(RawBsonRef::MinKey.into())
-            }
-            "$maxKey" => {
-                let _ = map.next_value::<i32>()?;
-                Ok(RawBsonRef::MaxKey.into())
-            }
-            "$code" => {
-                let code = map.next_value::<CowStr>()?;
-                if let Some(key) = map.next_key::<CowStr>()? {
-                    if key.0.as_ref() == "$scope" {
-                        let scope = map.next_value::<OwnedOrBorrowedRawDocument>()?;
-                        match (code.0, scope) {
-                            (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => {
-                                Ok(RawBsonRef::JavaScriptCodeWithScope(
-                                    RawJavaScriptCodeWithScopeRef { code, scope },
-                                )
-                                .into())
-                            }
-                            (code, scope) => Ok(RawBson::JavaScriptCodeWithScope(
-                                RawJavaScriptCodeWithScope {
-                                    code: code.into_owned(),
-                                    scope: scope.into_owned(),
-                                },
-                            )
-                            .into()),
-                        }
-                    } else {
-                        Err(SerdeError::unknown_field(&key.0, &["$scope"]))
-                    }
-                } else if let Cow::Borrowed(code) = code.0 {
-                    Ok(RawBsonRef::JavaScriptCode(code).into())
-                } else {
-                    Ok(RawBson::JavaScriptCode(code.0.into_owned()).into())
-                }
-            }
-            "$dbPointer" => {
-                let db_pointer: BorrowedDbPointerBody = map.next_value()?;
-                if let Cow::Borrowed(ns) = db_pointer.ns.0 {
-                    Ok(RawBsonRef::DbPointer(RawDbPointerRef {
-                        namespace: ns,
-                        id: db_pointer.id,
-                    })
-                    .into())
-                } else {
-                    Ok(RawBson::DbPointer(DbPointer {
-                        namespace: db_pointer.ns.0.into_owned(),
-                        id: db_pointer.id,
-                    })
-                    .into())
-                }
-            }
-            RAW_DOCUMENT_NEWTYPE => {
-                let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
-                Ok(RawBsonRef::Document(doc).into())
-            }
-            RAW_ARRAY_NEWTYPE => {
-                let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
-                Ok(RawBsonRef::Array(RawArray::from_doc(doc)).into())
-            }
-            _ => {
+        match Self::parse_map(&mut map)? {
+            MapParse::Leaf(value) => Ok(value),
+            MapParse::Aggregate(first_key) => {
                 let mut buffer = CowByteBuffer::new();
                 let seeded_visitor = SeededVisitor::new(&mut buffer);
                 seeded_visitor.iterate_map(first_key, map)?;
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
index e03ef7a6..fa0fd31a 100644
--- a/src/raw/serde/seeded_visitor.rs
+++ b/src/raw/serde/seeded_visitor.rs
@@ -4,23 +4,15 @@ use serde::{
     de::{DeserializeSeed, Error as SerdeError, MapAccess, SeqAccess, Visitor},
     Deserializer,
 };
-use serde_bytes::ByteBuf;
 
 use crate::{
-    de::MIN_BSON_DOCUMENT_SIZE,
-    extjson::models::{
-        BorrowedBinaryBody,
-        BorrowedDbPointerBody,
-        BorrowedRegexBody,
-        TimestampBody,
-    },
-    oid::ObjectId,
-    raw::{RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    raw::RAW_BSON_NEWTYPE,
     spec::{BinarySubtype, ElementType},
-    RawDocumentBuf,
+    RawBson,
+    RawBsonRef,
 };
 
-use super::CowStr;
+use super::{CowStr, MapParse, OwnedOrBorrowedRawBson, OwnedOrBorrowedRawBsonVisitor};
 
 /// A copy-on-write byte buffer containing raw BSON bytes. The inner value starts as `None` and
 /// transitions to either `Cow::Borrowed` or `Cow::Owned` depending upon the data visited.
@@ -272,122 +264,95 @@ impl<'a, 'de> Visitor<'de> for SeededVisitor<'a, 'de> {
     where
         A: MapAccess<'de>,
     {
-        let first_key = match map.next_key::<CowStr>()? {
-            Some(key) => key,
-            None => {
-                self.buffer
-                    .append_bytes(&MIN_BSON_DOCUMENT_SIZE.to_le_bytes());
-                self.buffer.push_byte(0);
-                return Ok(ElementType::EmbeddedDocument);
-            }
-        };
-
-        match first_key.0.as_ref() {
-            "$oid" => {
-                let oid: ObjectId = map.next_value()?;
-                self.buffer.append_bytes(&oid.bytes());
-                Ok(ElementType::ObjectId)
-            }
-            "$symbol" => {
-                let s: &str = map.next_value()?;
-                self.append_string(s);
-                Ok(ElementType::Symbol)
-            }
-            "$numberDecimalBytes" => {
-                let bytes: ByteBuf = map.next_value()?;
-                self.buffer.append_bytes(&bytes.into_vec());
-                Ok(ElementType::Decimal128)
-            }
-            "$regularExpression" => {
-                let regex: BorrowedRegexBody = map.next_value()?;
-                let pattern = regex.pattern.as_ref();
-                let options = regex.options.as_ref();
-
-                self.append_cstring(pattern).map_err(SerdeError::custom)?;
-                self.append_cstring(options).map_err(SerdeError::custom)?;
-
-                Ok(ElementType::RegularExpression)
-            }
-            "$undefined" => {
-                let _: bool = map.next_value()?;
-                Ok(ElementType::Undefined)
-            }
-            "$binary" => {
-                let binary: BorrowedBinaryBody = map.next_value()?;
-                match binary.bytes {
-                    Cow::Borrowed(borrowed_bytes) => {
-                        self.append_borrowed_binary(borrowed_bytes, binary.subtype);
+        match OwnedOrBorrowedRawBsonVisitor::parse_map(&mut map)? {
+            MapParse::Leaf(bson) => {
+                match bson {
+                    // Cases that need to distinguish owned and borrowed
+                    OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b)) => {
+                        self.append_borrowed_binary(b.bytes, b.subtype.into());
+                        Ok(ElementType::Binary)
                     }
-                    Cow::Owned(owned_bytes) => {
-                        self.append_owned_binary(owned_bytes, binary.subtype);
+                    OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b)) => {
+                        self.append_owned_binary(b.bytes, b.subtype.into());
+                        Ok(ElementType::Binary)
                     }
-                }
-
-                Ok(ElementType::Binary)
-            }
-            "$date" => {
-                let date: i64 = map.next_value()?;
-                self.buffer.append_bytes(&date.to_le_bytes());
-                Ok(ElementType::DateTime)
-            }
-            "$timestamp" => {
-                let timestamp: TimestampBody = map.next_value()?;
-                self.buffer.append_bytes(&timestamp.i.to_le_bytes());
-                self.buffer.append_bytes(&timestamp.t.to_le_bytes());
-                Ok(ElementType::Timestamp)
-            }
-            "$minKey" => {
-                let _: i32 = map.next_value()?;
-                Ok(ElementType::MinKey)
-            }
-            "$maxKey" => {
-                let _: i32 = map.next_value()?;
-                Ok(ElementType::MaxKey)
-            }
-            "$code" => {
-                let code: CowStr = map.next_value()?;
-                if let Some(key) = map.next_key::<CowStr>()? {
-                    let key = key.0.as_ref();
-                    if key == "$scope" {
-                        let length_index = self.pad_document_length();
-                        self.append_string(code.0.as_ref());
-
-                        let scope: RawDocumentBuf = map.next_value()?;
-                        self.buffer.append_bytes(scope.as_bytes());
-
-                        let length_bytes =
-                            ((self.buffer.len() - length_index) as i32).to_le_bytes();
-                        self.buffer
-                            .copy_from_slice(length_index..length_index + 4, &length_bytes);
-
-                        Ok(ElementType::JavaScriptCodeWithScope)
-                    } else {
-                        Err(SerdeError::unknown_field(key, &["$scope"]))
+                    OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Document(doc)) => {
+                        self.buffer.append_borrowed_bytes(doc.as_bytes());
+                        Ok(ElementType::EmbeddedDocument)
+                    }
+                    OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Array(arr)) => {
+                        self.buffer.append_borrowed_bytes(arr.as_bytes());
+                        Ok(ElementType::Array)
                     }
-                } else {
-                    self.append_string(code.0.as_ref());
-                    Ok(ElementType::JavaScriptCode)
+                    // Cases that don't
+                    _ => match bson.as_ref() {
+                        RawBsonRef::ObjectId(oid) => {
+                            self.buffer.append_bytes(&oid.bytes());
+                            Ok(ElementType::ObjectId)
+                        }
+                        RawBsonRef::Symbol(s) => {
+                            self.append_string(s);
+                            Ok(ElementType::Symbol)
+                        }
+                        RawBsonRef::Decimal128(d) => {
+                            self.buffer.append_bytes(&d.bytes);
+                            Ok(ElementType::Decimal128)
+                        }
+                        RawBsonRef::RegularExpression(re) => {
+                            self.append_cstring(re.pattern)
+                                .map_err(SerdeError::custom)?;
+                            self.append_cstring(re.options)
+                                .map_err(SerdeError::custom)?;
+                            Ok(ElementType::RegularExpression)
+                        }
+                        RawBsonRef::Undefined => Ok(ElementType::Undefined),
+                        RawBsonRef::DateTime(dt) => {
+                            self.buffer.append_bytes(&dt.as_le_bytes());
+                            Ok(ElementType::DateTime)
+                        }
+                        RawBsonRef::Timestamp(ts) => {
+                            self.buffer.append_bytes(&ts.increment.to_le_bytes());
+                            self.buffer.append_bytes(&ts.time.to_le_bytes());
+                            Ok(ElementType::Timestamp)
+                        }
+                        RawBsonRef::MinKey => Ok(ElementType::MinKey),
+                        RawBsonRef::MaxKey => Ok(ElementType::MaxKey),
+                        RawBsonRef::JavaScriptCode(s) => {
+                            self.append_string(s);
+                            Ok(ElementType::JavaScriptCode)
+                        }
+                        RawBsonRef::JavaScriptCodeWithScope(jsc) => {
+                            let length_index = self.pad_document_length();
+                            self.append_string(jsc.code);
+                            self.buffer.append_bytes(jsc.scope.as_bytes());
+
+                            let length_bytes =
+                                ((self.buffer.len() - length_index) as i32).to_le_bytes();
+                            self.buffer
+                                .copy_from_slice(length_index..length_index + 4, &length_bytes);
+
+                            Ok(ElementType::JavaScriptCodeWithScope)
+                        }
+                        RawBsonRef::DbPointer(dbp) => {
+                            self.append_string(dbp.namespace);
+                            self.buffer.append_bytes(&dbp.id.bytes());
+                            Ok(ElementType::DbPointer)
+                        }
+                        RawBsonRef::Double(d) => self.visit_f64(d),
+                        RawBsonRef::String(s) => self.visit_str(s),
+                        RawBsonRef::Boolean(b) => self.visit_bool(b),
+                        RawBsonRef::Null => self.visit_none(),
+                        RawBsonRef::Int32(i) => self.visit_i32(i),
+                        RawBsonRef::Int64(i) => self.visit_i64(i),
+                        // These are always borrowed and are handled
+                        // at the top of the outer `match`.
+                        RawBsonRef::Array(_) | RawBsonRef::Document(_) | RawBsonRef::Binary(_) => {
+                            unreachable!()
+                        }
+                    },
                 }
             }
-            "$dbPointer" => {
-                let db_pointer: BorrowedDbPointerBody = map.next_value()?;
-
-                self.append_string(db_pointer.ns.0.as_ref());
-                self.buffer.append_bytes(&db_pointer.id.bytes());
-
-                Ok(ElementType::DbPointer)
-            }
-            RAW_DOCUMENT_NEWTYPE => {
-                let document_bytes: &[u8] = map.next_value()?;
-                self.buffer.append_borrowed_bytes(document_bytes);
-                Ok(ElementType::EmbeddedDocument)
-            }
-            RAW_ARRAY_NEWTYPE => {
-                let array_bytes: &[u8] = map.next_value()?;
-                self.buffer.append_borrowed_bytes(array_bytes);
-                Ok(ElementType::Array)
-            }
-            _ => {
+            MapParse::Aggregate(first_key) => {
                 self.iterate_map(first_key, map)?;
                 Ok(ElementType::EmbeddedDocument)
             }

From b5541429b1ee0ab73e8d5a55d21dea3df2a51477 Mon Sep 17 00:00:00 2001
From: Pavel Lazureykis <pavel@lazureykis.dev>
Date: Mon, 15 Jul 2024 11:06:28 -0400
Subject: [PATCH 069/156] RUST-1987 Add serde helper module for
 `Option<DateTime>` (#482)

---
 src/serde_helpers.rs | 51 ++++++++++++++++++++++++++++++++++++++++++
 src/tests/serde.rs   | 53 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index c9472184..eb86578f 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -17,6 +17,12 @@ pub use chrono_datetime_as_bson_datetime::{
     deserialize as deserialize_chrono_datetime_from_bson_datetime,
     serialize as serialize_chrono_datetime_as_bson_datetime,
 };
+#[cfg(feature = "chrono-0_4")]
+#[doc(inline)]
+pub use chrono_datetime_as_bson_datetime_optional::{
+    deserialize as deserialize_chrono_datetime_from_bson_datetime_optional,
+    serialize as serialize_chrono_datetime_as_bson_datetime_optional,
+};
 #[doc(inline)]
 pub use hex_string_as_object_id::{
     deserialize as deserialize_hex_string_from_object_id,
@@ -307,6 +313,51 @@ pub mod chrono_datetime_as_bson_datetime {
     }
 }
 
+/// Contains functions to serialize an [`Option<chrono::DateTime>`] as an
+/// [`Option<crate::DateTime>`] and deserialize an [`Option<chrono::DateTime>`] from an
+/// [`Option<crate::DateTime>`].
+///
+/// ```rust
+/// # #[cfg(feature = "chrono-0_4")]
+/// # {
+/// # use serde::{Serialize, Deserialize};
+/// # use bson::serde_helpers::chrono_datetime_as_bson_datetime_optional;
+/// #[derive(Serialize, Deserialize)]
+/// struct Event {
+///     #[serde(with = "chrono_datetime_as_bson_datetime_optional")]
+///     pub date: Option<chrono::DateTime<chrono::Utc>>,
+/// }
+/// # }
+/// ```
+#[cfg(feature = "chrono-0_4")]
+#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
+pub mod chrono_datetime_as_bson_datetime_optional {
+    use crate::DateTime;
+    use chrono::Utc;
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
+    use std::result::Result;
+
+    /// Deserializes a [`chrono::DateTime`] from a [`crate::DateTime`].
+    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
+    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<chrono::DateTime<Utc>>, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let val = Option::deserialize(deserializer)?.map(|datetime: DateTime| datetime.to_chrono());
+        Ok(val)
+    }
+
+    /// Serializes a [`Option<chrono::DateTime>`] as a [`Option<crate::DateTime>`].
+    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
+    pub fn serialize<S: Serializer>(
+        val: &Option<chrono::DateTime<Utc>>,
+        serializer: S,
+    ) -> Result<S::Ok, S::Error> {
+        let datetime = val.map(DateTime::from_chrono);
+        datetime.serialize(serializer)
+    }
+}
+
 /// Contains functions to serialize an RFC 3339 (ISO 8601) formatted string as a [`crate::DateTime`]
 /// and deserialize an RFC 3339 (ISO 8601) formatted string from a [`crate::DateTime`].
 ///
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index b89ad79e..1720d7dc 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -866,6 +866,59 @@ fn test_datetime_helpers() {
         assert_eq!(b.date, expected);
     }
 
+    #[cfg(feature = "chrono-0_4")]
+    {
+        use std::str::FromStr;
+        #[derive(Deserialize, Serialize)]
+        struct B {
+            #[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime_optional")]
+            pub date: Option<chrono::DateTime<chrono::Utc>>,
+        }
+
+        let date = r#"
+    {
+        "date": {
+                "$date": {
+                    "$numberLong": "1591700287095"
+                }
+        }
+    }"#;
+        let json: serde_json::Value = serde_json::from_str(date).unwrap();
+        let b: B = serde_json::from_value(json).unwrap();
+        let expected: Option<chrono::DateTime<chrono::Utc>> =
+            Some(chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap());
+        assert_eq!(b.date, expected);
+        let doc = to_document(&b).unwrap();
+        assert_eq!(
+            Some(doc.get_datetime("date").unwrap().to_chrono()),
+            expected
+        );
+        let b: B = from_document(doc).unwrap();
+        assert_eq!(b.date, expected);
+    }
+
+    #[cfg(feature = "chrono-0_4")]
+    {
+        #[derive(Deserialize, Serialize)]
+        struct B {
+            #[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime_optional")]
+            pub date: Option<chrono::DateTime<chrono::Utc>>,
+        }
+
+        let date = r#"
+    {
+        "date": null
+    }"#;
+        let json: serde_json::Value = serde_json::from_str(date).unwrap();
+        let b: B = serde_json::from_value(json).unwrap();
+        let expected = None;
+        assert_eq!(b.date, expected);
+        let doc = to_document(&b).unwrap();
+        assert_eq!(None, expected);
+        let b: B = from_document(doc).unwrap();
+        assert_eq!(b.date, expected);
+    }
+
     #[derive(Deserialize, Serialize)]
     struct C {
         #[serde(with = "rfc3339_string_as_bson_datetime")]

From 39d90f6c446683b8d23da0ac6c391302449ef073 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 22 Jul 2024 15:44:07 -0400
Subject: [PATCH 070/156] RUST-1992 Convert raw deserializer to use raw
 document iteration (#483)

---
 src/de/error.rs          |    8 +
 src/de/mod.rs            |  118 +---
 src/de/raw.rs            | 1182 +++++++++++++-------------------------
 src/document.rs          |    4 +-
 src/raw/array.rs         |    4 +
 src/raw/document.rs      |    9 +-
 src/raw/iter.rs          |   78 ++-
 src/raw/mod.rs           |   10 +-
 src/raw/test/mod.rs      |    8 +
 src/tests/spec/corpus.rs |   12 +-
 10 files changed, 518 insertions(+), 915 deletions(-)

diff --git a/src/de/error.rs b/src/de/error.rs
index 30d4f51a..9f09c5b2 100644
--- a/src/de/error.rs
+++ b/src/de/error.rs
@@ -38,6 +38,14 @@ pub enum Error {
     },
 }
 
+impl Error {
+    pub(crate) fn deserialization(msg: impl ToString) -> Self {
+        Self::DeserializationError {
+            message: msg.to_string(),
+        }
+    }
+}
+
 impl From<io::Error> for Error {
     fn from(err: io::Error) -> Error {
         Error::Io(Arc::new(err))
diff --git a/src/de/mod.rs b/src/de/mod.rs
index eeaf6beb..f096ceca 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -34,11 +34,8 @@ use std::io::Read;
 
 use crate::{
     bson::{Bson, Document, Timestamp},
-    oid::ObjectId,
-    raw::RawBinaryRef,
     ser::write_i32,
     spec::BinarySubtype,
-    Decimal128,
 };
 
 use ::serde::{
@@ -71,38 +68,6 @@ enum DeserializerHint {
     RawBson,
 }
 
-pub(crate) fn read_string<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> Result<String> {
-    let len = read_i32(reader)?;
-
-    // UTF-8 String must have at least 1 byte (the last 0x00).
-    if len < 1 {
-        return Err(Error::invalid_length(
-            len as usize,
-            &"UTF-8 string must have at least 1 byte",
-        ));
-    }
-
-    let s = if utf8_lossy {
-        let mut buf = Vec::with_capacity(len as usize - 1);
-        reader.take(len as u64 - 1).read_to_end(&mut buf)?;
-        String::from_utf8_lossy(&buf).to_string()
-    } else {
-        let mut s = String::with_capacity(len as usize - 1);
-        reader.take(len as u64 - 1).read_to_string(&mut s)?;
-        s
-    };
-
-    // read the null terminator
-    if read_u8(reader)? != 0 {
-        return Err(Error::invalid_length(
-            len as usize,
-            &"contents of string longer than provided length",
-        ));
-    }
-
-    Ok(s)
-}
-
 pub(crate) fn read_bool<R: Read>(mut reader: R) -> Result<bool> {
     let val = read_u8(&mut reader)?;
     if val > 1 {
@@ -129,73 +94,6 @@ pub(crate) fn read_i32<R: Read + ?Sized>(reader: &mut R) -> Result<i32> {
     Ok(i32::from_le_bytes(buf))
 }
 
-#[inline]
-pub(crate) fn read_i64<R: Read + ?Sized>(reader: &mut R) -> Result<i64> {
-    let mut buf = [0; 8];
-    reader.read_exact(&mut buf)?;
-    Ok(i64::from_le_bytes(buf))
-}
-
-#[inline]
-fn read_f64<R: Read + ?Sized>(reader: &mut R) -> Result<f64> {
-    let mut buf = [0; 8];
-    reader.read_exact(&mut buf)?;
-    Ok(f64::from_le_bytes(buf))
-}
-
-/// Placeholder decoder for `Decimal128`. Reads 128 bits and just stores them, does no validation or
-/// parsing.
-#[inline]
-fn read_f128<R: Read + ?Sized>(reader: &mut R) -> Result<Decimal128> {
-    let mut buf = [0u8; 128 / 8];
-    reader.read_exact(&mut buf)?;
-    Ok(Decimal128 { bytes: buf })
-}
-
-impl<'a> RawBinaryRef<'a> {
-    pub(crate) fn from_slice_with_len_and_payload(
-        mut bytes: &'a [u8],
-        mut len: i32,
-        subtype: BinarySubtype,
-    ) -> Result<Self> {
-        if !(0..=MAX_BSON_SIZE).contains(&len) {
-            return Err(Error::invalid_length(
-                len as usize,
-                &format!("binary length must be between 0 and {}", MAX_BSON_SIZE).as_str(),
-            ));
-        } else if len as usize > bytes.len() {
-            return Err(Error::invalid_length(
-                len as usize,
-                &format!(
-                    "binary length {} exceeds buffer length {}",
-                    len,
-                    bytes.len()
-                )
-                .as_str(),
-            ));
-        }
-
-        // Skip length data in old binary.
-        if let BinarySubtype::BinaryOld = subtype {
-            let data_len = read_i32(&mut bytes)?;
-
-            if data_len + 4 != len {
-                return Err(Error::invalid_length(
-                    data_len as usize,
-                    &"0x02 length did not match top level binary length",
-                ));
-            }
-
-            len -= 4;
-        }
-
-        Ok(Self {
-            bytes: &bytes[0..len as usize],
-            subtype,
-        })
-    }
-}
-
 impl Timestamp {
     pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
         let mut bytes = [0; 8];
@@ -204,14 +102,6 @@ impl Timestamp {
     }
 }
 
-impl ObjectId {
-    pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
-        let mut buf = [0u8; 12];
-        reader.read_exact(&mut buf)?;
-        Ok(Self::from_bytes(buf))
-    }
-}
-
 /// Deserialize a `T` from the provided [`Bson`] value.
 ///
 /// The [`Deserializer`] used by this function presents itself as human readable, whereas the
@@ -335,8 +225,8 @@ pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    let mut deserializer = raw::Deserializer::new(bytes, false);
-    T::deserialize(&mut deserializer)
+    let deserializer = raw::Deserializer::new(bytes, false)?;
+    T::deserialize(deserializer)
 }
 
 /// Deserialize an instance of type `T` from a slice of BSON bytes, replacing any invalid UTF-8
@@ -349,6 +239,6 @@ pub fn from_slice_utf8_lossy<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    let mut deserializer = raw::Deserializer::new(bytes, true);
-    T::deserialize(&mut deserializer)
+    let deserializer = raw::Deserializer::new(bytes, true)?;
+    T::deserialize(deserializer)
 }
diff --git a/src/de/raw.rs b/src/de/raw.rs
index a7893f9d..f843272a 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -1,383 +1,213 @@
-use std::{
-    borrow::Cow,
-    convert::TryInto,
-    io::{ErrorKind, Read},
-    sync::Arc,
-};
+use std::borrow::Cow;
 
 use serde::{
-    de::{EnumAccess, Error as SerdeError, IntoDeserializer, MapAccess, VariantAccess},
+    de::{value::BorrowedStrDeserializer, Error as SerdeError, IntoDeserializer, MapAccess},
     forward_to_deserialize_any,
     Deserializer as SerdeDeserializer,
 };
 
 use crate::{
     oid::ObjectId,
-    raw::{RawBinaryRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    raw::{
+        RawBinaryRef,
+        RawElement,
+        RawIter,
+        Utf8LossyBson,
+        Utf8LossyJavaScriptCodeWithScope,
+        RAW_ARRAY_NEWTYPE,
+        RAW_BSON_NEWTYPE,
+        RAW_DOCUMENT_NEWTYPE,
+    },
     serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
     uuid::UUID_NEWTYPE_NAME,
     DateTime,
+    DbPointer,
     Decimal128,
-    DeserializerOptions,
+    RawBsonRef,
+    RawDbPointerRef,
     RawDocument,
+    RawJavaScriptCodeWithScopeRef,
+    RawRegexRef,
+    Regex,
     Timestamp,
 };
 
-use super::{
-    read_bool,
-    read_f128,
-    read_f64,
-    read_i32,
-    read_i64,
-    read_string,
-    read_u8,
-    DeserializerHint,
-    Error,
-    Result,
-    MAX_BSON_SIZE,
-    MIN_CODE_WITH_SCOPE_SIZE,
-};
+use super::{DeserializerHint, Error, Result};
 use crate::de::serde::MapDeserializer;
 
-/// Deserializer used to parse and deserialize raw BSON bytes.
+/// Deserializer mapping from raw bson to serde's data model.
 pub(crate) struct Deserializer<'de> {
-    bytes: BsonBuf<'de>,
-
-    /// The type of the element currently being deserialized.
-    ///
-    /// When the Deserializer is initialized, this will be `ElementType::EmbeddedDocument`, as the
-    /// only top level type is a document. The "embedded" portion is incorrect in this context,
-    /// but given that there's no difference between deserializing an embedded document and a
-    /// top level one, the distinction isn't necessary.
-    current_type: ElementType,
-
-    human_readable: bool,
+    element: RawElement<'de>,
+    options: DeserializerOptions,
 }
 
-/// Enum used to determine what the type of document being deserialized is in
-/// `Deserializer::deserialize_document`.
-enum DocumentType {
-    Array,
-    EmbeddedDocument,
+#[derive(Debug, Clone)]
+struct DeserializerOptions {
+    utf8_lossy: bool,
+    human_readable: bool,
 }
 
 impl<'de> Deserializer<'de> {
-    pub(crate) fn new(buf: &'de [u8], utf8_lossy: bool) -> Self {
-        Self {
-            bytes: BsonBuf::new(buf, utf8_lossy),
-            current_type: ElementType::EmbeddedDocument,
-            human_readable: false,
-        }
-    }
-
-    /// Ensure the entire document was visited, returning an error if not.
-    /// Will read the trailing null byte if necessary (i.e. the visitor stopped after visiting
-    /// exactly the number of elements in the document).
-    fn end_document(&mut self, length_remaining: i32) -> Result<()> {
-        match length_remaining.cmp(&1) {
-            std::cmp::Ordering::Equal => {
-                let nullbyte = read_u8(&mut self.bytes)?;
-                if nullbyte != 0 {
-                    return Err(Error::custom(format!(
-                        "expected null byte at end of document, got {:#x} instead",
-                        nullbyte
-                    )));
-                }
-            }
-            std::cmp::Ordering::Greater => {
-                return Err(Error::custom(format!(
-                    "document has bytes remaining that were not visited: {}",
-                    length_remaining
-                )));
-            }
-            std::cmp::Ordering::Less => {
-                if length_remaining < 0 {
-                    return Err(Error::custom("length of document was too short"));
-                }
-            }
-        }
-        Ok(())
-    }
-
-    /// Read a string from the BSON.
-    ///
-    /// If utf8_lossy, this will be an owned string if invalid UTF-8 is encountered in the string,
-    /// otherwise it will be borrowed.
-    fn deserialize_str(&mut self) -> Result<Cow<'de, str>> {
-        self.bytes.read_str()
+    pub(crate) fn new(buf: &'de [u8], utf8_lossy: bool) -> Result<Self> {
+        Ok(Self {
+            element: RawElement::toplevel(buf).map_err(Error::deserialization)?,
+            options: DeserializerOptions {
+                utf8_lossy,
+                human_readable: false,
+            },
+        })
     }
 
-    /// Read a null-terminated C style string from the underling BSON.
-    ///
-    /// If utf8_lossy, this will be an owned string if invalid UTF-8 is encountered in the string,
-    /// otherwise it will be borrowed.
-    fn deserialize_cstr(&mut self) -> Result<Cow<'de, str>> {
-        self.bytes.read_cstr()
+    fn value(&self) -> Result<RawBsonRef<'de>> {
+        self.element.value().map_err(Error::deserialization)
     }
 
-    /// Read an ObjectId from the underling BSON.
-    ///
-    /// If hinted to use raw BSON, the bytes of the ObjectId will be visited.
-    /// Otherwise, a map in the shape of the extended JSON format of an ObjectId will be.
-    fn deserialize_objectid<V>(&mut self, visitor: V, hint: DeserializerHint) -> Result<V::Value>
-    where
-        V: serde::de::Visitor<'de>,
-    {
-        let oid = ObjectId::from_reader(&mut self.bytes)?;
-        visitor.visit_map(ObjectIdAccess::new(oid, hint))
-    }
-
-    /// Read a document from the underling BSON, whether it's an array or an actual document.
-    ///
-    /// If hinted to use raw BSON, the bytes themselves will be visited using a special newtype
-    /// name. Otherwise, the key-value pairs will be accessed in order, either as part of a
-    /// [`MapAccess`] for documents or a [`SeqAccess`] for arrays.
-    fn deserialize_document<V>(
-        &mut self,
-        visitor: V,
-        hint: DeserializerHint,
-        document_type: DocumentType,
-    ) -> Result<V::Value>
+    /// Deserialize the element, using the type of the element along with the
+    /// provided hint to determine how to visit the data.
+    fn deserialize_hint<V>(&self, visitor: V, hint: DeserializerHint) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
-        let is_array = match document_type {
-            DocumentType::Array => true,
-            DocumentType::EmbeddedDocument => false,
-        };
-
-        match hint {
-            DeserializerHint::RawBson => {
-                let mut len = self.bytes.slice(4)?;
-                let len = read_i32(&mut len)?;
-
-                let doc = RawDocument::from_bytes(self.bytes.read_slice(len as usize)?)
-                    .map_err(Error::custom)?;
-
-                let access = if is_array {
-                    RawDocumentAccess::for_array(doc)
-                } else {
-                    RawDocumentAccess::new(doc)
+        if self.options.utf8_lossy {
+            if let Some(lossy) = self
+                .element
+                .value_utf8_lossy()
+                .map_err(Error::deserialization)?
+            {
+                return match lossy {
+                    Utf8LossyBson::String(s) => visitor.visit_string(s),
+                    Utf8LossyBson::RegularExpression(re) => {
+                        visitor.visit_map(RegexAccess::new(BsonCow::Owned(re)))
+                    }
+                    Utf8LossyBson::JavaScriptCode(code) => visitor.visit_map(MapDeserializer::new(
+                        doc! { "$code": code },
+                        #[allow(deprecated)]
+                        crate::DeserializerOptions::builder()
+                            .human_readable(false)
+                            .build(),
+                    )),
+                    Utf8LossyBson::JavaScriptCodeWithScope(jsc) => visitor.visit_map(
+                        CodeWithScopeAccess::new(BsonCow::Owned(jsc), hint, self.options.clone()),
+                    ),
+                    Utf8LossyBson::DbPointer(dbp) => {
+                        visitor.visit_map(DbPointerAccess::new(BsonCow::Owned(dbp), hint))
+                    }
+                    Utf8LossyBson::Symbol(s) => visitor.visit_map(MapDeserializer::new(
+                        doc! { "$symbol": s },
+                        #[allow(deprecated)]
+                        crate::DeserializerOptions::builder()
+                            .human_readable(false)
+                            .build(),
+                    )),
                 };
-
-                visitor.visit_map(access)
             }
-            _ if is_array => self.access_document(|access| visitor.visit_seq(access)),
-            _ => self.access_document(|access| visitor.visit_map(access)),
         }
-    }
-
-    /// Construct a [`DocumentAccess`] and pass it into the provided closure, returning the
-    /// result of the closure if no other errors are encountered.
-    fn access_document<F, O>(&mut self, f: F) -> Result<O>
-    where
-        F: FnOnce(DocumentAccess<'_, 'de>) -> Result<O>,
-    {
-        let mut length_remaining = read_i32(&mut self.bytes)?;
-        if length_remaining < 4 {
-            return Err(Error::custom("invalid length, less than min document size"));
-        }
-        length_remaining -= 4;
-        let out = f(DocumentAccess {
-            root_deserializer: self,
-            length_remaining: &mut length_remaining,
-        });
-
-        if out.is_ok() {
-            self.end_document(length_remaining)?;
-        }
-        out
-    }
-
-    /// Deserialize the next element type and update `current_type` accordingly.
-    /// Returns [`None`] if a null byte is read.
-    fn deserialize_next_type(&mut self) -> Result<Option<ElementType>> {
-        let tag = read_u8(&mut self.bytes)?;
-        if tag == 0 {
-            return Ok(None);
-        }
-
-        let element_type = ElementType::from(tag)
-            .ok_or_else(|| Error::custom(format!("invalid element type: {}", tag)))?;
-
-        self.current_type = element_type;
-        Ok(Some(element_type))
-    }
-
-    /// Deserialize the next element in the BSON, using the type of the element along with the
-    /// provided hint to determine how to visit the data.
-    fn deserialize_next<V>(&mut self, visitor: V, hint: DeserializerHint) -> Result<V::Value>
-    where
-        V: serde::de::Visitor<'de>,
-    {
-        match self.current_type {
-            ElementType::Int32 => visitor.visit_i32(read_i32(&mut self.bytes)?),
-            ElementType::Int64 => visitor.visit_i64(read_i64(&mut self.bytes)?),
-            ElementType::Double => visitor.visit_f64(read_f64(&mut self.bytes)?),
-            ElementType::String => match self.deserialize_str()? {
-                Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
-                Cow::Owned(string) => visitor.visit_string(string),
+        match self.value()? {
+            RawBsonRef::Int32(i) => visitor.visit_i32(i),
+            RawBsonRef::Int64(i) => visitor.visit_i64(i),
+            RawBsonRef::Double(d) => visitor.visit_f64(d),
+            RawBsonRef::String(s) => visitor.visit_borrowed_str(s),
+            RawBsonRef::Boolean(b) => visitor.visit_bool(b),
+            RawBsonRef::Null => visitor.visit_unit(),
+            RawBsonRef::ObjectId(oid) => visitor.visit_map(ObjectIdAccess::new(oid, hint)),
+            RawBsonRef::Document(doc) => match hint {
+                DeserializerHint::RawBson => visitor.visit_map(RawDocumentAccess::new(doc)),
+                _ => visitor.visit_map(DocumentAccess::new(doc, self.options.clone())?),
             },
-            ElementType::Boolean => visitor.visit_bool(read_bool(&mut self.bytes)?),
-            ElementType::Null => visitor.visit_unit(),
-            ElementType::ObjectId => self.deserialize_objectid(visitor, hint),
-            ElementType::EmbeddedDocument => {
-                self.deserialize_document(visitor, hint, DocumentType::EmbeddedDocument)
-            }
-            ElementType::Array => self.deserialize_document(visitor, hint, DocumentType::Array),
-            ElementType::Binary => {
-                let len = read_i32(&mut self.bytes)?;
-                if !(0..=MAX_BSON_SIZE).contains(&len) {
-                    return Err(Error::invalid_length(
-                        len as usize,
-                        &format!("binary length must be between 0 and {}", MAX_BSON_SIZE).as_str(),
-                    ));
+            RawBsonRef::Array(arr) => match hint {
+                DeserializerHint::RawBson => {
+                    visitor.visit_map(RawDocumentAccess::for_array(arr.as_doc()))
                 }
-                let subtype = BinarySubtype::from(read_u8(&mut self.bytes)?);
-
+                _ => visitor.visit_seq(DocumentAccess::new(arr.as_doc(), self.options.clone())?),
+            },
+            RawBsonRef::Binary(bin) => {
                 if let DeserializerHint::BinarySubtype(expected_subtype) = hint {
-                    if subtype != expected_subtype {
+                    if bin.subtype != expected_subtype {
                         return Err(Error::custom(format!(
                             "expected binary subtype {:?} instead got {:?}",
-                            expected_subtype, subtype
+                            expected_subtype, bin.subtype
                         )));
                     }
                 }
 
-                match subtype {
-                    BinarySubtype::Generic => {
-                        visitor.visit_borrowed_bytes(self.bytes.read_slice(len as usize)?)
-                    }
+                match bin.subtype {
+                    BinarySubtype::Generic => visitor.visit_borrowed_bytes(bin.bytes),
                     _ => {
-                        let binary = RawBinaryRef::from_slice_with_len_and_payload(
-                            self.bytes.read_slice(len as usize)?,
-                            len,
-                            subtype,
-                        )?;
-                        let mut d = BinaryDeserializer::new(binary, hint);
+                        let mut d = BinaryDeserializer::new(bin, hint);
                         visitor.visit_map(BinaryAccess {
                             deserializer: &mut d,
                         })
                     }
                 }
             }
-            ElementType::Undefined => {
+            RawBsonRef::Undefined => {
                 visitor.visit_map(RawBsonAccess::new("$undefined", BsonContent::Boolean(true)))
             }
-            ElementType::DateTime => {
-                let dti = read_i64(&mut self.bytes)?;
-                let dt = DateTime::from_millis(dti);
+            RawBsonRef::DateTime(dt) => {
                 let mut d = DateTimeDeserializer::new(dt, hint);
                 visitor.visit_map(DateTimeAccess {
                     deserializer: &mut d,
                 })
             }
-            ElementType::RegularExpression => {
-                let mut de = RegexDeserializer::new(&mut *self);
-                visitor.visit_map(RegexAccess::new(&mut de))
+            RawBsonRef::RegularExpression(re) => {
+                visitor.visit_map(RegexAccess::new(BsonCow::Borrowed(re)))
             }
-            ElementType::DbPointer => {
-                let mut de = DbPointerDeserializer::new(&mut *self, hint);
-                visitor.visit_map(DbPointerAccess::new(&mut de))
+            RawBsonRef::DbPointer(dbp) => {
+                visitor.visit_map(DbPointerAccess::new(BsonCow::Borrowed(dbp), hint))
             }
-            ElementType::JavaScriptCode => {
-                let utf8_lossy = self.bytes.utf8_lossy;
-
-                match hint {
-                    DeserializerHint::RawBson => visitor.visit_map(RawBsonAccess::new(
-                        "$code",
-                        BsonContent::Str(self.bytes.read_borrowed_str()?),
-                    )),
-                    _ => {
-                        let code = read_string(&mut self.bytes, utf8_lossy)?;
-                        visitor.visit_map(MapDeserializer::new(
-                            doc! { "$code": code },
-                            #[allow(deprecated)]
-                            DeserializerOptions::builder().human_readable(false).build(),
-                        ))
-                    }
-                }
+            RawBsonRef::JavaScriptCode(s) => {
+                visitor.visit_map(RawBsonAccess::new("$code", BsonContent::Str(s)))
             }
-            ElementType::JavaScriptCodeWithScope => {
-                let len = read_i32(&mut self.bytes)?;
-
-                if len < MIN_CODE_WITH_SCOPE_SIZE {
-                    return Err(SerdeError::invalid_length(
-                        len.try_into().unwrap_or(0),
-                        &format!(
-                            "CodeWithScope to be at least {} bytes",
-                            MIN_CODE_WITH_SCOPE_SIZE
-                        )
-                        .as_str(),
-                    ));
-                } else if (self.bytes.bytes_remaining() as i32) < len - 4 {
-                    return Err(SerdeError::invalid_length(
-                        len.try_into().unwrap_or(0),
-                        &format!(
-                            "CodeWithScope to be at most {} bytes",
-                            self.bytes.bytes_remaining()
-                        )
-                        .as_str(),
-                    ));
-                }
-
-                let mut de = CodeWithScopeDeserializer::new(&mut *self, hint, len - 4);
-                let out = visitor.visit_map(CodeWithScopeAccess::new(&mut de));
-
-                if de.length_remaining != 0 {
-                    return Err(SerdeError::invalid_length(
-                        len.try_into().unwrap_or(0),
-                        &format!(
-                            "CodeWithScope length {} bytes greater than actual length",
-                            de.length_remaining
-                        )
-                        .as_str(),
-                    ));
-                }
-
-                out
-            }
-            ElementType::Symbol => {
-                let utf8_lossy = self.bytes.utf8_lossy;
-
-                match hint {
-                    DeserializerHint::RawBson => visitor.visit_map(RawBsonAccess::new(
-                        "$symbol",
-                        BsonContent::Str(self.bytes.read_borrowed_str()?),
-                    )),
-                    _ => {
-                        let symbol = read_string(&mut self.bytes, utf8_lossy)?;
-                        visitor.visit_map(MapDeserializer::new(
-                            doc! { "$symbol": symbol },
-                            #[allow(deprecated)]
-                            DeserializerOptions::builder().human_readable(false).build(),
-                        ))
-                    }
-                }
+            RawBsonRef::JavaScriptCodeWithScope(jsc) => visitor.visit_map(
+                CodeWithScopeAccess::new(BsonCow::Borrowed(jsc), hint, self.options.clone()),
+            ),
+            RawBsonRef::Symbol(s) => {
+                visitor.visit_map(RawBsonAccess::new("$symbol", BsonContent::Str(s)))
             }
-            ElementType::Timestamp => {
-                let ts = Timestamp::from_reader(&mut self.bytes)?;
+            RawBsonRef::Timestamp(ts) => {
                 let mut d = TimestampDeserializer::new(ts);
                 visitor.visit_map(TimestampAccess {
                     deserializer: &mut d,
                 })
             }
-            ElementType::Decimal128 => {
-                let d128 = read_f128(&mut self.bytes)?;
-                visitor.visit_map(Decimal128Access::new(d128))
-            }
-            ElementType::MaxKey => {
+            RawBsonRef::Decimal128(d128) => visitor.visit_map(Decimal128Access::new(d128)),
+            RawBsonRef::MaxKey => {
                 visitor.visit_map(RawBsonAccess::new("$maxKey", BsonContent::Int32(1)))
             }
-            ElementType::MinKey => {
+            RawBsonRef::MinKey => {
                 visitor.visit_map(RawBsonAccess::new("$minKey", BsonContent::Int32(1)))
             }
         }
     }
+
+    fn get_string(&self) -> Result<Cow<'de, str>> {
+        if self.options.utf8_lossy {
+            let value = self
+                .element
+                .value_utf8_lossy()
+                .map_err(Error::deserialization)?;
+            let s = match value {
+                Some(Utf8LossyBson::String(s)) => s,
+                _ => {
+                    return Err(Error::deserialization(
+                        "internal error: unexpected non-string",
+                    ))
+                }
+            };
+            Ok(Cow::Owned(s))
+        } else {
+            match self.value()? {
+                RawBsonRef::String(s) => Ok(Cow::Borrowed(s)),
+                _ => Err(Error::deserialization(
+                    "internal error: unexpected non-string",
+                )),
+            }
+        }
+    }
 }
 
-impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
+impl<'de> serde::de::Deserializer<'de> for Deserializer<'de> {
     type Error = Error;
 
     #[inline]
@@ -385,7 +215,7 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
     where
         V: serde::de::Visitor<'de>,
     {
-        self.deserialize_next(visitor, DeserializerHint::None)
+        self.deserialize_hint(visitor, DeserializerHint::None)
     }
 
     #[inline]
@@ -393,7 +223,7 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
     where
         V: serde::de::Visitor<'de>,
     {
-        match self.current_type {
+        match self.element.element_type() {
             ElementType::Null => visitor.visit_none(),
             _ => visitor.visit_some(self),
         }
@@ -401,75 +231,85 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
 
     fn deserialize_enum<V>(
         self,
-        _name: &str,
+        _name: &'static str,
         _variants: &'static [&'static str],
         visitor: V,
-    ) -> Result<V::Value>
+    ) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::Visitor<'de>,
     {
-        match self.current_type {
-            ElementType::String => visitor.visit_enum(self.deserialize_str()?.into_deserializer()),
+        match self.element.element_type() {
+            ElementType::String => visitor.visit_enum(self.get_string()?.into_deserializer()),
             ElementType::EmbeddedDocument => {
-                self.access_document(|access| visitor.visit_enum(access))
+                let doc = match self.value()? {
+                    RawBsonRef::Document(doc) => doc,
+                    _ => {
+                        return Err(Error::deserialization(
+                            "internal error: unexpected non-document",
+                        ))
+                    }
+                };
+                visitor.visit_enum(DocumentAccess::new(doc, self.options.clone())?)
             }
             t => Err(Error::custom(format!("expected enum, instead got {:?}", t))),
         }
     }
 
-    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+    fn deserialize_bytes<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::Visitor<'de>,
     {
-        match self.current_type {
-            ElementType::ObjectId => visitor.visit_borrowed_bytes(self.bytes.read_slice(12)?),
+        match self.element.element_type() {
+            ElementType::ObjectId => visitor.visit_borrowed_bytes(self.element.slice()),
             _ => self.deserialize_any(visitor),
         }
     }
 
-    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+    fn deserialize_newtype_struct<V>(
+        self,
+        name: &'static str,
+        visitor: V,
+    ) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::Visitor<'de>,
     {
         match name {
-            UUID_NEWTYPE_NAME => self.deserialize_next(
+            UUID_NEWTYPE_NAME => self.deserialize_hint(
                 visitor,
                 DeserializerHint::BinarySubtype(BinarySubtype::Uuid),
             ),
-            RAW_BSON_NEWTYPE => self.deserialize_next(visitor, DeserializerHint::RawBson),
+            RAW_BSON_NEWTYPE => self.deserialize_hint(visitor, DeserializerHint::RawBson),
             RAW_DOCUMENT_NEWTYPE => {
-                if self.current_type != ElementType::EmbeddedDocument {
+                if self.element.element_type() != ElementType::EmbeddedDocument {
                     return Err(serde::de::Error::custom(format!(
                         "expected raw document, instead got {:?}",
-                        self.current_type
+                        self.element.element_type()
                     )));
                 }
 
-                self.deserialize_next(visitor, DeserializerHint::RawBson)
+                self.deserialize_hint(visitor, DeserializerHint::RawBson)
             }
             RAW_ARRAY_NEWTYPE => {
-                if self.current_type != ElementType::Array {
+                if self.element.element_type() != ElementType::Array {
                     return Err(serde::de::Error::custom(format!(
                         "expected raw array, instead got {:?}",
-                        self.current_type
+                        self.element.element_type()
                     )));
                 }
 
-                self.deserialize_next(visitor, DeserializerHint::RawBson)
+                self.deserialize_hint(visitor, DeserializerHint::RawBson)
             }
             HUMAN_READABLE_NEWTYPE => {
-                let old = self.human_readable;
-                self.human_readable = true;
-                let result = visitor.visit_newtype_struct(&mut *self);
-                self.human_readable = old;
-                result
+                let mut inner = self;
+                inner.options.human_readable = true;
+                visitor.visit_newtype_struct(inner)
             }
             _ => visitor.visit_newtype_struct(self),
         }
     }
 
     fn is_human_readable(&self) -> bool {
-        self.human_readable
+        self.options.human_readable
     }
 
     forward_to_deserialize_any! {
@@ -479,205 +319,153 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
     }
 }
 
-/// Struct for accessing documents for deserialization purposes.
-/// This is used to deserialize maps, structs, sequences, and enums.
-struct DocumentAccess<'d, 'de> {
-    root_deserializer: &'d mut Deserializer<'de>,
-    length_remaining: &'d mut i32,
+struct DocumentAccess<'de> {
+    iter: RawIter<'de>,
+    elem: Option<RawElement<'de>>,
+    options: DeserializerOptions,
 }
 
-impl<'d, 'de> DocumentAccess<'d, 'de> {
-    /// Read the next element type and update the root deserializer with it.
-    ///
-    /// Returns `Ok(None)` if the document has been fully read and has no more elements.
-    fn read_next_type(&mut self) -> Result<Option<ElementType>> {
-        let t = self.read(|s| s.root_deserializer.deserialize_next_type())?;
-
-        if t.is_none() && *self.length_remaining != 0 {
-            return Err(Error::custom(format!(
-                "got null byte but still have length {} remaining",
-                self.length_remaining
-            )));
-        }
-
-        Ok(t)
+impl<'de> DocumentAccess<'de> {
+    fn new(doc: &'de RawDocument, options: DeserializerOptions) -> Result<Self> {
+        Ok(Self {
+            iter: doc.iter_elements(),
+            elem: None,
+            options,
+        })
     }
 
-    /// Executes a closure that reads from the BSON bytes and returns an error if the number of
-    /// bytes read exceeds length_remaining.
-    ///
-    /// A mutable reference to this [`DocumentAccess`] is passed into the closure.
-    fn read<F, O>(&mut self, f: F) -> Result<O>
-    where
-        F: FnOnce(&mut Self) -> Result<O>,
-    {
-        let start_bytes = self.root_deserializer.bytes.bytes_read();
-        let out = f(self)?;
-        let bytes_read = self.root_deserializer.bytes.bytes_read() - start_bytes;
-        let bytes_read: i32 = bytes_read
-            .try_into()
-            .map_err(|_| Error::custom("overflow in read size"))?;
-        if bytes_read > *self.length_remaining {
-            return Err(Error::custom("length of document too short"));
-        }
-        *self.length_remaining -= bytes_read;
-        Ok(out)
+    fn advance(&mut self) -> Result<()> {
+        self.elem = self
+            .iter
+            .next()
+            .transpose()
+            .map_err(Error::deserialization)?;
+        Ok(())
     }
 
-    /// Read the next value from the document.
-    fn read_next_value<V>(&mut self, seed: V) -> Result<V::Value>
-    where
-        V: serde::de::DeserializeSeed<'de>,
-    {
-        self.read(|s| seed.deserialize(&mut *s.root_deserializer))
+    fn deserializer(self) -> Result<Deserializer<'de>> {
+        let elem = match self.elem {
+            Some(e) => e,
+            None => {
+                return Err(Error::deserialization(
+                    "internal error: no element for deserializer",
+                ))
+            }
+        };
+        Ok(Deserializer {
+            element: elem,
+            options: self.options,
+        })
     }
 }
 
-impl<'d, 'de> serde::de::MapAccess<'de> for DocumentAccess<'d, 'de> {
-    type Error = crate::de::Error;
+impl<'de> serde::de::MapAccess<'de> for DocumentAccess<'de> {
+    type Error = Error;
 
-    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
+    fn next_key_seed<K>(&mut self, seed: K) -> std::result::Result<Option<K::Value>, Self::Error>
     where
         K: serde::de::DeserializeSeed<'de>,
     {
-        if self.read_next_type()?.is_none() {
-            return Ok(None);
+        self.advance()?;
+        match &self.elem {
+            None => Ok(None),
+            Some(elem) => seed
+                .deserialize(BorrowedStrDeserializer::new(elem.key()))
+                .map(Some),
         }
-
-        self.read(|s| {
-            seed.deserialize(DocumentKeyDeserializer {
-                root_deserializer: &mut *s.root_deserializer,
-            })
-        })
-        .map(Some)
     }
 
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+    fn next_value_seed<V>(&mut self, seed: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::DeserializeSeed<'de>,
     {
-        self.read_next_value(seed)
+        match &self.elem {
+            None => Err(Error::deserialization("too many values requested")),
+            Some(elem) => seed.deserialize(Deserializer {
+                element: elem.clone(),
+                options: self.options.clone(),
+            }),
+        }
     }
 }
 
-impl<'d, 'de> serde::de::SeqAccess<'de> for DocumentAccess<'d, 'de> {
+impl<'de> serde::de::SeqAccess<'de> for DocumentAccess<'de> {
     type Error = Error;
 
-    fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>>
+    fn next_element_seed<T>(
+        &mut self,
+        seed: T,
+    ) -> std::result::Result<Option<T::Value>, Self::Error>
     where
-        S: serde::de::DeserializeSeed<'de>,
+        T: serde::de::DeserializeSeed<'de>,
     {
-        if self.read_next_type()?.is_none() {
-            return Ok(None);
+        self.advance()?;
+        match &self.elem {
+            None => Ok(None),
+            Some(elem) => seed
+                .deserialize(Deserializer {
+                    element: elem.clone(),
+                    options: self.options.clone(),
+                })
+                .map(Some),
         }
-        let _index = self.read(|s| s.root_deserializer.deserialize_cstr())?;
-        self.read_next_value(seed).map(Some)
     }
 }
 
-impl<'d, 'de> EnumAccess<'de> for DocumentAccess<'d, 'de> {
+impl<'de> serde::de::EnumAccess<'de> for DocumentAccess<'de> {
     type Error = Error;
     type Variant = Self;
 
-    fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant)>
+    fn variant_seed<V>(
+        mut self,
+        seed: V,
+    ) -> std::result::Result<(V::Value, Self::Variant), Self::Error>
     where
         V: serde::de::DeserializeSeed<'de>,
     {
-        if self.read_next_type()?.is_none() {
-            return Err(Error::EndOfStream);
-        }
-
-        let key = self.read(|s| {
-            seed.deserialize(DocumentKeyDeserializer {
-                root_deserializer: &mut *s.root_deserializer,
-            })
-        })?;
-
+        self.advance()?;
+        let elem = match &self.elem {
+            Some(e) => e,
+            None => return Err(Error::EndOfStream),
+        };
+        let de: BorrowedStrDeserializer<'_, Error> = BorrowedStrDeserializer::new(elem.key());
+        let key = seed.deserialize(de)?;
         Ok((key, self))
     }
 }
 
-impl<'d, 'de> VariantAccess<'de> for DocumentAccess<'d, 'de> {
+impl<'de> serde::de::VariantAccess<'de> for DocumentAccess<'de> {
     type Error = Error;
 
-    fn unit_variant(self) -> Result<()> {
+    fn unit_variant(self) -> std::result::Result<(), Self::Error> {
         Err(Error::custom(
             "expected a string enum, got a document instead",
         ))
     }
 
-    fn newtype_variant_seed<S>(mut self, seed: S) -> Result<S::Value>
+    fn newtype_variant_seed<T>(self, seed: T) -> std::result::Result<T::Value, Self::Error>
     where
-        S: serde::de::DeserializeSeed<'de>,
+        T: serde::de::DeserializeSeed<'de>,
     {
-        self.read_next_value(seed)
+        seed.deserialize(self.deserializer()?)
     }
 
-    fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> Result<V::Value>
+    fn tuple_variant<V>(self, _len: usize, visitor: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::Visitor<'de>,
     {
-        self.read(|s| s.root_deserializer.deserialize_seq(visitor))
+        self.deserializer()?.deserialize_seq(visitor)
     }
 
-    fn struct_variant<V>(mut self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
-    where
-        V: serde::de::Visitor<'de>,
-    {
-        self.read(|s| s.root_deserializer.deserialize_map(visitor))
-    }
-}
-
-/// Deserializer used specifically for deserializing a document's cstring keys.
-struct DocumentKeyDeserializer<'d, 'de> {
-    root_deserializer: &'d mut Deserializer<'de>,
-}
-
-impl<'d, 'de> serde::de::Deserializer<'de> for DocumentKeyDeserializer<'d, 'de> {
-    type Error = Error;
-
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
-    where
-        V: serde::de::Visitor<'de>,
-    {
-        let s = self.root_deserializer.deserialize_cstr()?;
-        match s {
-            Cow::Borrowed(b) => visitor.visit_borrowed_str(b),
-            Cow::Owned(string) => visitor.visit_string(string),
-        }
-    }
-
-    fn deserialize_enum<V>(
+    fn struct_variant<V>(
         self,
-        _name: &str,
-        _variants: &'static [&'static str],
+        _fields: &'static [&'static str],
         visitor: V,
-    ) -> Result<V::Value>
-    where
-        V: serde::de::Visitor<'de>,
-    {
-        visitor.visit_enum(
-            self.root_deserializer
-                .deserialize_cstr()?
-                .into_deserializer(),
-        )
-    }
-
-    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
+    ) -> std::result::Result<V::Value, Self::Error>
     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 seq tuple tuple_struct struct map
-        ignored_any i8 i16 i32 i64 u8 u16 u32 u64 f32 f64
+        self.deserializer()?.deserialize_map(visitor)
     }
 }
 
@@ -1251,84 +1039,58 @@ enum BinaryDeserializationStage {
 ///
 /// Otherwise, this deserializes the serde data model equivalent of
 /// { "$code": <borrowed str> "$scope": <map> }.
-struct CodeWithScopeAccess<'de, 'd, 'a> {
-    deserializer: &'a mut CodeWithScopeDeserializer<'de, 'd>,
+struct CodeWithScopeAccess<'de> {
+    cws: BsonCow<RawJavaScriptCodeWithScopeRef<'de>, Utf8LossyJavaScriptCodeWithScope<'de>>,
+    hint: DeserializerHint,
+    options: DeserializerOptions,
+    stage: CodeWithScopeDeserializationStage,
 }
 
-impl<'de, 'd, 'a> CodeWithScopeAccess<'de, 'd, 'a> {
-    fn new(deserializer: &'a mut CodeWithScopeDeserializer<'de, 'd>) -> Self {
-        Self { deserializer }
+impl<'de> CodeWithScopeAccess<'de> {
+    fn new(
+        cws: BsonCow<RawJavaScriptCodeWithScopeRef<'de>, Utf8LossyJavaScriptCodeWithScope<'de>>,
+        hint: DeserializerHint,
+        options: DeserializerOptions,
+    ) -> Self {
+        Self {
+            cws,
+            hint,
+            options,
+            stage: CodeWithScopeDeserializationStage::Code,
+        }
     }
 }
 
-impl<'de, 'd, 'a> serde::de::MapAccess<'de> for CodeWithScopeAccess<'de, 'd, 'a> {
+impl<'de> serde::de::MapAccess<'de> for CodeWithScopeAccess<'de> {
     type Error = Error;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
     where
         K: serde::de::DeserializeSeed<'de>,
     {
-        match self.deserializer.stage {
-            CodeWithScopeDeserializationStage::Code => seed
-                .deserialize(FieldDeserializer {
-                    field_name: "$code",
-                })
-                .map(Some),
-            CodeWithScopeDeserializationStage::Scope => seed
-                .deserialize(FieldDeserializer {
-                    field_name: "$scope",
-                })
-                .map(Some),
-            CodeWithScopeDeserializationStage::Done => Ok(None),
-        }
+        let field_name = match self.stage {
+            CodeWithScopeDeserializationStage::Code => "$code",
+            CodeWithScopeDeserializationStage::Scope => "$scope",
+            CodeWithScopeDeserializationStage::Done => return Ok(None),
+        };
+        seed.deserialize(FieldDeserializer { field_name }).map(Some)
     }
 
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+    fn next_value_seed<V>(&mut self, seed: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::DeserializeSeed<'de>,
     {
-        seed.deserialize(&mut *self.deserializer)
-    }
-}
-
-struct CodeWithScopeDeserializer<'de, 'a> {
-    root_deserializer: &'a mut Deserializer<'de>,
-    stage: CodeWithScopeDeserializationStage,
-    hint: DeserializerHint,
-    length_remaining: i32,
-}
-
-impl<'de, 'a> CodeWithScopeDeserializer<'de, 'a> {
-    fn new(root_deserializer: &'a mut Deserializer<'de>, hint: DeserializerHint, len: i32) -> Self {
-        Self {
-            root_deserializer,
-            stage: CodeWithScopeDeserializationStage::Code,
-            hint,
-            length_remaining: len,
-        }
-    }
-
-    /// Executes a closure that reads from the BSON bytes and returns an error if the number of
-    /// bytes read exceeds length_remaining.
-    ///
-    /// A mutable reference to this [`CodeWithScopeDeserializer`] is passed into the closure.
-    fn read<F, O>(&mut self, f: F) -> Result<O>
-    where
-        F: FnOnce(&mut Self) -> Result<O>,
-    {
-        let start_bytes = self.root_deserializer.bytes.bytes_read();
-        let out = f(self)?;
-        let bytes_read = self.root_deserializer.bytes.bytes_read() - start_bytes;
-        self.length_remaining -= bytes_read as i32;
-
-        if self.length_remaining < 0 {
-            return Err(Error::custom("length of CodeWithScope too short"));
-        }
-        Ok(out)
+        let value = seed.deserialize(&*self)?;
+        self.stage = match self.stage {
+            CodeWithScopeDeserializationStage::Code => CodeWithScopeDeserializationStage::Scope,
+            CodeWithScopeDeserializationStage::Scope => CodeWithScopeDeserializationStage::Done,
+            CodeWithScopeDeserializationStage::Done => return Err(Error::EndOfStream),
+        };
+        Ok(value)
     }
 }
 
-impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserializer<'de, 'a> {
+impl<'a, 'de> serde::de::Deserializer<'de> for &'a CodeWithScopeAccess<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
@@ -1336,26 +1098,21 @@ impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserial
         V: serde::de::Visitor<'de>,
     {
         match self.stage {
-            CodeWithScopeDeserializationStage::Code => {
-                self.stage = CodeWithScopeDeserializationStage::Scope;
-                match self.read(|s| s.root_deserializer.deserialize_str())? {
-                    Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
-                    Cow::Owned(s) => visitor.visit_string(s),
-                }
-            }
+            CodeWithScopeDeserializationStage::Code => match &self.cws {
+                BsonCow::Borrowed(cws) => visitor.visit_borrowed_str(cws.code),
+                BsonCow::Owned(cws) => visitor.visit_str(&cws.code),
+            },
             CodeWithScopeDeserializationStage::Scope => {
-                self.stage = CodeWithScopeDeserializationStage::Done;
-                self.read(|s| {
-                    s.root_deserializer.deserialize_document(
-                        visitor,
-                        s.hint,
-                        DocumentType::EmbeddedDocument,
-                    )
-                })
+                let scope = match &self.cws {
+                    BsonCow::Borrowed(cws) => cws.scope,
+                    BsonCow::Owned(cws) => cws.scope,
+                };
+                match self.hint {
+                    DeserializerHint::RawBson => visitor.visit_map(RawDocumentAccess::new(scope)),
+                    _ => visitor.visit_map(DocumentAccess::new(scope, self.options.clone())?),
+                }
             }
-            CodeWithScopeDeserializationStage::Done => Err(Error::custom(
-                "JavaScriptCodeWithScope fully deserialized already",
-            )),
+            CodeWithScopeDeserializationStage::Done => Err(Error::EndOfStream),
         }
     }
 
@@ -1367,7 +1124,7 @@ impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserial
     }
 
     fn is_human_readable(&self) -> bool {
-        false
+        self.options.human_readable
     }
 
     serde::forward_to_deserialize_any! {
@@ -1388,86 +1145,77 @@ enum CodeWithScopeDeserializationStage {
 ///
 /// Regardless of the hint, this deserializes the serde data model equivalent
 /// of { "$dbPointer": { "$ref": <borrowed str>, "$id": <bytes> } }.
-struct DbPointerAccess<'de, 'd, 'a> {
-    deserializer: &'a mut DbPointerDeserializer<'de, 'd>,
+struct DbPointerAccess<'de> {
+    dbp: BsonCow<RawDbPointerRef<'de>, DbPointer>,
+    hint: DeserializerHint,
+    stage: DbPointerDeserializationStage,
 }
 
-impl<'de, 'd, 'a> DbPointerAccess<'de, 'd, 'a> {
-    fn new(deserializer: &'a mut DbPointerDeserializer<'de, 'd>) -> Self {
-        Self { deserializer }
+impl<'de> DbPointerAccess<'de> {
+    fn new(dbp: BsonCow<RawDbPointerRef<'de>, DbPointer>, hint: DeserializerHint) -> Self {
+        Self {
+            dbp,
+            hint,
+            stage: DbPointerDeserializationStage::TopLevel,
+        }
     }
 }
 
-impl<'de, 'd, 'a> serde::de::MapAccess<'de> for DbPointerAccess<'de, 'd, 'a> {
+impl<'de> serde::de::MapAccess<'de> for DbPointerAccess<'de> {
     type Error = Error;
 
-    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
+    fn next_key_seed<K>(&mut self, seed: K) -> std::result::Result<Option<K::Value>, Self::Error>
     where
         K: serde::de::DeserializeSeed<'de>,
     {
-        match self.deserializer.stage {
-            DbPointerDeserializationStage::TopLevel => seed
-                .deserialize(FieldDeserializer {
-                    field_name: "$dbPointer",
-                })
-                .map(Some),
-            DbPointerDeserializationStage::Namespace => seed
-                .deserialize(FieldDeserializer { field_name: "$ref" })
-                .map(Some),
-            DbPointerDeserializationStage::Id => seed
-                .deserialize(FieldDeserializer { field_name: "$id" })
-                .map(Some),
-            DbPointerDeserializationStage::Done => Ok(None),
-        }
+        let name = match self.stage {
+            DbPointerDeserializationStage::TopLevel => "$dbPointer",
+            DbPointerDeserializationStage::Namespace => "$ref",
+            DbPointerDeserializationStage::Id => "$id",
+            DbPointerDeserializationStage::Done => return Ok(None),
+        };
+        seed.deserialize(FieldDeserializer { field_name: name })
+            .map(Some)
     }
 
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+    fn next_value_seed<V>(&mut self, seed: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::DeserializeSeed<'de>,
     {
-        seed.deserialize(&mut *self.deserializer)
+        seed.deserialize(self)
     }
 }
 
-struct DbPointerDeserializer<'de, 'a> {
-    root_deserializer: &'a mut Deserializer<'de>,
-    stage: DbPointerDeserializationStage,
-    hint: DeserializerHint,
-}
-
-impl<'de, 'a> DbPointerDeserializer<'de, 'a> {
-    fn new(root_deserializer: &'a mut Deserializer<'de>, hint: DeserializerHint) -> Self {
-        Self {
-            root_deserializer,
-            stage: DbPointerDeserializationStage::TopLevel,
-            hint,
-        }
-    }
-}
-
-impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut DbPointerDeserializer<'de, 'a> {
+impl<'a, 'de> serde::de::Deserializer<'de> for &'a mut DbPointerAccess<'de> {
     type Error = Error;
 
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::Visitor<'de>,
     {
         match self.stage {
             DbPointerDeserializationStage::TopLevel => {
-                self.stage = DbPointerDeserializationStage::Namespace;
-                visitor.visit_map(DbPointerAccess::new(self))
+                self.stage = DbPointerDeserializationStage::Done;
+                visitor.visit_map(DbPointerAccess {
+                    dbp: self.dbp.clone(),
+                    hint: self.hint,
+                    stage: DbPointerDeserializationStage::Namespace,
+                })
             }
             DbPointerDeserializationStage::Namespace => {
                 self.stage = DbPointerDeserializationStage::Id;
-                match self.root_deserializer.deserialize_str()? {
-                    Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
-                    Cow::Owned(s) => visitor.visit_string(s),
+                match &self.dbp {
+                    BsonCow::Borrowed(dbp) => visitor.visit_borrowed_str(dbp.namespace),
+                    BsonCow::Owned(dbp) => visitor.visit_str(&dbp.namespace),
                 }
             }
             DbPointerDeserializationStage::Id => {
                 self.stage = DbPointerDeserializationStage::Done;
-                self.root_deserializer
-                    .deserialize_objectid(visitor, self.hint)
+                let oid = match &self.dbp {
+                    BsonCow::Borrowed(dbp) => dbp.id,
+                    BsonCow::Owned(dbp) => dbp.id,
+                };
+                visitor.visit_map(ObjectIdAccess::new(oid, self.hint))
             }
             DbPointerDeserializationStage::Done => {
                 Err(Error::custom("DbPointer fully deserialized already"))
@@ -1505,66 +1253,49 @@ enum DbPointerDeserializationStage {
 ///
 /// Regardless of the hint, this deserializes the serde data model equivalent
 /// of { "$regularExpression": { "pattern": <borrowed str>, "options": <borrowed str> } }.
-struct RegexAccess<'de, 'd, 'a> {
-    deserializer: &'a mut RegexDeserializer<'de, 'd>,
+struct RegexAccess<'de> {
+    re: BsonCow<RawRegexRef<'de>, Regex>,
+    stage: RegexDeserializationStage,
 }
 
-impl<'de, 'd, 'a> RegexAccess<'de, 'd, 'a> {
-    fn new(deserializer: &'a mut RegexDeserializer<'de, 'd>) -> Self {
-        Self { deserializer }
+impl<'de> RegexAccess<'de> {
+    fn new(re: BsonCow<RawRegexRef<'de>, Regex>) -> Self {
+        Self {
+            re,
+            stage: RegexDeserializationStage::TopLevel,
+        }
     }
 }
 
-impl<'de, 'd, 'a> serde::de::MapAccess<'de> for RegexAccess<'de, 'd, 'a> {
+impl<'de> serde::de::MapAccess<'de> for RegexAccess<'de> {
     type Error = Error;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
     where
         K: serde::de::DeserializeSeed<'de>,
     {
-        match self.deserializer.stage {
-            RegexDeserializationStage::TopLevel => seed
-                .deserialize(FieldDeserializer {
-                    field_name: "$regularExpression",
-                })
-                .map(Some),
-            RegexDeserializationStage::Pattern => seed
-                .deserialize(FieldDeserializer {
-                    field_name: "pattern",
-                })
-                .map(Some),
-            RegexDeserializationStage::Options => seed
-                .deserialize(FieldDeserializer {
-                    field_name: "options",
-                })
-                .map(Some),
-            RegexDeserializationStage::Done => Ok(None),
-        }
+        let name = match self.stage {
+            RegexDeserializationStage::TopLevel => "$regularExpression",
+            RegexDeserializationStage::Pattern => "pattern",
+            RegexDeserializationStage::Options => "options",
+            RegexDeserializationStage::Done => return Ok(None),
+        };
+        seed.deserialize(FieldDeserializer { field_name: name })
+            .map(Some)
     }
 
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
+    fn next_value_seed<V>(&mut self, seed: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: serde::de::DeserializeSeed<'de>,
     {
-        seed.deserialize(&mut *self.deserializer)
-    }
-}
-
-struct RegexDeserializer<'de, 'a> {
-    root_deserializer: &'a mut Deserializer<'de>,
-    stage: RegexDeserializationStage,
-}
-
-impl<'de, 'a> RegexDeserializer<'de, 'a> {
-    fn new(root_deserializer: &'a mut Deserializer<'de>) -> Self {
-        Self {
-            root_deserializer,
-            stage: RegexDeserializationStage::TopLevel,
+        if matches!(self.stage, RegexDeserializationStage::Done) {
+            return Err(Error::custom("Regex fully deserialized already"));
         }
+        seed.deserialize(self)
     }
 }
 
-impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut RegexDeserializer<'de, 'a> {
+impl<'a, 'de> serde::de::Deserializer<'de> for &'a mut RegexAccess<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
@@ -1573,29 +1304,46 @@ impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut RegexDeserializer<'de
     {
         match self.stage {
             RegexDeserializationStage::TopLevel => {
-                self.stage.advance();
-                visitor.visit_map(RegexAccess::new(self))
+                self.stage = RegexDeserializationStage::Done;
+                visitor.visit_map(RegexAccess {
+                    re: self.re.clone(),
+                    stage: RegexDeserializationStage::Pattern,
+                })
+            }
+            RegexDeserializationStage::Pattern => {
+                self.stage = RegexDeserializationStage::Options;
+                match &self.re {
+                    BsonCow::Borrowed(re) => visitor.visit_borrowed_str(re.pattern),
+                    BsonCow::Owned(re) => visitor.visit_str(&re.pattern),
+                }
             }
-            RegexDeserializationStage::Pattern | RegexDeserializationStage::Options => {
-                self.stage.advance();
-                match self.root_deserializer.deserialize_cstr()? {
-                    Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
-                    Cow::Owned(s) => visitor.visit_string(s),
+            RegexDeserializationStage::Options => {
+                self.stage = RegexDeserializationStage::Done;
+                match &self.re {
+                    BsonCow::Borrowed(re) => visitor.visit_borrowed_str(re.options),
+                    BsonCow::Owned(re) => visitor.visit_str(&re.options),
                 }
             }
             RegexDeserializationStage::Done => {
-                Err(Error::custom("DbPointer fully deserialized already"))
+                Err(Error::custom("Regex fully deserialized already"))
             }
         }
     }
 
+    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
+    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
     }
 }
@@ -1608,17 +1356,6 @@ enum RegexDeserializationStage {
     Done,
 }
 
-impl RegexDeserializationStage {
-    fn advance(&mut self) {
-        *self = match self {
-            RegexDeserializationStage::TopLevel => RegexDeserializationStage::Pattern,
-            RegexDeserializationStage::Pattern => RegexDeserializationStage::Options,
-            RegexDeserializationStage::Options => RegexDeserializationStage::Done,
-            RegexDeserializationStage::Done => RegexDeserializationStage::Done,
-        }
-    }
-}
-
 /// Helper access struct for visiting the extended JSON model of simple BSON types.
 /// e.g. Symbol, Timestamp, etc.
 struct RawBsonAccess<'a> {
@@ -1708,137 +1445,8 @@ impl<'de> serde::de::Deserializer<'de> for RawBsonDeserializer<'de> {
     }
 }
 
-/// Struct wrapping a slice of BSON bytes.
-struct BsonBuf<'a> {
-    bytes: &'a [u8],
-    index: usize,
-
-    /// Whether or not to insert replacement characters in place of invalid UTF-8 sequences when
-    /// deserializing strings.
-    utf8_lossy: bool,
-}
-
-impl<'a> Read for BsonBuf<'a> {
-    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
-        self.index_check()?;
-        let bytes_read = self.bytes[self.index..].as_ref().read(buf)?;
-        self.index += bytes_read;
-        Ok(bytes_read)
-    }
-}
-
-impl<'a> BsonBuf<'a> {
-    fn new(bytes: &'a [u8], utf8_lossy: bool) -> Self {
-        Self {
-            bytes,
-            index: 0,
-            utf8_lossy,
-        }
-    }
-
-    fn bytes_read(&self) -> usize {
-        self.index
-    }
-
-    fn bytes_remaining(&self) -> usize {
-        self.bytes.len() - self.bytes_read()
-    }
-
-    /// Verify the index has not run out of bounds.
-    fn index_check(&self) -> std::io::Result<()> {
-        if self.index >= self.bytes.len() {
-            return Err(ErrorKind::UnexpectedEof.into());
-        }
-        Ok(())
-    }
-
-    /// Get the string starting at the provided index and ending at the buffer's current index.
-    ///
-    /// Can optionally override the global UTF-8 lossy setting to ensure bytes are not allocated.
-    fn str(&mut self, start: usize, utf8_lossy_override: Option<bool>) -> Result<Cow<'a, str>> {
-        let bytes = &self.bytes[start..self.index];
-        let s = if utf8_lossy_override.unwrap_or(self.utf8_lossy) {
-            String::from_utf8_lossy(bytes)
-        } else {
-            Cow::Borrowed(std::str::from_utf8(bytes).map_err(Error::custom)?)
-        };
-
-        // consume the null byte
-        if self.bytes[self.index] != 0 {
-            return Err(Error::custom("string was not null-terminated"));
-        }
-        self.index += 1;
-        self.index_check()?;
-
-        Ok(s)
-    }
-
-    /// Attempts to read a null-terminated UTF-8 cstring from the data.
-    ///
-    /// If utf8_lossy and invalid UTF-8 is encountered, the unicode replacement character will be
-    /// inserted in place of the offending data, resulting in an owned [`String`]. Otherwise, the
-    /// data will be borrowed as-is.
-    fn read_cstr(&mut self) -> Result<Cow<'a, str>> {
-        let start = self.index;
-        while self.index < self.bytes.len() && self.bytes[self.index] != 0 {
-            self.index += 1
-        }
-
-        self.index_check()?;
-
-        self.str(start, None)
-    }
-
-    fn _advance_to_len_encoded_str(&mut self) -> Result<usize> {
-        let len = read_i32(self)?;
-        let start = self.index;
-
-        // UTF-8 String must have at least 1 byte (the last 0x00).
-        if len < 1 {
-            return Err(Error::invalid_length(
-                len as usize,
-                &"UTF-8 string must have at least 1 byte",
-            ));
-        }
-
-        self.index += (len - 1) as usize;
-        self.index_check()?;
-
-        Ok(start)
-    }
-
-    /// Attempts to read a null-terminated UTF-8 string from the data.
-    ///
-    /// If invalid UTF-8 is encountered, the unicode replacement character will be inserted in place
-    /// of the offending data, resulting in an owned [`String`]. Otherwise, the data will be
-    /// borrowed as-is.
-    fn read_str(&mut self) -> Result<Cow<'a, str>> {
-        let start = self._advance_to_len_encoded_str()?;
-        self.str(start, None)
-    }
-
-    /// Attempts to read a null-terminated UTF-8 string from the data.
-    fn read_borrowed_str(&mut self) -> Result<&'a str> {
-        let start = self._advance_to_len_encoded_str()?;
-        match self.str(start, Some(false))? {
-            Cow::Borrowed(s) => Ok(s),
-            Cow::Owned(_) => panic!("should have errored when encountering invalid UTF-8"),
-        }
-    }
-
-    fn slice(&self, length: usize) -> Result<&'a [u8]> {
-        if self.index + length > self.bytes.len() {
-            return Err(Error::Io(Arc::new(
-                std::io::ErrorKind::UnexpectedEof.into(),
-            )));
-        }
-
-        Ok(&self.bytes[self.index..(self.index + length)])
-    }
-
-    fn read_slice(&mut self, length: usize) -> Result<&'a [u8]> {
-        let slice = self.slice(length)?;
-        self.index += length;
-        Ok(slice)
-    }
+#[derive(Debug, Copy, Clone)]
+enum BsonCow<Borrowed, Owned> {
+    Borrowed(Borrowed),
+    Owned(Owned),
 }
diff --git a/src/document.rs b/src/document.rs
index f11643d9..e073b386 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -564,8 +564,8 @@ impl Document {
         let mut buf = vec![0u8; ulen];
         buf[0..4].copy_from_slice(&length.to_le_bytes());
         reader.read_exact(&mut buf[4..])?;
-        let mut deserializer = crate::de::RawDeserializer::new(&buf, utf_lossy);
-        Document::deserialize(&mut deserializer)
+        let deserializer = crate::de::RawDeserializer::new(&buf, utf_lossy)?;
+        Document::deserialize(deserializer)
     }
 
     /// Attempts to deserialize a [`Document`] from a byte stream.
diff --git a/src/raw/array.rs b/src/raw/array.rs
index 497e820c..dd13164c 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -92,6 +92,10 @@ impl RawArray {
         unsafe { &*(doc as *const RawDocument as *const RawArray) }
     }
 
+    pub(crate) fn as_doc(&self) -> &RawDocument {
+        &self.doc
+    }
+
     /// Convert this borrowed [`RawArray`] into an owned [`RawArrayBuf`].
     ///
     /// This involves a traversal of the array to count the values.
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 7132db92..bebd4b24 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -515,7 +515,7 @@ impl RawDocument {
         self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize
     }
 
-    pub(crate) fn read_cstring_at(&self, start_at: usize) -> Result<&str> {
+    pub(crate) fn cstring_bytes_at(&self, start_at: usize) -> Result<&[u8]> {
         let buf = &self.as_bytes()[start_at..];
 
         let mut splits = buf.splitn(2, |x| *x == 0);
@@ -523,13 +523,18 @@ impl RawDocument {
             .next()
             .ok_or_else(|| Error::new_without_key(ErrorKind::new_malformed("no value")))?;
         if splits.next().is_some() {
-            Ok(try_to_str(value)?)
+            Ok(value)
         } else {
             Err(Error::new_without_key(ErrorKind::new_malformed(
                 "expected null terminator",
             )))
         }
     }
+
+    pub(crate) fn read_cstring_at(&self, start_at: usize) -> Result<&str> {
+        let bytes = self.cstring_bytes_at(start_at)?;
+        try_to_str(bytes)
+    }
 }
 
 impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 01667b87..410c68d0 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -25,6 +25,7 @@ use super::{
     i64_from_slice,
     read_len,
     read_lenencode,
+    read_lenencode_bytes,
     try_to_str,
     RawBsonRef,
     RawDocument,
@@ -146,6 +147,16 @@ impl<'a> TryInto<Bson> for RawElement<'a> {
 
 #[allow(clippy::len_without_is_empty)]
 impl<'a> RawElement<'a> {
+    pub(crate) fn toplevel(bytes: &'a [u8]) -> Result<Self> {
+        let doc = RawDocument::from_bytes(bytes)?;
+        Ok(Self {
+            key: "TOPLEVEL",
+            kind: ElementType::EmbeddedDocument,
+            doc,
+            start_at: 0,
+            size: doc.as_bytes().len(),
+        })
+    }
     pub fn len(&self) -> usize {
         self.size
     }
@@ -256,11 +267,52 @@ impl<'a> RawElement<'a> {
         })
     }
 
+    pub(crate) fn value_utf8_lossy(&self) -> Result<Option<Utf8LossyBson<'a>>> {
+        Ok(Some(match self.kind {
+            ElementType::String => Utf8LossyBson::String(self.read_utf8_lossy()),
+            ElementType::JavaScriptCode => Utf8LossyBson::JavaScriptCode(self.read_utf8_lossy()),
+            ElementType::JavaScriptCodeWithScope => {
+                if self.size < MIN_CODE_WITH_SCOPE_SIZE as usize {
+                    return Err(self.malformed_error("code with scope length too small"));
+                }
+
+                let slice = self.slice();
+                let code = String::from_utf8_lossy(read_lenencode_bytes(&slice[4..])?).into_owned();
+                let scope_start = 4 + 4 + code.len() + 1;
+                let scope = RawDocument::from_bytes(&slice[scope_start..])?;
+
+                Utf8LossyBson::JavaScriptCodeWithScope(Utf8LossyJavaScriptCodeWithScope {
+                    code,
+                    scope,
+                })
+            }
+            ElementType::Symbol => Utf8LossyBson::Symbol(self.read_utf8_lossy()),
+            ElementType::DbPointer => Utf8LossyBson::DbPointer(crate::DbPointer {
+                namespace: String::from_utf8_lossy(read_lenencode_bytes(self.slice())?)
+                    .into_owned(),
+                id: self.get_oid_at(self.start_at + (self.size - 12))?,
+            }),
+            ElementType::RegularExpression => {
+                let pattern =
+                    String::from_utf8_lossy(self.doc.cstring_bytes_at(self.start_at)?).into_owned();
+                let pattern_len = pattern.len();
+                Utf8LossyBson::RegularExpression(crate::Regex {
+                    pattern,
+                    options: String::from_utf8_lossy(
+                        self.doc.cstring_bytes_at(self.start_at + pattern_len + 1)?,
+                    )
+                    .into_owned(),
+                })
+            }
+            _ => return Ok(None),
+        }))
+    }
+
     fn malformed_error(&self, e: impl ToString) -> Error {
         Error::new_with_key(self.key, ErrorKind::new_malformed(e))
     }
 
-    fn slice(&self) -> &'a [u8] {
+    pub(crate) fn slice(&self) -> &'a [u8] {
         self.slice_bounds(self.start_at, self.size)
     }
 
@@ -268,8 +320,16 @@ impl<'a> RawElement<'a> {
         &self.doc.as_bytes()[start_at..(start_at + size)]
     }
 
+    fn str_bytes(&self) -> &'a [u8] {
+        self.slice_bounds(self.start_at + 4, self.size - 4 - 1)
+    }
+
     fn read_str(&self) -> Result<&'a str> {
-        try_to_str(self.slice_bounds(self.start_at + 4, self.size - 4 - 1))
+        try_to_str(self.str_bytes())
+    }
+
+    fn read_utf8_lossy(&self) -> String {
+        String::from_utf8_lossy(self.str_bytes()).into_owned()
     }
 
     fn get_oid_at(&self, start_at: usize) -> Result<ObjectId> {
@@ -390,3 +450,17 @@ impl<'a> Iterator for RawIter<'a> {
         })
     }
 }
+
+pub(crate) enum Utf8LossyBson<'a> {
+    String(String),
+    JavaScriptCode(String),
+    JavaScriptCodeWithScope(Utf8LossyJavaScriptCodeWithScope<'a>),
+    Symbol(String),
+    DbPointer(crate::DbPointer),
+    RegularExpression(crate::Regex),
+}
+
+pub(crate) struct Utf8LossyJavaScriptCodeWithScope<'a> {
+    pub(crate) code: String,
+    pub(crate) scope: &'a RawDocument,
+}
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index 8a503634..b8c1ea54 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -145,6 +145,8 @@ pub use self::{
     iter::{RawElement, RawIter},
 };
 
+pub(crate) use self::iter::{Utf8LossyBson, Utf8LossyJavaScriptCodeWithScope};
+
 /// 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";
 
@@ -237,11 +239,15 @@ fn read_len(buf: &[u8]) -> Result<usize> {
     Ok(length as usize + 4)
 }
 
-fn read_lenencode(buf: &[u8]) -> Result<&str> {
+fn read_lenencode_bytes(buf: &[u8]) -> Result<&[u8]> {
     let end = read_len(buf)?;
 
     // exclude length-prefix and null byte suffix
-    try_to_str(&buf[4..(end - 1)])
+    Ok(&buf[4..(end - 1)])
+}
+
+fn read_lenencode(buf: &[u8]) -> Result<&str> {
+    try_to_str(read_lenencode_bytes(buf)?)
 }
 
 fn try_to_str(data: &[u8]) -> Result<&str> {
diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs
index 250141d6..67b42732 100644
--- a/src/raw/test/mod.rs
+++ b/src/raw/test/mod.rs
@@ -462,6 +462,14 @@ fn into_bson_conversion() {
     );
 }
 
+#[test]
+fn fuzz_oom() {
+    let bytes: &[u8] = &[
+        17, 0, 0, 0, 11, 36, 100, 97, 116, 101, 0, 111, 112, 101, 0, 4, 0,
+    ];
+    let _ = crate::from_slice::<crate::Document>(bytes);
+}
+
 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 98fc23a0..95e63988 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -175,8 +175,8 @@ fn run_test(test: TestFile) {
             // skip regex tests that don't have the value at the test key
             if !description.contains("$regex query operator") {
                 // deserialize the field from raw Bytes into a RawBson
-                let mut deserializer_raw =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false);
+                let deserializer_raw =
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false).unwrap();
                 let raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBsonRef>))
                     .expect(&description);
@@ -187,8 +187,8 @@ fn run_test(test: TestFile) {
                 };
 
                 // deserialize the field from raw Bytes into an OwnedRawBson
-                let mut deserializer_raw =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false);
+                let deserializer_raw =
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false).unwrap();
                 let owned_raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
                     .expect(&description);
@@ -196,8 +196,8 @@ fn run_test(test: TestFile) {
                     RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_bytes();
 
                 // deserialize the field from raw Bytes into a Bson
-                let mut deserializer_value =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false);
+                let deserializer_value =
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false).unwrap();
                 let bson_field = deserializer_value
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<Bson>))
                     .expect(&description);

From 1c6e65a27aeeb9e4d8442ba2b268e3690766bb9a Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 23 Jul 2024 16:08:51 -0400
Subject: [PATCH 071/156] RUST-1992 Minor parsing cleanup (#485)

---
 src/de/error.rs     |  6 +++
 src/de/mod.rs       | 34 +++-------------
 src/de/raw.rs       | 21 +++-------
 src/document.rs     | 21 +---------
 src/raw/document.rs |  8 +---
 src/raw/error.rs    | 27 +++++--------
 src/raw/iter.rs     | 49 ++++++++++-------------
 src/raw/mod.rs      | 97 +++++++++++++++++++++++++--------------------
 8 files changed, 104 insertions(+), 159 deletions(-)

diff --git a/src/de/error.rs b/src/de/error.rs
index 9f09c5b2..44a32131 100644
--- a/src/de/error.rs
+++ b/src/de/error.rs
@@ -58,6 +58,12 @@ impl From<string::FromUtf8Error> for Error {
     }
 }
 
+impl From<crate::raw::Error> for Error {
+    fn from(value: crate::raw::Error) -> Self {
+        Self::deserialization(value)
+    }
+}
+
 impl fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match *self {
diff --git a/src/de/mod.rs b/src/de/mod.rs
index f096ceca..b6a95a09 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -39,7 +39,7 @@ use crate::{
 };
 
 use ::serde::{
-    de::{DeserializeOwned, Error as _, Unexpected},
+    de::{DeserializeOwned, Error as _},
     Deserialize,
 };
 
@@ -68,32 +68,6 @@ enum DeserializerHint {
     RawBson,
 }
 
-pub(crate) fn read_bool<R: Read>(mut reader: R) -> Result<bool> {
-    let val = read_u8(&mut reader)?;
-    if val > 1 {
-        return Err(Error::invalid_value(
-            Unexpected::Unsigned(val as u64),
-            &"boolean must be stored as 0 or 1",
-        ));
-    }
-
-    Ok(val != 0)
-}
-
-#[inline]
-pub(crate) fn read_u8<R: Read + ?Sized>(reader: &mut R) -> Result<u8> {
-    let mut buf = [0; 1];
-    reader.read_exact(&mut buf)?;
-    Ok(u8::from_le_bytes(buf))
-}
-
-#[inline]
-pub(crate) fn read_i32<R: Read + ?Sized>(reader: &mut R) -> Result<i32> {
-    let mut buf = [0; 4];
-    reader.read_exact(&mut buf)?;
-    Ok(i32::from_le_bytes(buf))
-}
-
 impl Timestamp {
     pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
         let mut bytes = [0; 8];
@@ -181,8 +155,10 @@ where
     Deserialize::deserialize(de)
 }
 
-fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
-    let length = read_i32(&mut reader)?;
+pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
+    let mut buf = [0; 4];
+    reader.read_exact(&mut buf)?;
+    let length = i32::from_le_bytes(buf);
 
     if length < MIN_BSON_DOCUMENT_SIZE {
         return Err(Error::custom("document size too small"));
diff --git a/src/de/raw.rs b/src/de/raw.rs
index f843272a..6501c325 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -51,7 +51,7 @@ struct DeserializerOptions {
 impl<'de> Deserializer<'de> {
     pub(crate) fn new(buf: &'de [u8], utf8_lossy: bool) -> Result<Self> {
         Ok(Self {
-            element: RawElement::toplevel(buf).map_err(Error::deserialization)?,
+            element: RawElement::toplevel(buf)?,
             options: DeserializerOptions {
                 utf8_lossy,
                 human_readable: false,
@@ -60,7 +60,7 @@ impl<'de> Deserializer<'de> {
     }
 
     fn value(&self) -> Result<RawBsonRef<'de>> {
-        self.element.value().map_err(Error::deserialization)
+        Ok(self.element.value()?)
     }
 
     /// Deserialize the element, using the type of the element along with the
@@ -70,11 +70,7 @@ impl<'de> Deserializer<'de> {
         V: serde::de::Visitor<'de>,
     {
         if self.options.utf8_lossy {
-            if let Some(lossy) = self
-                .element
-                .value_utf8_lossy()
-                .map_err(Error::deserialization)?
-            {
+            if let Some(lossy) = self.element.value_utf8_lossy()? {
                 return match lossy {
                     Utf8LossyBson::String(s) => visitor.visit_string(s),
                     Utf8LossyBson::RegularExpression(re) => {
@@ -183,10 +179,7 @@ impl<'de> Deserializer<'de> {
 
     fn get_string(&self) -> Result<Cow<'de, str>> {
         if self.options.utf8_lossy {
-            let value = self
-                .element
-                .value_utf8_lossy()
-                .map_err(Error::deserialization)?;
+            let value = self.element.value_utf8_lossy()?;
             let s = match value {
                 Some(Utf8LossyBson::String(s)) => s,
                 _ => {
@@ -335,11 +328,7 @@ impl<'de> DocumentAccess<'de> {
     }
 
     fn advance(&mut self) -> Result<()> {
-        self.elem = self
-            .iter
-            .next()
-            .transpose()
-            .map_err(Error::deserialization)?;
+        self.elem = self.iter.next().transpose()?;
         Ok(())
     }
 
diff --git a/src/document.rs b/src/document.rs
index e073b386..1c18446a 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -1,7 +1,6 @@
 //! A BSON document represented as an associative HashMap with insertion ordering.
 
 use std::{
-    convert::TryInto,
     error,
     fmt::{self, Debug, Display, Formatter},
     io::{Read, Write},
@@ -10,11 +9,10 @@ use std::{
 
 use ahash::RandomState;
 use indexmap::IndexMap;
-use serde::{de::Error, Deserialize};
+use serde::Deserialize;
 
 use crate::{
     bson::{Array, Bson, Timestamp},
-    de::{read_i32, MIN_BSON_DOCUMENT_SIZE},
     oid::ObjectId,
     spec::BinarySubtype,
     Binary,
@@ -548,22 +546,7 @@ impl Document {
     }
 
     fn decode<R: Read + ?Sized>(reader: &mut R, utf_lossy: bool) -> crate::de::Result<Document> {
-        let length = read_i32(reader)?;
-        if length < MIN_BSON_DOCUMENT_SIZE {
-            return Err(crate::de::Error::invalid_length(
-                length as usize,
-                &"document length must be at least 5",
-            ));
-        }
-        let ulen: usize =
-            length
-                .try_into()
-                .map_err(|e| crate::de::Error::DeserializationError {
-                    message: format!("invalid document length: {}", e),
-                })?;
-        let mut buf = vec![0u8; ulen];
-        buf[0..4].copy_from_slice(&length.to_le_bytes());
-        reader.read_exact(&mut buf[4..])?;
+        let buf = crate::de::reader_to_vec(reader)?;
         let deserializer = crate::de::RawDeserializer::new(&buf, utf_lossy)?;
         Document::deserialize(deserializer)
     }
diff --git a/src/raw/document.rs b/src/raw/document.rs
index bebd4b24..710cf699 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -519,15 +519,11 @@ impl RawDocument {
         let buf = &self.as_bytes()[start_at..];
 
         let mut splits = buf.splitn(2, |x| *x == 0);
-        let value = splits
-            .next()
-            .ok_or_else(|| Error::new_without_key(ErrorKind::new_malformed("no value")))?;
+        let value = splits.next().ok_or_else(|| Error::malformed("no value"))?;
         if splits.next().is_some() {
             Ok(value)
         } else {
-            Err(Error::new_without_key(ErrorKind::new_malformed(
-                "expected null terminator",
-            )))
+            Err(Error::malformed("expected null terminator"))
         }
     }
 
diff --git a/src/raw/error.rs b/src/raw/error.rs
index b29fe280..e6ab8fbc 100644
--- a/src/raw/error.rs
+++ b/src/raw/error.rs
@@ -14,19 +14,18 @@ pub struct Error {
 }
 
 impl Error {
-    pub(crate) fn new_with_key(key: impl Into<String>, kind: ErrorKind) -> Self {
-        Self {
-            kind,
-            key: Some(key.into()),
-        }
+    pub(crate) fn new(kind: ErrorKind) -> Self {
+        Self { key: None, kind }
     }
 
-    pub(crate) fn new_without_key(kind: ErrorKind) -> Self {
-        Self { key: None, kind }
+    pub(crate) fn malformed(e: impl ToString) -> Self {
+        Self::new(ErrorKind::MalformedValue {
+            message: e.to_string(),
+        })
     }
 
-    pub(crate) fn with_key(mut self, key: impl AsRef<str>) -> Self {
-        self.key = Some(key.as_ref().to_string());
+    pub(crate) fn with_key(mut self, key: impl Into<String>) -> Self {
+        self.key = Some(key.into());
         self
     }
 
@@ -48,14 +47,6 @@ pub enum ErrorKind {
     Utf8EncodingError(Utf8Error),
 }
 
-impl ErrorKind {
-    pub(crate) fn new_malformed(e: impl ToString) -> Self {
-        ErrorKind::MalformedValue {
-            message: e.to_string(),
-        }
-    }
-}
-
 impl std::fmt::Display for Error {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         let p = self
@@ -80,7 +71,7 @@ pub type Result<T> = std::result::Result<T, Error>;
 
 /// Execute the provided closure, mapping the key of the returned error (if any) to the provided
 /// key.
-pub(crate) fn try_with_key<G, F: FnOnce() -> Result<G>>(key: impl AsRef<str>, f: F) -> Result<G> {
+pub(crate) fn try_with_key<G, F: FnOnce() -> Result<G>>(key: impl Into<String>, f: F) -> Result<G> {
     f().map_err(|e| e.with_key(key))
 }
 
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 410c68d0..bff08502 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -1,9 +1,9 @@
 use std::convert::TryInto;
 
 use crate::{
-    de::{read_bool, MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE},
+    de::{MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE},
     oid::ObjectId,
-    raw::{Error, ErrorKind, Result},
+    raw::{Error, Result},
     spec::{BinarySubtype, ElementType},
     Bson,
     DateTime,
@@ -18,6 +18,7 @@ use crate::{
 };
 
 use super::{
+    bool_from_slice,
     checked_add,
     error::try_with_key,
     f64_from_slice,
@@ -81,11 +82,11 @@ impl<'a> RawIter<'a> {
     fn verify_enough_bytes(&self, start: usize, num_bytes: usize) -> Result<()> {
         let end = checked_add(start, num_bytes)?;
         if self.doc.as_bytes().get(start..end).is_none() {
-            return Err(Error::new_without_key(ErrorKind::new_malformed(format!(
+            return Err(Error::malformed(format!(
                 "length exceeds remaining length of buffer: {} vs {}",
                 num_bytes,
                 self.doc.as_bytes().len() - start
-            ))));
+            )));
         }
         Ok(())
     }
@@ -95,18 +96,16 @@ impl<'a> RawIter<'a> {
         let size = i32_from_slice(&self.doc.as_bytes()[starting_at..])? as usize;
 
         if size < MIN_BSON_DOCUMENT_SIZE as usize {
-            return Err(Error::new_without_key(ErrorKind::new_malformed(format!(
+            return Err(Error::malformed(format!(
                 "document too small: {} bytes",
                 size
-            ))));
+            )));
         }
 
         self.verify_enough_bytes(starting_at, size)?;
 
         if self.doc.as_bytes()[starting_at + size - 1] != 0 {
-            return Err(Error::new_without_key(ErrorKind::new_malformed(
-                "not null terminated",
-            )));
+            return Err(Error::malformed("not null terminated"));
         }
         Ok(size)
     }
@@ -186,9 +185,9 @@ impl<'a> RawElement<'a> {
             ElementType::Array => {
                 RawBsonRef::Array(RawArray::from_doc(RawDocument::from_bytes(self.slice())?))
             }
-            ElementType::Boolean => {
-                RawBsonRef::Boolean(read_bool(self.slice()).map_err(|e| self.malformed_error(e))?)
-            }
+            ElementType::Boolean => RawBsonRef::Boolean(
+                bool_from_slice(self.slice()).map_err(|e| self.malformed_error(e))?,
+            ),
             ElementType::DateTime => {
                 RawBsonRef::DateTime(DateTime::from_millis(i64_from_slice(self.slice())?))
             }
@@ -309,7 +308,7 @@ impl<'a> RawElement<'a> {
     }
 
     fn malformed_error(&self, e: impl ToString) -> Error {
-        Error::new_with_key(self.key, ErrorKind::new_malformed(e))
+        Error::malformed(e).with_key(self.key)
     }
 
     pub(crate) fn slice(&self) -> &'a [u8] {
@@ -336,7 +335,7 @@ impl<'a> RawElement<'a> {
         Ok(ObjectId::from_bytes(
             self.doc.as_bytes()[start_at..(start_at + 12)]
                 .try_into()
-                .map_err(|e| Error::new_with_key(self.key, ErrorKind::new_malformed(e)))?,
+                .map_err(|e| Error::malformed(e).with_key(self.key))?,
         ))
     }
 }
@@ -345,9 +344,7 @@ impl<'a> RawIter<'a> {
     fn get_next_length_at(&self, start_at: usize) -> Result<usize> {
         let len = i32_from_slice(&self.doc.as_bytes()[start_at..])?;
         if len < 0 {
-            Err(Error::new_without_key(ErrorKind::new_malformed(
-                "lengths can't be negative",
-            )))
+            Err(Error::malformed("lengths can't be negative"))
         } else {
             Ok(len as usize)
         }
@@ -366,15 +363,11 @@ impl<'a> Iterator for RawIter<'a> {
                 return None;
             } else {
                 self.valid = false;
-                return Some(Err(Error::new_without_key(ErrorKind::new_malformed(
-                    "document not null terminated",
-                ))));
+                return Some(Err(Error::malformed("document not null terminated")));
             }
         } else if self.offset >= self.doc.as_bytes().len() {
             self.valid = false;
-            return Some(Err(Error::new_without_key(ErrorKind::new_malformed(
-                "iteration overflowed document",
-            ))));
+            return Some(Err(Error::malformed("iteration overflowed document")));
         }
 
         let key = match self.doc.read_cstring_at(self.offset + 1) {
@@ -390,13 +383,11 @@ impl<'a> Iterator for RawIter<'a> {
             let element_type = match ElementType::from(self.doc.as_bytes()[self.offset]) {
                 Some(et) => et,
                 None => {
-                    return Err(Error::new_with_key(
-                        key,
-                        ErrorKind::new_malformed(format!(
-                            "invalid tag: {}",
-                            self.doc.as_bytes()[self.offset]
-                        )),
+                    return Err(Error::malformed(format!(
+                        "invalid tag: {}",
+                        self.doc.as_bytes()[self.offset]
                     ))
+                    .with_key(key))
                 }
             };
 
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index b8c1ea54..175bca64 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -163,9 +163,10 @@ fn f64_from_slice(val: &[u8]) -> Result<f64> {
         .get(0..8)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::new_without_key(ErrorKind::MalformedValue {
-                message: format!("expected 8 bytes to read double, instead got {}", val.len()),
-            })
+            Error::malformed(format!(
+                "expected 8 bytes to read double, instead got {}",
+                val.len()
+            ))
         })?;
     Ok(f64::from_le_bytes(arr))
 }
@@ -177,9 +178,10 @@ fn i32_from_slice(val: &[u8]) -> Result<i32> {
         .get(0..4)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::new_without_key(ErrorKind::MalformedValue {
-                message: format!("expected 4 bytes to read i32, instead got {}", val.len()),
-            })
+            Error::malformed(format!(
+                "expected 4 bytes to read i32, instead got {}",
+                val.len()
+            ))
         })?;
     Ok(i32::from_le_bytes(arr))
 }
@@ -191,49 +193,67 @@ fn i64_from_slice(val: &[u8]) -> Result<i64> {
         .get(0..8)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::new_without_key(ErrorKind::MalformedValue {
-                message: format!("expected 8 bytes to read i64, instead got {}", val.len()),
-            })
+            Error::malformed(format!(
+                "expected 8 bytes to read i64, instead got {}",
+                val.len()
+            ))
         })?;
     Ok(i64::from_le_bytes(arr))
 }
 
+fn u8_from_slice(val: &[u8]) -> Result<u8> {
+    let arr = val
+        .get(0..1)
+        .and_then(|s| s.try_into().ok())
+        .ok_or_else(|| {
+            Error::malformed(format!(
+                "expected 1 byte to read u8, instead got {}",
+                val.len()
+            ))
+        })?;
+    Ok(u8::from_le_bytes(arr))
+}
+
+pub(crate) fn bool_from_slice(val: &[u8]) -> Result<bool> {
+    let val = u8_from_slice(val)?;
+    if val > 1 {
+        return Err(Error::malformed(format!(
+            "boolean must be stored as 0 or 1, got {}",
+            val
+        )));
+    }
+
+    Ok(val != 0)
+}
+
 fn read_len(buf: &[u8]) -> Result<usize> {
     if buf.len() < 4 {
-        return Err(Error::new_without_key(ErrorKind::MalformedValue {
-            message: format!(
-                "expected buffer with string to contain at least 4 bytes, but it only has {}",
-                buf.len()
-            ),
-        }));
+        return Err(Error::malformed(format!(
+            "expected buffer with string to contain at least 4 bytes, but it only has {}",
+            buf.len()
+        )));
     }
 
     let length = i32_from_slice(&buf[..4])?;
     let end = checked_add(usize_try_from_i32(length)?, 4)?;
 
     if end < MIN_BSON_STRING_SIZE as usize {
-        return Err(Error::new_without_key(ErrorKind::MalformedValue {
-            message: format!(
-                "BSON length encoded string needs to be at least {} bytes, instead got {}",
-                MIN_BSON_STRING_SIZE, end
-            ),
-        }));
+        return Err(Error::malformed(format!(
+            "BSON length encoded string needs to be at least {} bytes, instead got {}",
+            MIN_BSON_STRING_SIZE, end
+        )));
     }
 
     if buf.len() < end {
-        return Err(Error::new_without_key(ErrorKind::MalformedValue {
-            message: format!(
-                "expected buffer to contain at least {} bytes, but it only has {}",
-                end,
-                buf.len()
-            ),
-        }));
+        return Err(Error::malformed(format!(
+            "expected buffer to contain at least {} bytes, but it only has {}",
+            end,
+            buf.len()
+        )));
     }
 
     if buf[end - 1] != 0 {
-        return Err(Error::new_without_key(ErrorKind::MalformedValue {
-            message: "expected string to be null-terminated".to_string(),
-        }));
+        return Err(Error::malformed("expected string to be null-terminated"));
     }
 
     Ok(length as usize + 4)
@@ -251,21 +271,14 @@ fn read_lenencode(buf: &[u8]) -> Result<&str> {
 }
 
 fn try_to_str(data: &[u8]) -> Result<&str> {
-    std::str::from_utf8(data).map_err(|e| Error::new_without_key(ErrorKind::Utf8EncodingError(e)))
+    std::str::from_utf8(data).map_err(|e| Error::new(ErrorKind::Utf8EncodingError(e)))
 }
 
 fn usize_try_from_i32(i: i32) -> Result<usize> {
-    usize::try_from(i).map_err(|e| {
-        Error::new_without_key(ErrorKind::MalformedValue {
-            message: e.to_string(),
-        })
-    })
+    usize::try_from(i).map_err(Error::malformed)
 }
 
 fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
-    lhs.checked_add(rhs).ok_or_else(|| {
-        Error::new_without_key(ErrorKind::MalformedValue {
-            message: "attempted to add with overflow".to_string(),
-        })
-    })
+    lhs.checked_add(rhs)
+        .ok_or_else(|| Error::malformed("attempted to add with overflow"))
 }

From 2e8fb00cf8dcb0ce23de57d8c535ed44e03e4834 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 25 Jul 2024 10:19:51 -0400
Subject: [PATCH 072/156] RUST-1992 Factor raw bson encoding out of
 RawDocumentBuf (#486)

---
 src/raw/document_buf.rs            | 104 ++---------------------------
 src/raw/document_buf/raw_writer.rs |  96 ++++++++++++++++++++++++++
 src/raw/serde/seeded_visitor.rs    |  19 +-----
 src/ser/mod.rs                     |  15 ++---
 src/ser/raw/mod.rs                 |   3 +-
 src/ser/raw/value_serializer.rs    |   8 +--
 6 files changed, 118 insertions(+), 127 deletions(-)
 create mode 100644 src/raw/document_buf/raw_writer.rs

diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 6a508a35..5a99fa72 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -7,7 +7,7 @@ use std::{
 
 use serde::{Deserialize, Serialize};
 
-use crate::{de::MIN_BSON_DOCUMENT_SIZE, spec::BinarySubtype, Document};
+use crate::{de::MIN_BSON_DOCUMENT_SIZE, Document};
 
 use super::{
     bson::RawBson,
@@ -21,6 +21,8 @@ use super::{
     Result,
 };
 
+mod raw_writer;
+
 /// An owned BSON document (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes.
 /// This can be created from a `Vec<u8>` or a [`crate::Document`].
 ///
@@ -221,103 +223,9 @@ impl RawDocumentBuf {
     ///
     /// If the provided key contains an interior null byte, this method will panic.
     pub fn append_ref<'a>(&mut self, key: impl AsRef<str>, value: impl Into<RawBsonRef<'a>>) {
-        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.as_bytes());
-            doc.data.push(0);
-        }
-
-        fn append_cstring(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();
-
-        // 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.as_ref());
-
-        let value = value.into();
-        let element_type = value.element_type();
-
-        match value {
-            RawBsonRef::Int32(i) => {
-                self.data.extend(i.to_le_bytes());
-            }
-            RawBsonRef::String(s) => {
-                append_string(self, s);
-            }
-            RawBsonRef::Document(d) => {
-                self.data.extend(d.as_bytes());
-            }
-            RawBsonRef::Array(a) => {
-                self.data.extend(a.as_bytes());
-            }
-            RawBsonRef::Binary(b) => {
-                let len = b.len();
-                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(b.bytes);
-            }
-            RawBsonRef::Boolean(b) => {
-                self.data.push(b as u8);
-            }
-            RawBsonRef::DateTime(dt) => {
-                self.data.extend(dt.timestamp_millis().to_le_bytes());
-            }
-            RawBsonRef::DbPointer(dbp) => {
-                append_string(self, dbp.namespace);
-                self.data.extend(dbp.id.bytes());
-            }
-            RawBsonRef::Decimal128(d) => {
-                self.data.extend(d.bytes());
-            }
-            RawBsonRef::Double(d) => {
-                self.data.extend(d.to_le_bytes());
-            }
-            RawBsonRef::Int64(i) => {
-                self.data.extend(i.to_le_bytes());
-            }
-            RawBsonRef::RegularExpression(re) => {
-                append_cstring(self, re.pattern);
-                append_cstring(self, re.options);
-            }
-            RawBsonRef::JavaScriptCode(js) => {
-                append_string(self, js);
-            }
-            RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => {
-                let len = code_w_scope.len();
-                self.data.extend(len.to_le_bytes());
-                append_string(self, code_w_scope.code);
-                self.data.extend(code_w_scope.scope.as_bytes());
-            }
-            RawBsonRef::Timestamp(ts) => {
-                self.data.extend(ts.to_le_bytes());
-            }
-            RawBsonRef::ObjectId(oid) => {
-                self.data.extend(oid.bytes());
-            }
-            RawBsonRef::Symbol(s) => {
-                append_string(self, s);
-            }
-            RawBsonRef::Null | RawBsonRef::Undefined | RawBsonRef::MinKey | RawBsonRef::MaxKey => {}
-        }
-
-        // update element type
-        self.data[original_len - 1] = element_type as u8;
-        // append trailing null byte
-        self.data.push(0);
-        // update length
-        let new_len = (self.data.len() as i32).to_le_bytes();
-        self.data[0..4].copy_from_slice(&new_len);
+        raw_writer::RawWriter::new(&mut self.data)
+            .append(key.as_ref(), value.into())
+            .expect("key should not contain interior null byte")
     }
 
     /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error
diff --git a/src/raw/document_buf/raw_writer.rs b/src/raw/document_buf/raw_writer.rs
new file mode 100644
index 00000000..1d6fae22
--- /dev/null
+++ b/src/raw/document_buf/raw_writer.rs
@@ -0,0 +1,96 @@
+use crate::{
+    ser::{write_cstring, write_string},
+    spec::BinarySubtype,
+    RawBsonRef,
+};
+
+pub(super) struct RawWriter<'a> {
+    data: &'a mut Vec<u8>,
+}
+
+impl<'a> RawWriter<'a> {
+    pub(super) fn new(data: &'a mut Vec<u8>) -> Self {
+        Self { data }
+    }
+
+    pub(super) fn append(&mut self, key: &str, value: RawBsonRef) -> crate::ser::Result<()> {
+        let original_len = self.data.len();
+        self.data[original_len - 1] = value.element_type() as u8;
+
+        write_cstring(self.data, key)?;
+
+        match value {
+            RawBsonRef::Int32(i) => {
+                self.data.extend(i.to_le_bytes());
+            }
+            RawBsonRef::String(s) => {
+                write_string(self.data, s);
+            }
+            RawBsonRef::Document(d) => {
+                self.data.extend(d.as_bytes());
+            }
+            RawBsonRef::Array(a) => {
+                self.data.extend(a.as_bytes());
+            }
+            RawBsonRef::Binary(b) => {
+                let len = b.len();
+                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(b.bytes);
+            }
+            RawBsonRef::Boolean(b) => {
+                self.data.push(b as u8);
+            }
+            RawBsonRef::DateTime(dt) => {
+                self.data.extend(dt.timestamp_millis().to_le_bytes());
+            }
+            RawBsonRef::DbPointer(dbp) => {
+                write_string(self.data, dbp.namespace);
+                self.data.extend(dbp.id.bytes());
+            }
+            RawBsonRef::Decimal128(d) => {
+                self.data.extend(d.bytes());
+            }
+            RawBsonRef::Double(d) => {
+                self.data.extend(d.to_le_bytes());
+            }
+            RawBsonRef::Int64(i) => {
+                self.data.extend(i.to_le_bytes());
+            }
+            RawBsonRef::RegularExpression(re) => {
+                write_cstring(self.data, re.pattern)?;
+                write_cstring(self.data, re.options)?;
+            }
+            RawBsonRef::JavaScriptCode(js) => {
+                write_string(self.data, js);
+            }
+            RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => {
+                let len = code_w_scope.len();
+                self.data.extend(len.to_le_bytes());
+                write_string(self.data, code_w_scope.code);
+                self.data.extend(code_w_scope.scope.as_bytes());
+            }
+            RawBsonRef::Timestamp(ts) => {
+                self.data.extend(ts.to_le_bytes());
+            }
+            RawBsonRef::ObjectId(oid) => {
+                self.data.extend(oid.bytes());
+            }
+            RawBsonRef::Symbol(s) => {
+                write_string(self.data, s);
+            }
+            RawBsonRef::Null | RawBsonRef::Undefined | RawBsonRef::MinKey | RawBsonRef::MaxKey => {}
+        }
+
+        // append trailing null byte
+        self.data.push(0);
+        // update length
+        let new_len = (self.data.len() as i32).to_le_bytes();
+        self.data[0..4].copy_from_slice(&new_len);
+
+        Ok(())
+    }
+}
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
index fa0fd31a..1d6f7ca9 100644
--- a/src/raw/serde/seeded_visitor.rs
+++ b/src/raw/serde/seeded_visitor.rs
@@ -7,6 +7,7 @@ use serde::{
 
 use crate::{
     raw::RAW_BSON_NEWTYPE,
+    ser::{write_cstring, write_string},
     spec::{BinarySubtype, ElementType},
     RawBson,
     RawBsonRef,
@@ -119,26 +120,12 @@ impl<'a, 'de> SeededVisitor<'a, 'de> {
 
     /// Appends a cstring to the buffer. Returns an error if the given string contains a null byte.
     fn append_cstring(&mut self, key: &str) -> Result<(), String> {
-        let key_bytes = key.as_bytes();
-        if key_bytes.contains(&0) {
-            return Err(format!("key contains interior null byte: {}", key));
-        }
-
-        self.buffer.append_bytes(key_bytes);
-        self.buffer.push_byte(0);
-
-        Ok(())
+        write_cstring(self.buffer.get_owned_buffer(), key).map_err(|e| e.to_string())
     }
 
     /// Appends a string and its length to the buffer.
     fn append_string(&mut self, s: &str) {
-        let bytes = s.as_bytes();
-
-        // Add 1 to account for null byte.
-        self.append_length_bytes((bytes.len() + 1) as i32);
-
-        self.buffer.append_bytes(bytes);
-        self.buffer.push_byte(0);
+        write_string(self.buffer.get_owned_buffer(), s)
     }
 
     /// Converts the given length into little-endian bytes and appends the bytes to the buffer.
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index 6adf87ec..b35e51cd 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -40,19 +40,18 @@ use crate::{
 };
 use ::serde::{ser::Error as SerdeError, Serialize};
 
-fn write_string<W: Write + ?Sized>(writer: &mut W, s: &str) -> Result<()> {
-    writer.write_all(&(s.len() as i32 + 1).to_le_bytes())?;
-    writer.write_all(s.as_bytes())?;
-    writer.write_all(b"\0")?;
-    Ok(())
+pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
+    buf.extend(&(s.len() as i32 + 1).to_le_bytes());
+    buf.extend(s.as_bytes());
+    buf.push(0);
 }
 
-fn write_cstring<W: Write + ?Sized>(writer: &mut W, s: &str) -> Result<()> {
+pub(crate) fn write_cstring(buf: &mut Vec<u8>, s: &str) -> Result<()> {
     if s.contains('\0') {
         return Err(Error::InvalidCString(s.into()));
     }
-    writer.write_all(s.as_bytes())?;
-    writer.write_all(b"\0")?;
+    buf.extend(s.as_bytes());
+    buf.push(0);
     Ok(())
 }
 
diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs
index 2fb739c3..103627d2 100644
--- a/src/ser/raw/mod.rs
+++ b/src/ser/raw/mod.rs
@@ -199,7 +199,8 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     #[inline]
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
         self.update_element_type(ElementType::String)?;
-        write_string(&mut self.bytes, v)
+        write_string(&mut self.bytes, v);
+        Ok(())
     }
 
     #[inline]
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 6f7b9945..76d1a1c0 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -265,7 +265,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
                 write_binary(&mut self.root_serializer.bytes, bytes.as_slice(), subtype)?;
             }
             SerializationStep::Symbol | SerializationStep::DbPointerRef => {
-                write_string(&mut self.root_serializer.bytes, v)?;
+                write_string(&mut self.root_serializer.bytes, v);
             }
             SerializationStep::RegExPattern => {
                 write_cstring(&mut self.root_serializer.bytes, v)?;
@@ -278,7 +278,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
                 write_cstring(&mut self.root_serializer.bytes, sorted.as_str())?;
             }
             SerializationStep::Code => {
-                write_string(&mut self.root_serializer.bytes, v)?;
+                write_string(&mut self.root_serializer.bytes, v);
             }
             SerializationStep::CodeWithScopeCode => {
                 self.state = SerializationStep::CodeWithScopeScope {
@@ -313,7 +313,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
                     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)?;
+                write_string(&mut self.root_serializer.bytes, code);
                 self.root_serializer.bytes.write_all(v)?;
                 self.state = SerializationStep::Done;
                 Ok(())
@@ -590,7 +590,7 @@ impl<'a> CodeWithScopeSerializer<'a> {
     fn start(code: &str, rs: &'a mut Serializer) -> Result<Self> {
         let start = rs.bytes.len();
         write_i32(&mut rs.bytes, 0)?; // placeholder length
-        write_string(&mut rs.bytes, code)?;
+        write_string(&mut rs.bytes, code);
 
         let doc = DocumentSerializer::start(rs)?;
         Ok(Self { start, doc })

From d0f5d233fd6b1bd54021f5637be718d9bc192269 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 26 Jul 2024 13:04:23 -0400
Subject: [PATCH 073/156] minor: update bson to clippy 1.80.0 (#487)

---
 .evergreen/check-clippy.sh         |  2 +-
 src/bson.rs                        | 11 ++++-----
 src/de/serde.rs                    |  6 ++---
 src/extjson/de.rs                  |  2 +-
 src/extjson/mod.rs                 |  3 +--
 src/extjson/models.rs              |  6 ++---
 src/oid.rs                         |  2 +-
 src/ser/mod.rs                     | 19 +++++++---------
 src/ser/raw/document_serializer.rs | 36 +++++++++++++++---------------
 src/ser/raw/mod.rs                 | 24 ++++++++++----------
 src/ser/raw/value_serializer.rs    | 24 ++++++++++----------
 src/ser/serde.rs                   | 12 +++++-----
 src/tests/modules/ser.rs           |  2 +-
 13 files changed, 71 insertions(+), 78 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index 9a809142..c41008d5 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.75.0
+CLIPPY_VERSION=1.80.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/src/bson.rs b/src/bson.rs
index 6c8c905e..5ecb06dd 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -695,9 +695,9 @@ impl Bson {
             }
 
             ["$numberDouble"] => match doc.get_str("$numberDouble") {
-                Ok("Infinity") => return Bson::Double(std::f64::INFINITY),
-                Ok("-Infinity") => return Bson::Double(std::f64::NEG_INFINITY),
-                Ok("NaN") => return Bson::Double(std::f64::NAN),
+                Ok("Infinity") => return Bson::Double(f64::INFINITY),
+                Ok("-Infinity") => return Bson::Double(f64::NEG_INFINITY),
+                Ok("NaN") => return Bson::Double(f64::NAN),
                 Ok(other) => {
                     if let Ok(d) = other.parse() {
                         return Bson::Double(d);
@@ -758,10 +758,7 @@ impl Bson {
 
                     if let Ok(t) = timestamp.get_i64("t") {
                         if let Ok(i) = timestamp.get_i64("i") {
-                            if t >= 0
-                                && i >= 0
-                                && t <= (std::u32::MAX as i64)
-                                && i <= (std::u32::MAX as i64)
+                            if t >= 0 && i >= 0 && t <= (u32::MAX as i64) && i <= (u32::MAX as i64)
                             {
                                 return Bson::Timestamp(Timestamp {
                                     time: t as u32,
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 4b73859d..ecf35935 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -359,9 +359,9 @@ impl<'de> Visitor<'de> for BsonVisitor {
                 "$numberDouble" => {
                     let string: String = visitor.next_value()?;
                     let val = match string.as_str() {
-                        "Infinity" => Bson::Double(std::f64::INFINITY),
-                        "-Infinity" => Bson::Double(std::f64::NEG_INFINITY),
-                        "NaN" => Bson::Double(std::f64::NAN),
+                        "Infinity" => Bson::Double(f64::INFINITY),
+                        "-Infinity" => Bson::Double(f64::NEG_INFINITY),
+                        "NaN" => Bson::Double(f64::NAN),
                         _ => Bson::Double(string.parse().map_err(|_| {
                             V::Error::invalid_value(
                                 Unexpected::Str(&string),
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
index e4683391..82b8fcde 100644
--- a/src/extjson/de.rs
+++ b/src/extjson/de.rs
@@ -182,7 +182,7 @@ impl TryFrom<serde_json::Value> for Bson {
             serde_json::Value::Number(x) => x
                 .as_i64()
                 .map(|i| {
-                    if i >= std::i32::MIN as i64 && i <= std::i32::MAX as i64 {
+                    if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
                         Bson::Int32(i as i32)
                     } else {
                         Bson::Int64(i)
diff --git a/src/extjson/mod.rs b/src/extjson/mod.rs
index 32e94455..a23ca419 100644
--- a/src/extjson/mod.rs
+++ b/src/extjson/mod.rs
@@ -26,8 +26,7 @@
 //! There are two modes of extJSON: "Canonical" and "Relaxed". They are the same except for the
 //! following differences:
 //!   - In relaxed mode, all BSON numbers are represented by the JSON number type, rather than the
-//!     object
-//! notation.
+//!     object notation.
 //!   - In relaxed mode, the string in the datetime object notation is RFC 3339 (ISO-8601) formatted
 //!     (if the date is after 1970).
 //!
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 8e738c35..b91d5f67 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -57,9 +57,9 @@ pub(crate) struct Double {
 impl Double {
     pub(crate) fn parse(self) -> extjson::de::Result<f64> {
         match self.value.as_str() {
-            "Infinity" => Ok(std::f64::INFINITY),
-            "-Infinity" => Ok(std::f64::NEG_INFINITY),
-            "NaN" => Ok(std::f64::NAN),
+            "Infinity" => Ok(f64::INFINITY),
+            "-Infinity" => Ok(f64::NEG_INFINITY),
+            "NaN" => Ok(f64::NAN),
             other => {
                 let d: f64 = other.parse().map_err(|_| {
                     extjson::de::Error::invalid_value(
diff --git a/src/oid.rs b/src/oid.rs
index 89374a7e..9cec640e 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -332,7 +332,7 @@ fn test_counter_overflow_u24_max() {
 #[test]
 fn test_counter_overflow_usize_max() {
     let _guard = LOCK.run_exclusively();
-    let start = usize::max_value();
+    let start = usize::MAX;
     OID_COUNTER.store(start, Ordering::SeqCst);
     // Test counter overflows to u24_max when set to usize_max
     let oid = ObjectId::new();
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index b35e51cd..d2faf636 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -112,9 +112,9 @@ fn write_binary<W: Write>(mut writer: W, bytes: &[u8], subtype: BinarySubtype) -
 /// the format is human readable or not. To serialize to a [`Document`] with a serializer that
 /// presents itself as not human readable, use [`to_bson_with_options`] with
 /// [`SerializerOptions::human_readable`] set to false.
-pub fn to_bson<T: ?Sized>(value: &T) -> Result<Bson>
+pub fn to_bson<T>(value: &T) -> Result<Bson>
 where
-    T: Serialize,
+    T: Serialize + ?Sized,
 {
     let ser = Serializer::new();
     value.serialize(ser)
@@ -136,9 +136,9 @@ where
 /// assert_eq!(bson, bson!({ "a": "ok" }));
 /// # Ok::<(), Box<dyn std::error::Error>>(())
 /// ```
-pub fn to_bson_with_options<T: ?Sized>(value: &T, options: SerializerOptions) -> Result<Bson>
+pub fn to_bson_with_options<T>(value: &T, options: SerializerOptions) -> Result<Bson>
 where
-    T: Serialize,
+    T: Serialize + ?Sized,
 {
     let ser = Serializer::new_with_options(options);
     value.serialize(ser)
@@ -152,9 +152,9 @@ where
 /// the format is human readable or not. To serialize to a [`Document`] with a serializer that
 /// presents itself as not human readable, use [`to_document_with_options`] with
 /// [`SerializerOptions::human_readable`] set to false.
-pub fn to_document<T: ?Sized>(value: &T) -> Result<Document>
+pub fn to_document<T>(value: &T) -> Result<Document>
 where
-    T: Serialize,
+    T: Serialize + ?Sized,
 {
     to_document_with_options(value, Default::default())
 }
@@ -175,12 +175,9 @@ where
 /// assert_eq!(doc, doc! { "a": "ok" });
 /// # Ok::<(), Box<dyn std::error::Error>>(())
 /// ```
-pub fn to_document_with_options<T: ?Sized>(
-    value: &T,
-    options: SerializerOptions,
-) -> Result<Document>
+pub fn to_document_with_options<T>(value: &T, options: SerializerOptions) -> Result<Document>
 where
-    T: Serialize,
+    T: Serialize + ?Sized,
 {
     match to_bson_with_options(value, options)? {
         Bson::Document(doc) => Ok(doc),
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index e3eb53ee..9b20f5b8 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -71,9 +71,9 @@ impl<'a> serde::ser::SerializeSeq for DocumentSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
+    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         let index = self.num_keys_serialized;
         self.serialize_doc_key_custom(|rs| {
@@ -97,17 +97,17 @@ impl<'a> serde::ser::SerializeMap for DocumentSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>
+    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         self.serialize_doc_key(key)
     }
 
     #[inline]
-    fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>
+    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         value.serialize(&mut *self.root_serializer)
     }
@@ -123,9 +123,9 @@ impl<'a> serde::ser::SerializeStruct for DocumentSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()>
+    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         self.serialize_doc_key(key)?;
         value.serialize(&mut *self.root_serializer)
@@ -143,9 +143,9 @@ impl<'a> serde::ser::SerializeTuple for DocumentSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
+    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         self.serialize_doc_key(&self.num_keys_serialized.to_string())?;
         value.serialize(&mut *self.root_serializer)
@@ -163,9 +163,9 @@ impl<'a> serde::ser::SerializeTupleStruct for DocumentSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
+    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         self.serialize_doc_key(&self.num_keys_serialized.to_string())?;
         value.serialize(&mut *self.root_serializer)
@@ -278,9 +278,9 @@ impl<'a> serde::Serializer for KeySerializer<'a> {
     }
 
     #[inline]
-    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok>
+    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         value.serialize(self)
     }
@@ -306,15 +306,15 @@ impl<'a> serde::Serializer for KeySerializer<'a> {
     }
 
     #[inline]
-    fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<Self::Ok>
+    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Self::Ok>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         value.serialize(self)
     }
 
     #[inline]
-    fn serialize_newtype_variant<T: ?Sized>(
+    fn serialize_newtype_variant<T>(
         self,
         _name: &'static str,
         _variant_index: u32,
@@ -322,7 +322,7 @@ impl<'a> serde::Serializer for KeySerializer<'a> {
         value: &T,
     ) -> Result<Self::Ok>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         Err(Self::invalid_key(value))
     }
diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs
index 103627d2..1fb904f5 100644
--- a/src/ser/raw/mod.rs
+++ b/src/ser/raw/mod.rs
@@ -236,9 +236,9 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     }
 
     #[inline]
-    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok>
+    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         value.serialize(self)
     }
@@ -264,9 +264,9 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     }
 
     #[inline]
-    fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<Self::Ok>
+    fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Self::Ok>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         match name {
             UUID_NEWTYPE_NAME => self.hint = SerializerHint::Uuid,
@@ -285,7 +285,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     }
 
     #[inline]
-    fn serialize_newtype_variant<T: ?Sized>(
+    fn serialize_newtype_variant<T>(
         self,
         _name: &'static str,
         _variant_index: u32,
@@ -293,7 +293,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
         value: &T,
     ) -> Result<Self::Ok>
     where
-        T: serde::Serialize,
+        T: serde::Serialize + ?Sized,
     {
         self.update_element_type(ElementType::EmbeddedDocument)?;
         let mut d = DocumentSerializer::start(&mut *self)?;
@@ -396,9 +396,9 @@ impl<'a> SerializeStruct for StructSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()>
+    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         match self {
             StructSerializer::Value(ref mut v) => (&mut *v).serialize_field(key, value),
@@ -499,9 +499,9 @@ impl<'a> serde::ser::SerializeTupleVariant for VariantSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
+    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         self.serialize_element(format!("{}", self.num_elements_serialized).as_str(), value)
     }
@@ -518,9 +518,9 @@ impl<'a> serde::ser::SerializeStructVariant for VariantSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()>
+    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         self.serialize_element(key, value)
     }
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 76d1a1c0..46fb8623 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -328,9 +328,9 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
     }
 
     #[inline]
-    fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok>
+    fn serialize_some<T>(self, _value: &T) -> Result<Self::Ok>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         Err(self.invalid_step("some"))
     }
@@ -356,9 +356,9 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
     }
 
     #[inline]
-    fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<Self::Ok>
+    fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Self::Ok>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         match (&mut self.state, name) {
             (
@@ -376,7 +376,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
     }
 
     #[inline]
-    fn serialize_newtype_variant<T: ?Sized>(
+    fn serialize_newtype_variant<T>(
         self,
         _name: &'static str,
         _variant_index: u32,
@@ -384,7 +384,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
         _value: &T,
     ) -> Result<Self::Ok>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         Err(self.invalid_step("newtype_variant"))
     }
@@ -454,9 +454,9 @@ impl<'a, 'b> SerializeStruct for &'b mut ValueSerializer<'a> {
     type Ok = ();
     type Error = Error;
 
-    fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()>
+    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         match (&self.state, key) {
             (SerializationStep::DateTime, "$date") => {
@@ -602,17 +602,17 @@ impl<'a> SerializeMap for CodeWithScopeSerializer<'a> {
     type Error = Error;
 
     #[inline]
-    fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>
+    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         self.doc.serialize_key(key)
     }
 
     #[inline]
-    fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>
+    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         self.doc.serialize_value(value)
     }
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index b3a2389c..9b5ce313 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -266,9 +266,9 @@ impl ser::Serializer for Serializer {
     }
 
     #[inline]
-    fn serialize_some<V: ?Sized>(self, value: &V) -> crate::ser::Result<Bson>
+    fn serialize_some<V>(self, value: &V) -> crate::ser::Result<Bson>
     where
-        V: Serialize,
+        V: Serialize + ?Sized,
     {
         value.serialize(self)
     }
@@ -294,13 +294,13 @@ impl ser::Serializer for Serializer {
     }
 
     #[inline]
-    fn serialize_newtype_struct<T: ?Sized>(
+    fn serialize_newtype_struct<T>(
         mut self,
         name: &'static str,
         value: &T,
     ) -> crate::ser::Result<Bson>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         match name {
             UUID_NEWTYPE_NAME => {
@@ -357,7 +357,7 @@ impl ser::Serializer for Serializer {
     }
 
     #[inline]
-    fn serialize_newtype_variant<T: ?Sized>(
+    fn serialize_newtype_variant<T>(
         self,
         _name: &'static str,
         _variant_index: u32,
@@ -365,7 +365,7 @@ impl ser::Serializer for Serializer {
         value: &T,
     ) -> crate::ser::Result<Bson>
     where
-        T: Serialize,
+        T: Serialize + ?Sized,
     {
         let mut newtype_variant = Document::new();
         newtype_variant.insert(variant, to_bson_with_options(value, self.options)?);
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index 3b93bbb7..48aa6596 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -1,4 +1,4 @@
-use std::{collections::BTreeMap, u16, u32, u64, u8};
+use std::collections::BTreeMap;
 
 use assert_matches::assert_matches;
 

From a72431e4867ec7d5b38faa52860a45da6b183ff3 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 30 Jul 2024 13:13:33 -0400
Subject: [PATCH 074/156] RUST-1874 Add optional integration with
 `serde_path_to_error` (#488)

---
 Cargo.toml               |  2 +
 README.md                | 11 +++++
 src/de/error.rs          | 33 +++++++++++----
 src/de/mod.rs            | 28 ++++++++++---
 src/document.rs          |  4 +-
 src/lib.rs               | 11 ++++-
 src/ser/error.rs         | 43 +++++++++++++++++--
 src/ser/mod.rs           | 14 ++++++-
 src/tests/modules/ser.rs | 11 ++---
 src/tests/serde.rs       | 89 ++++++++++++++++++++++++++++++++++++++++
 10 files changed, 217 insertions(+), 29 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 7c013ff7..5a1ca73f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -43,6 +43,7 @@ chrono-0_4 = ["chrono"]
 uuid-1 = []
 # if enabled, include API for interfacing with time 0.3
 time-0_3 = []
+serde_path_to_error = ["dep:serde_path_to_error"]
 # if enabled, include serde_with interop.
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
 # it's commented out here because Cargo implicitly adds a feature flag for
@@ -69,6 +70,7 @@ serde_with = { version = "1.3.1", optional = true }
 serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
+serde_path_to_error = { version = "0.1.16", optional = true }
 [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
 js-sys = "0.3"
 
diff --git a/README.md b/README.md
index 993bcc36..196cf7de 100644
--- a/README.md
+++ b/README.md
@@ -50,8 +50,11 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
 | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
 | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
+| `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.                  | n/a                | no      |
 | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
+| `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | serde_path_to_error  | no |
+
 ## Overview of the BSON Format
 
 BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents.
@@ -208,6 +211,14 @@ separate the "business logic" that operates over the data from the (de)serializa
 translates the data to/from its serialized form. This can lead to more clear and concise code
 that is also less error prone.
 
+When serializing values that cannot be represented in BSON, or deserialzing from BSON that does
+not match the format expected by the type, the default error will only report the specific field
+that failed. To aid debugging, enabling the [`serde_path_to_error`](#feature-flags) feature will
+[augment errors](https://docs.rs/bson/latest/bson/de/enum.Error.html#variant.WithPath) with the
+full field path from root object to failing field.  This feature does incur a small CPU and memory
+overhead during (de)serialization and should be enabled with care in performance-sensitive
+environments.
+
 ### Working with datetimes
 
 The BSON format includes a datetime type, which is modeled in this crate by the
diff --git a/src/de/error.rs b/src/de/error.rs
index 44a32131..8b3c7920 100644
--- a/src/de/error.rs
+++ b/src/de/error.rs
@@ -36,6 +36,17 @@ pub enum Error {
         /// A message describing the error.
         message: String,
     },
+
+    #[cfg(feature = "serde_path_to_error")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "serde_path_to_error")))]
+    #[non_exhaustive]
+    WithPath {
+        /// The path to the error.
+        path: serde_path_to_error::Path,
+
+        /// The original error.
+        source: Box<Error>,
+    },
 }
 
 impl Error {
@@ -44,6 +55,13 @@ impl Error {
             message: msg.to_string(),
         }
     }
+
+    #[cfg(feature = "serde_path_to_error")]
+    pub(crate) fn with_path(err: serde_path_to_error::Error<Error>) -> Self {
+        let path = err.path().clone();
+        let source = Box::new(err.into_inner());
+        Self::WithPath { path, source }
+    }
 }
 
 impl From<io::Error> for Error {
@@ -66,19 +84,18 @@ impl From<crate::raw::Error> for Error {
 
 impl fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Error::Io(ref inner) => inner.fmt(fmt),
-            Error::InvalidUtf8String(ref inner) => inner.fmt(fmt),
-            Error::UnrecognizedDocumentElementType {
-                ref key,
-                element_type,
-            } => write!(
+        match self {
+            Error::Io(inner) => inner.fmt(fmt),
+            Error::InvalidUtf8String(inner) => inner.fmt(fmt),
+            Error::UnrecognizedDocumentElementType { key, element_type } => write!(
                 fmt,
                 "unrecognized element type for key \"{}\": `{:#x}`",
                 key, element_type
             ),
             Error::EndOfStream => fmt.write_str("end of stream"),
-            Error::DeserializationError { ref message } => message.fmt(fmt),
+            Error::DeserializationError { message } => message.fmt(fmt),
+            #[cfg(feature = "serde_path_to_error")]
+            Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source),
         }
     }
 }
diff --git a/src/de/mod.rs b/src/de/mod.rs
index b6a95a09..73c108d4 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -89,7 +89,14 @@ where
     T: DeserializeOwned,
 {
     let de = Deserializer::new(bson);
-    Deserialize::deserialize(de)
+    #[cfg(feature = "serde_path_to_error")]
+    {
+        return serde_path_to_error::deserialize(de).map_err(Error::with_path);
+    }
+    #[cfg(not(feature = "serde_path_to_error"))]
+    {
+        Deserialize::deserialize(de)
+    }
 }
 
 /// Deserialize a `T` from the provided [`Bson`] value, configuring the underlying
@@ -201,8 +208,7 @@ pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    let deserializer = raw::Deserializer::new(bytes, false)?;
-    T::deserialize(deserializer)
+    from_raw(raw::Deserializer::new(bytes, false)?)
 }
 
 /// Deserialize an instance of type `T` from a slice of BSON bytes, replacing any invalid UTF-8
@@ -215,6 +221,18 @@ pub fn from_slice_utf8_lossy<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    let deserializer = raw::Deserializer::new(bytes, true)?;
-    T::deserialize(deserializer)
+    from_raw(raw::Deserializer::new(bytes, true)?)
+}
+
+pub(crate) fn from_raw<'de, T: Deserialize<'de>>(
+    deserializer: raw::Deserializer<'de>,
+) -> Result<T> {
+    #[cfg(feature = "serde_path_to_error")]
+    {
+        serde_path_to_error::deserialize(deserializer).map_err(Error::with_path)
+    }
+    #[cfg(not(feature = "serde_path_to_error"))]
+    {
+        T::deserialize(deserializer)
+    }
 }
diff --git a/src/document.rs b/src/document.rs
index 1c18446a..fa408877 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -9,7 +9,6 @@ use std::{
 
 use ahash::RandomState;
 use indexmap::IndexMap;
-use serde::Deserialize;
 
 use crate::{
     bson::{Array, Bson, Timestamp},
@@ -547,8 +546,7 @@ impl Document {
 
     fn decode<R: Read + ?Sized>(reader: &mut R, utf_lossy: bool) -> crate::de::Result<Document> {
         let buf = crate::de::reader_to_vec(reader)?;
-        let deserializer = crate::de::RawDeserializer::new(&buf, utf_lossy)?;
-        Document::deserialize(deserializer)
+        crate::de::from_raw(crate::de::RawDeserializer::new(&buf, utf_lossy)?)
     }
 
     /// Attempts to deserialize a [`Document`] from a byte stream.
diff --git a/src/lib.rs b/src/lib.rs
index 8e70d2fe..69ad9db0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -65,7 +65,9 @@
 //! | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.           | no      |
 //! | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API.           | no      |
 //! | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.           | no      |
-//! | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/latest) integrations for [`DateTime`] and [`Uuid`]. | no      |
+//! | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for [`DateTime`] and [`Uuid`]. | no      |
+//! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for [`DateTime`] and [`Uuid`]. | no      |
+//! | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | no |
 //!
 //! ## BSON values
 //!
@@ -213,6 +215,13 @@
 //! data from the (de)serialization logic that translates the data to/from its serialized form. This
 //! can lead to more clear and concise code that is also less error prone.
 //!
+//! When serializing values that cannot be represented in BSON, or deserialzing from BSON that does
+//! not match the format expected by the type, the default error will only report the specific field
+//! that failed. To aid debugging, enabling the `serde_path_to_error` feature will
+//! [augment errors](crate::de::Error::WithPath) with the full field path from root object to
+//! failing field.  This feature does incur a small CPU and memory overhead during (de)serialization
+//! and should be enabled with care in performance-sensitive environments.
+//!
 //! ## Working with datetimes
 //!
 //! The BSON format includes a datetime type, which is modeled in this crate by the
diff --git a/src/ser/error.rs b/src/ser/error.rs
index ed355ab8..6f3b8877 100644
--- a/src/ser/error.rs
+++ b/src/ser/error.rs
@@ -27,6 +27,39 @@ pub enum Error {
 
     /// An unsigned integer type could not fit into a signed integer type.
     UnsignedIntegerExceededRange(u64),
+
+    #[cfg(feature = "serde_path_to_error")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "serde_path_to_error")))]
+    #[non_exhaustive]
+    WithPath {
+        /// The path to the error.
+        path: serde_path_to_error::Path,
+
+        /// The original error.
+        source: Box<Error>,
+    },
+}
+
+impl Error {
+    #[cfg(feature = "serde_path_to_error")]
+    pub(crate) fn with_path(err: serde_path_to_error::Error<Error>) -> Self {
+        let path = err.path().clone();
+        let source = Box::new(err.into_inner());
+        Self::WithPath { path, source }
+    }
+
+    #[cfg(test)]
+    pub(crate) fn strip_path(self) -> Self {
+        #[cfg(feature = "serde_path_to_error")]
+        match self {
+            Self::WithPath { path: _, source } => *source,
+            _ => self,
+        }
+        #[cfg(not(feature = "serde_path_to_error"))]
+        {
+            self
+        }
+    }
 }
 
 impl From<io::Error> for Error {
@@ -37,13 +70,13 @@ impl From<io::Error> for Error {
 
 impl fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Error::Io(ref inner) => inner.fmt(fmt),
-            Error::InvalidDocumentKey(ref key) => write!(fmt, "Invalid map key type: {}", key),
+        match self {
+            Error::Io(inner) => inner.fmt(fmt),
+            Error::InvalidDocumentKey(key) => write!(fmt, "Invalid map key type: {}", key),
             Error::InvalidCString(ref string) => {
                 write!(fmt, "cstrings cannot contain null bytes: {:?}", string)
             }
-            Error::SerializationError { ref message } => message.fmt(fmt),
+            Error::SerializationError { message } => message.fmt(fmt),
             Error::UnsignedIntegerExceededRange(value) => write!(
                 fmt,
                 "BSON does not support unsigned integers.
@@ -51,6 +84,8 @@ impl fmt::Display for Error {
                  size.",
                 value
             ),
+            #[cfg(feature = "serde_path_to_error")]
+            Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source),
         }
     }
 }
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index d2faf636..10fb8037 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -117,6 +117,11 @@ where
     T: Serialize + ?Sized,
 {
     let ser = Serializer::new();
+    #[cfg(feature = "serde_path_to_error")]
+    {
+        serde_path_to_error::serialize(value, ser).map_err(Error::with_path)
+    }
+    #[cfg(not(feature = "serde_path_to_error"))]
     value.serialize(ser)
 }
 
@@ -197,7 +202,14 @@ where
     T: Serialize,
 {
     let mut serializer = raw::Serializer::new();
-    value.serialize(&mut serializer)?;
+    #[cfg(feature = "serde_path_to_error")]
+    {
+        serde_path_to_error::serialize(value, &mut serializer).map_err(Error::with_path)?;
+    }
+    #[cfg(not(feature = "serde_path_to_error"))]
+    {
+        value.serialize(&mut serializer)?;
+    }
     Ok(serializer.into_vec())
 }
 
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index 48aa6596..aa95651c 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -109,11 +109,8 @@ fn uint64_u2i() {
     let deser_min: u64 = from_bson(obj_min).unwrap();
     assert_eq!(deser_min, u64::MIN);
 
-    let obj_max: ser::Result<Bson> = to_bson(&u64::MAX);
-    assert_matches!(
-        obj_max,
-        Err(ser::Error::UnsignedIntegerExceededRange(u64::MAX))
-    );
+    let err: ser::Error = to_bson(&u64::MAX).unwrap_err().strip_path();
+    assert_matches!(err, ser::Error::UnsignedIntegerExceededRange(u64::MAX));
 }
 
 #[test]
@@ -161,11 +158,11 @@ fn cstring_null_bytes_error() {
     fn verify_doc(doc: Document) {
         let mut vec = Vec::new();
         assert!(matches!(
-            doc.to_writer(&mut vec).unwrap_err(),
+            doc.to_writer(&mut vec).unwrap_err().strip_path(),
             ser::Error::InvalidCString(_)
         ));
         assert!(matches!(
-            to_vec(&doc).unwrap_err(),
+            to_vec(&doc).unwrap_err().strip_path(),
             ser::Error::InvalidCString(_)
         ));
     }
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 1720d7dc..595cc312 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -1116,3 +1116,92 @@ fn fuzz_regression_00() {
     let buf: &[u8] = &[227, 0, 35, 4, 2, 0, 255, 255, 255, 127, 255, 255, 255, 47];
     let _ = crate::from_slice::<Document>(buf);
 }
+
+#[cfg(feature = "serde_path_to_error")]
+mod serde_path_to_error {
+    use super::*;
+
+    #[derive(Serialize, Deserialize, Debug)]
+    struct Foo {
+        one: Bar,
+        two: Bar,
+    }
+
+    #[derive(Serialize, Deserialize, Debug)]
+    struct Bar {
+        value: u64,
+    }
+
+    #[test]
+    fn de() {
+        let src = doc! {
+            "one": {
+                "value": 42,
+            },
+            "two": {
+                "value": "hello",
+            },
+        };
+        let result: Result<Foo, _> = crate::from_document(src);
+        assert!(result.is_err());
+        match result.unwrap_err() {
+            crate::de::Error::WithPath { source: _, path } => {
+                assert_eq!("two.value", path.to_string())
+            }
+            e => panic!("unexpected error: {:?}", e),
+        }
+    }
+
+    #[test]
+    fn de_raw() {
+        let src = rawdoc! {
+            "one": {
+                "value": 42,
+            },
+            "two": {
+                "value": "hello",
+            },
+        }
+        .into_bytes();
+        let result: Result<Foo, _> = crate::from_slice(&src);
+        assert!(result.is_err());
+        match result.unwrap_err() {
+            crate::de::Error::WithPath { source: _, path } => {
+                assert_eq!("two.value", path.to_string())
+            }
+            e => panic!("unexpected error: {:?}", e),
+        }
+    }
+
+    #[test]
+    fn ser() {
+        let src = Foo {
+            one: Bar { value: 42 },
+            two: Bar { value: u64::MAX },
+        };
+        let result = crate::to_bson(&src);
+        assert!(result.is_err());
+        match result.unwrap_err() {
+            crate::ser::Error::WithPath { source: _, path } => {
+                assert_eq!("two.value", path.to_string())
+            }
+            e => panic!("unexpected error: {:?}", e),
+        }
+    }
+
+    #[test]
+    fn ser_raw() {
+        let src = Foo {
+            one: Bar { value: 42 },
+            two: Bar { value: u64::MAX },
+        };
+        let result = crate::to_vec(&src);
+        assert!(result.is_err());
+        match result.unwrap_err() {
+            crate::ser::Error::WithPath { source: _, path } => {
+                assert_eq!("two.value", path.to_string())
+            }
+            e => panic!("unexpected error: {:?}", e),
+        }
+    }
+}

From 20c56f03e635d04849c3a27fdc0f1e89e2df4b1f Mon Sep 17 00:00:00 2001
From: Asger Hautop Drewsen <asger@tyilo.com>
Date: Tue, 27 Aug 2024 17:51:26 +0200
Subject: [PATCH 075/156] RUST-2017 Add method to construct an `ObjectId` from
 its parts (#492)

---------

Co-authored-by: Abraham Egnor <abraham.egnor@mongodb.com>
Co-authored-by: Isabel Atkinson <isabelatkinson@gmail.com>
---
 src/oid.rs               | 41 +++++++++++++++++++++++-----------------
 src/tests/modules/oid.rs | 15 +++++++++++++++
 2 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/src/oid.rs b/src/oid.rs
index 9cec640e..8281d802 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -166,20 +166,12 @@ impl ObjectId {
     /// Generates a new [`ObjectId`], represented in bytes.
     /// See the [docs](http://www.mongodb.com/docs/manual/reference/object-id/)
     /// for more information.
-    pub fn new() -> ObjectId {
-        let timestamp = ObjectId::gen_timestamp();
-        let process_id = ObjectId::gen_process_id();
-        let counter = ObjectId::gen_count();
-
-        let mut buf: [u8; 12] = [0; 12];
-        buf[TIMESTAMP_OFFSET..(TIMESTAMP_SIZE + TIMESTAMP_OFFSET)]
-            .clone_from_slice(&timestamp[..TIMESTAMP_SIZE]);
-        buf[PROCESS_ID_OFFSET..(PROCESS_ID_SIZE + PROCESS_ID_OFFSET)]
-            .clone_from_slice(&process_id[..PROCESS_ID_SIZE]);
-        buf[COUNTER_OFFSET..(COUNTER_SIZE + COUNTER_OFFSET)]
-            .clone_from_slice(&counter[..COUNTER_SIZE]);
-
-        ObjectId::from_bytes(buf)
+    pub fn new() -> Self {
+        let timestamp = Self::gen_timestamp();
+        let process_id = Self::gen_process_id();
+        let counter = Self::gen_count();
+
+        Self::from_parts(timestamp, process_id, counter)
     }
 
     /// Constructs a new ObjectId wrapper around the raw byte representation.
@@ -187,6 +179,21 @@ impl ObjectId {
         ObjectId { id: bytes }
     }
 
+    /// Construct an `ObjectId` from its parts.
+    /// See the [docs](http://www.mongodb.com/docs/manual/reference/object-id/)
+    /// for more information.
+    pub fn from_parts(seconds_since_epoch: u32, process_id: [u8; 5], counter: [u8; 3]) -> Self {
+        let mut bytes = [0; 12];
+
+        bytes[TIMESTAMP_OFFSET..(TIMESTAMP_OFFSET + TIMESTAMP_SIZE)]
+            .clone_from_slice(&u32::to_be_bytes(seconds_since_epoch));
+        bytes[PROCESS_ID_OFFSET..(PROCESS_ID_OFFSET + PROCESS_ID_SIZE)]
+            .clone_from_slice(&process_id);
+        bytes[COUNTER_OFFSET..(COUNTER_OFFSET + COUNTER_SIZE)].clone_from_slice(&counter);
+
+        Self::from_bytes(bytes)
+    }
+
     /// Creates an ObjectID using a 12-byte (24-char) hexadecimal string.
     pub fn parse_str(s: impl AsRef<str>) -> Result<ObjectId> {
         let s = s.as_ref();
@@ -237,8 +244,7 @@ impl ObjectId {
     }
 
     /// Generates a new timestamp representing the current seconds since epoch.
-    /// Represented in Big Endian.
-    fn gen_timestamp() -> [u8; 4] {
+    fn gen_timestamp() -> u32 {
         #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
         let timestamp: u32 = (js_sys::Date::now() / 1000.0) as u32;
         #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
@@ -248,7 +254,8 @@ impl ObjectId {
             .as_secs()
             .try_into()
             .unwrap(); // will succeed until 2106 since timestamp is unsigned
-        timestamp.to_be_bytes()
+
+        timestamp
     }
 
     /// Generate a random 5-byte array.
diff --git a/src/tests/modules/oid.rs b/src/tests/modules/oid.rs
index b875eaa2..6bd7bccd 100644
--- a/src/tests/modules/oid.rs
+++ b/src/tests/modules/oid.rs
@@ -58,3 +58,18 @@ fn fromstr_oid() {
     let actual_s = hex::encode(oid_res.unwrap().bytes());
     assert_eq!(s, &actual_s, "parsed and expected oids differ");
 }
+
+#[test]
+fn oid_from_parts() {
+    let _guard = LOCK.run_concurrently();
+    let seconds_since_epoch = 123;
+    let process_id = [4, 5, 6, 7, 8];
+    let counter = [9, 10, 11];
+    let oid = ObjectId::from_parts(seconds_since_epoch, process_id, counter);
+    assert_eq!(
+        oid.timestamp().timestamp_millis(),
+        i64::from(seconds_since_epoch) * 1000
+    );
+    assert_eq!(&oid.bytes()[4..9], &process_id);
+    assert_eq!(&oid.bytes()[9..], &counter);
+}

From 28e39259c14a9e1fe7ccc598521e7749f55a7322 Mon Sep 17 00:00:00 2001
From: NineLord <35367897+NineLord@users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:31:37 +0300
Subject: [PATCH 076/156] RUST-2027 Impl Hash/Eq for BSON (#495)

---
 Cargo.toml                |  2 ++
 README.md                 |  1 +
 src/binary.rs             |  2 +-
 src/bson.rs               | 44 +++++++++++++++++++++++++++++++++++++--
 src/decimal128.rs         |  2 +-
 src/document.rs           | 12 +++++++++++
 src/tests/modules/bson.rs | 16 ++++++++++++++
 7 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 5a1ca73f..7876a930 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -43,6 +43,8 @@ chrono-0_4 = ["chrono"]
 uuid-1 = []
 # if enabled, include API for interfacing with time 0.3
 time-0_3 = []
+# If enabled, implement Hash/Eq for Bson and Document
+hashable = []
 serde_path_to_error = ["dep:serde_path_to_error"]
 # if enabled, include serde_with interop.
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
diff --git a/README.md b/README.md
index 196cf7de..149947bf 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | serde_path_to_error  | no |
+| `hashable`   | Implement `core::hash::Hash` and `std::cmp::Eq` on `Bson` and `Document`.                  | n/a                | no      |
 
 ## Overview of the BSON Format
 
diff --git a/src/binary.rs b/src/binary.rs
index 2a6d0fa3..18cf8a3d 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -6,7 +6,7 @@ use std::{
 };
 
 /// Represents a BSON binary value.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct Binary {
     /// The subtype of the bytes.
     pub subtype: BinarySubtype,
diff --git a/src/bson.rs b/src/bson.rs
index 5ecb06dd..01ce1bb3 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -24,6 +24,7 @@
 use std::{
     convert::{TryFrom, TryInto},
     fmt::{self, Debug, Display, Formatter},
+    hash::Hash,
 };
 
 use serde_json::{json, Value};
@@ -87,6 +88,44 @@ pub enum Bson {
 /// Alias for `Vec<Bson>`.
 pub type Array = Vec<Bson>;
 
+#[cfg(feature = "hashable")]
+impl Hash for Bson {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        match self {
+            Bson::Double(double) => {
+                if *double == 0.0_f64 {
+                    // There are 2 zero representations, +0 and -0, which
+                    // compare equal but have different bits. We use the +0 hash
+                    // for both so that hash(+0) == hash(-0).
+                    0.0_f64.to_bits().hash(state);
+                } else {
+                    double.to_bits().hash(state);
+                }
+            }
+            Bson::String(x) => x.hash(state),
+            Bson::Array(x) => x.hash(state),
+            Bson::Document(x) => x.hash(state),
+            Bson::Boolean(x) => x.hash(state),
+            Bson::RegularExpression(x) => x.hash(state),
+            Bson::JavaScriptCode(x) => x.hash(state),
+            Bson::JavaScriptCodeWithScope(x) => x.hash(state),
+            Bson::Int32(x) => x.hash(state),
+            Bson::Int64(x) => x.hash(state),
+            Bson::Timestamp(x) => x.hash(state),
+            Bson::Binary(x) => x.hash(state),
+            Bson::ObjectId(x) => x.hash(state),
+            Bson::DateTime(x) => x.hash(state),
+            Bson::Symbol(x) => x.hash(state),
+            Bson::Decimal128(x) => x.hash(state),
+            Bson::DbPointer(x) => x.hash(state),
+            Bson::Null | Bson::Undefined | Bson::MaxKey | Bson::MinKey => (),
+        }
+    }
+}
+
+#[cfg(feature = "hashable")]
+impl Eq for Bson {}
+
 impl Display for Bson {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match *self {
@@ -1046,7 +1085,7 @@ impl Timestamp {
 }
 
 /// Represents a BSON regular expression value.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct Regex {
     /// The regex pattern to match.
     pub pattern: String,
@@ -1081,6 +1120,7 @@ impl Display for Regex {
 
 /// Represents a BSON code with scope value.
 #[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "hashable", derive(Eq, Hash))]
 pub struct JavaScriptCodeWithScope {
     /// The JavaScript code.
     pub code: String,
@@ -1096,7 +1136,7 @@ impl Display for JavaScriptCodeWithScope {
 }
 
 /// Represents a DBPointer. (Deprecated)
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct DbPointer {
     pub(crate) namespace: String,
     pub(crate) id: oid::ObjectId,
diff --git a/src/decimal128.rs b/src/decimal128.rs
index 7316c790..7846d3cd 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -21,7 +21,7 @@ use bitvec::prelude::*;
 /// # }
 /// # example().unwrap()
 /// ```
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Decimal128 {
     /// BSON bytes containing the decimal128. Stored for round tripping.
     pub(crate) bytes: [u8; 16],
diff --git a/src/document.rs b/src/document.rs
index fa408877..ebfcc622 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -1,5 +1,7 @@
 //! A BSON document represented as an associative HashMap with insertion ordering.
 
+#[cfg(feature = "hashable")]
+use std::hash::Hash;
 use std::{
     error,
     fmt::{self, Debug, Display, Formatter},
@@ -56,6 +58,7 @@ impl error::Error for ValueAccessError {}
 
 /// A BSON document represented as an associative HashMap with insertion ordering.
 #[derive(Clone, PartialEq)]
+#[cfg_attr(feature = "hashable", derive(Eq))]
 pub struct Document {
     inner: IndexMap<String, Bson, RandomState>,
 }
@@ -66,6 +69,15 @@ impl Default for Document {
     }
 }
 
+#[cfg(feature = "hashable")]
+impl Hash for Document {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        let mut entries = Vec::from_iter(&self.inner);
+        entries.sort_unstable_by(|a, b| a.0.cmp(b.0));
+        entries.hash(state);
+    }
+}
+
 impl Display for Document {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         fmt.write_str("{")?;
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 8bb66f8b..d5362d20 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -486,3 +486,19 @@ fn debug_print() {
     assert_eq!(format!("{:?}", doc), normal_print);
     assert_eq!(format!("{:#?}", doc), pretty_print);
 }
+
+#[cfg(feature = "hashable")]
+#[test]
+fn test_hashable() {
+    let mut map = std::collections::HashMap::new();
+    map.insert(bson!({"a":1, "b": 2}), 1);
+    map.insert(Bson::Null, 2);
+    map.insert(Bson::Undefined, 3);
+
+    let key = bson!({"b": 2, "a":1});
+    assert_eq!(map.remove(&key), Some(1));
+    assert_eq!(map.remove(&Bson::Undefined), Some(3));
+    assert_eq!(map.remove(&Bson::Null), Some(2));
+
+    assert!(map.is_empty());
+}

From 692cd752e94efeef215b0e51c676be59e689183d Mon Sep 17 00:00:00 2001
From: Arthur Silva <arthurprs@gmail.com>
Date: Mon, 9 Sep 2024 16:42:48 +0200
Subject: [PATCH 077/156] RUST-2028 Fix Decimal128 panic when parsing strings
 w/o a char boundary at idx 34 (#496)

---
 src/decimal128.rs   |  8 ++++++++
 src/raw/test/mod.rs | 12 ++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/src/decimal128.rs b/src/decimal128.rs
index 7846d3cd..546b9619 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -333,6 +333,7 @@ pub enum ParseError {
     Overflow,
     Underflow,
     InexactRounding,
+    Unparseable,
 }
 
 impl fmt::Display for ParseError {
@@ -344,6 +345,7 @@ impl fmt::Display for ParseError {
             ParseError::Overflow => write!(f, "overflow"),
             ParseError::Underflow => write!(f, "underflow"),
             ParseError::InexactRounding => write!(f, "inexact rounding"),
+            ParseError::Unparseable => write!(f, "unparseable"),
         }
     }
 }
@@ -469,6 +471,12 @@ impl std::str::FromStr for ParsedDecimal128 {
 }
 
 fn round_decimal_str(s: &str, precision: usize) -> Result<&str, ParseError> {
+    // TODO: In 1.80+ there's split_at_checked to make sure the split doesn't
+    // panic if the index doesn't falls at a codepoint boundary, until then
+    // we can check it with s.is_char_boundary(precision)
+    if !s.is_char_boundary(precision) {
+        return Err(ParseError::Unparseable);
+    }
     let (pre, post) = s.split_at(precision);
     // Any nonzero trimmed digits mean it would be an imprecise round.
     if post.chars().any(|c| c != '0') {
diff --git a/src/raw/test/mod.rs b/src/raw/test/mod.rs
index 67b42732..11f6bcd3 100644
--- a/src/raw/test/mod.rs
+++ b/src/raw/test/mod.rs
@@ -10,10 +10,22 @@ use crate::{
     Binary,
     Bson,
     DateTime,
+    Decimal128,
     Regex,
     Timestamp,
 };
 
+#[test]
+fn test_decimal128_doesnt_panic_on_bad_codepoint_boundary() {
+    use crate::decimal128::ParseError;
+    use std::str::FromStr;
+    // idx 34 (Coefficient::MAX_DIGITS) on this string isn't a valid codepoint boundary
+    assert!(matches!(
+        Decimal128::from_str("111111111111111111111111111111111❤"),
+        Err(ParseError::Unparseable)
+    ))
+}
+
 #[test]
 fn string_from_document() {
     let rawdoc = rawdoc! {

From 8e0fb3b4eae2f465d3ee1f8cfbc5fd60bc381616 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 11 Sep 2024 13:23:38 -0400
Subject: [PATCH 078/156] release v2.12.0 (#498)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 7876a930..5153b2fe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.11.0"
+version = "2.12.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index 149947bf..c8ad00d3 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.11.0"
+bson = "2.12.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 69ad9db0..e68cbd68 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.11.0"
+//! bson = "2.12.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From 0fbdeeffd3e9d4d811d119e19a9657c43d644f37 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Wed, 11 Sep 2024 14:39:20 -0400
Subject: [PATCH 079/156] RUST-2023 Add wrapper type for utf-8 lossy
 deserialization (#497)

---
 src/de/raw.rs                                |  7 ++-
 src/document.rs                              |  1 +
 src/lib.rs                                   |  5 +-
 src/serde_helpers.rs                         | 43 ++++++++++++++++
 src/tests/modules/serializer_deserializer.rs |  1 +
 src/tests/serde_helpers.rs                   | 54 +++++++++++++++++++-
 src/tests/spec/corpus.rs                     |  4 ++
 7 files changed, 111 insertions(+), 4 deletions(-)

diff --git a/src/de/raw.rs b/src/de/raw.rs
index 6501c325..58a2d2bc 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -18,7 +18,7 @@ use crate::{
         RAW_BSON_NEWTYPE,
         RAW_DOCUMENT_NEWTYPE,
     },
-    serde_helpers::HUMAN_READABLE_NEWTYPE,
+    serde_helpers::{HUMAN_READABLE_NEWTYPE, UTF8_LOSSY_NEWTYPE},
     spec::{BinarySubtype, ElementType},
     uuid::UUID_NEWTYPE_NAME,
     DateTime,
@@ -297,6 +297,11 @@ impl<'de> serde::de::Deserializer<'de> for Deserializer<'de> {
                 inner.options.human_readable = true;
                 visitor.visit_newtype_struct(inner)
             }
+            UTF8_LOSSY_NEWTYPE => {
+                let mut inner = self;
+                inner.options.utf8_lossy = true;
+                visitor.visit_newtype_struct(inner)
+            }
             _ => visitor.visit_newtype_struct(self),
         }
     }
diff --git a/src/document.rs b/src/document.rs
index ebfcc622..3a5f189f 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -599,6 +599,7 @@ impl Document {
     /// This is mainly useful when reading raw BSON returned from a MongoDB server, which
     /// in rare cases can contain invalidly truncated strings (<https://jira.mongodb.org/browse/SERVER-24007>).
     /// For most use cases, `Document::from_reader` can be used instead.
+    #[deprecated = "use bson::serde_helpers::Utf8LossyDeserialization"]
     pub fn from_reader_utf8_lossy<R: Read>(mut reader: R) -> crate::de::Result<Document> {
         Self::decode(&mut reader, true)
     }
diff --git a/src/lib.rs b/src/lib.rs
index e68cbd68..e7ff11b3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -295,9 +295,7 @@ pub use self::{
         from_document,
         from_document_with_options,
         from_reader,
-        from_reader_utf8_lossy,
         from_slice,
-        from_slice_utf8_lossy,
         Deserializer,
         DeserializerOptions,
     },
@@ -328,6 +326,9 @@ pub use self::{
     uuid::{Uuid, UuidRepresentation},
 };
 
+#[allow(deprecated)]
+pub use self::de::{from_reader_utf8_lossy, from_slice_utf8_lossy,};
+
 #[macro_use]
 mod macros;
 pub mod binary;
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index eb86578f..56702b8e 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -886,3 +886,46 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for HumanReadable<T> {
         deserializer.deserialize_newtype_struct(HUMAN_READABLE_NEWTYPE, V(PhantomData))
     }
 }
+
+/// Wrapper type for deserializing BSON bytes with invalid UTF-8 sequences.
+///
+/// Any invalid UTF-8 strings contained in the wrapped type will be replaced with the Unicode
+/// replacement character. This wrapper type only has an effect when deserializing from BSON bytes.
+///
+/// This wrapper type has no impact on serialization. Serializing a `Utf8LossyDeserialization<T>`
+/// will call the `serialize` method for the wrapped `T`.
+#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct Utf8LossyDeserialization<T>(pub T);
+
+pub(crate) const UTF8_LOSSY_NEWTYPE: &str = "$__bson_private_utf8_lossy";
+
+impl<T: Serialize> Serialize for Utf8LossyDeserialization<T> {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        self.0.serialize(serializer)
+    }
+}
+
+impl<'de, T: Deserialize<'de>> Deserialize<'de> for Utf8LossyDeserialization<T> {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        struct V<T>(PhantomData<fn() -> T>);
+        impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
+            type Value = Utf8LossyDeserialization<T>;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+                formatter.write_str("Utf8Lossy wrapper")
+            }
+            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                T::deserialize(deserializer).map(Utf8LossyDeserialization)
+            }
+        }
+        deserializer.deserialize_newtype_struct(UTF8_LOSSY_NEWTYPE, V(PhantomData))
+    }
+}
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 2f476841..1083e985 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -73,6 +73,7 @@ fn test_encode_decode_utf8_string_invalid() {
     doc.to_writer(&mut buf).unwrap();
 
     let expected = doc! { "key": "��" };
+    #[allow(deprecated)]
     let decoded = Document::from_reader_utf8_lossy(&mut Cursor::new(buf)).unwrap();
     assert_eq!(decoded, expected);
 }
diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs
index 2e6453c1..805aa93b 100644
--- a/src/tests/serde_helpers.rs
+++ b/src/tests/serde_helpers.rs
@@ -1,6 +1,11 @@
+use core::str;
+
 use serde::{de::Visitor, Deserialize, Serialize};
 
-use crate::serde_helpers::HumanReadable;
+use crate::{
+    from_slice,
+    serde_helpers::{HumanReadable, Utf8LossyDeserialization},
+};
 
 #[test]
 fn human_readable_wrapper() {
@@ -135,3 +140,50 @@ fn human_readable_wrapper() {
     let raw_tripped: Data = crate::from_slice(&bytes).unwrap();
     assert_eq!(&raw_tripped, &expected);
 }
+
+#[test]
+#[allow(dead_code)] // suppress warning for unread fields
+fn utf8_lossy_wrapper() {
+    let invalid_bytes = b"\x80\xae".to_vec();
+    let invalid_string = unsafe { String::from_utf8_unchecked(invalid_bytes) };
+
+    let both_strings_invalid_bytes =
+        rawdoc! { "s1": invalid_string.clone(), "s2": invalid_string.clone() }.into_bytes();
+    let first_string_invalid_bytes =
+        rawdoc! { "s1": invalid_string.clone(), "s2": ":)" }.into_bytes();
+
+    let expected_replacement = "��".to_string();
+
+    #[derive(Debug, Deserialize)]
+    struct NoUtf8Lossy {
+        s1: String,
+        s2: String,
+    }
+
+    from_slice::<NoUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
+
+    let s = from_slice::<Utf8LossyDeserialization<NoUtf8Lossy>>(&both_strings_invalid_bytes)
+        .unwrap()
+        .0;
+    assert_eq!(s.s1, expected_replacement);
+    assert_eq!(s.s2, expected_replacement);
+
+    #[derive(Debug, Deserialize)]
+    struct FirstStringUtf8Lossy {
+        s1: Utf8LossyDeserialization<String>,
+        s2: String,
+    }
+
+    let s = from_slice::<FirstStringUtf8Lossy>(&first_string_invalid_bytes).unwrap();
+    assert_eq!(s.s1.0, expected_replacement);
+    assert_eq!(&s.s2, ":)");
+
+    from_slice::<FirstStringUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
+
+    let s =
+        from_slice::<Utf8LossyDeserialization<FirstStringUtf8Lossy>>(&both_strings_invalid_bytes)
+            .unwrap()
+            .0;
+    assert_eq!(s.s1.0, expected_replacement);
+    assert_eq!(s.s2, expected_replacement);
+}
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 95e63988..6df2487e 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -7,6 +7,7 @@ use std::{
 
 use crate::{
     raw::{RawBsonRef, RawDocument},
+    serde_helpers::Utf8LossyDeserialization,
     tests::LOCK,
     Bson,
     Document,
@@ -549,12 +550,15 @@ fn run_test(test: TestFile) {
         crate::from_reader::<_, Document>(bson.as_slice()).expect_err(description.as_str());
 
         if decode_error.description.contains("invalid UTF-8") {
+            #[allow(deprecated)]
             crate::from_reader_utf8_lossy::<_, Document>(bson.as_slice()).unwrap_or_else(|err| {
                 panic!(
                     "{}: utf8_lossy should not fail (failed with {:?})",
                     description, err
                 )
             });
+            crate::from_slice::<Utf8LossyDeserialization<Document>>(bson.as_slice())
+                .expect(&description);
         }
     }
 

From 401f638ba70288ac19a1a2124ddc95805ebc828c Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 19 Sep 2024 12:00:31 -0400
Subject: [PATCH 080/156] release v2.13.0 (#499)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 5153b2fe..1fb1626b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.12.0"
+version = "2.13.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index c8ad00d3..875724a6 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.12.0"
+bson = "2.13.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index e7ff11b3..ab7c2c0f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.12.0"
+//! bson = "2.13.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From 31c92ad66056d01ba12a578b352a2ee45687287c Mon Sep 17 00:00:00 2001
From: "Tristan F." <LeoDog896@hotmail.com>
Date: Tue, 15 Oct 2024 13:36:25 -0700
Subject: [PATCH 081/156] test(fuzz): read -> write bson (#500)

---
 fuzz/Cargo.toml                                 |  6 +++++-
 fuzz/fuzz_targets/deserialize.rs                |  8 ++++++--
 fuzz/fuzz_targets/iterate.rs                    |  3 ++-
 fuzz/fuzz_targets/raw_deserialize.rs            |  8 ++++++--
 fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs | 11 +++++++++++
 5 files changed, 30 insertions(+), 6 deletions(-)
 create mode 100644 fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs

diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index e6fd43eb..25c60712 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -27,4 +27,8 @@ path = "fuzz_targets/iterate.rs"
 
 [[bin]]
 name = "raw_deserialize"
-path = "fuzz_targets/raw_deserialize.rs"
\ No newline at end of file
+path = "fuzz_targets/raw_deserialize.rs"
+
+[[bin]]
+name = "raw_deserialize_utf8_lossy"
+path = "fuzz_targets/raw_deserialize_utf8_lossy.rs"
diff --git a/fuzz/fuzz_targets/deserialize.rs b/fuzz/fuzz_targets/deserialize.rs
index c41599d9..4995394d 100644
--- a/fuzz/fuzz_targets/deserialize.rs
+++ b/fuzz/fuzz_targets/deserialize.rs
@@ -1,10 +1,14 @@
 #![no_main]
-#[macro_use] extern crate libfuzzer_sys;
+#[macro_use]
+extern crate libfuzzer_sys;
 extern crate bson;
 
 use bson::Document;
 use std::io::Cursor;
 
 fuzz_target!(|buf: &[u8]| {
-    let _ = Document::from_reader(&mut Cursor::new(&buf[..]));
+    if let Ok(doc) = Document::from_reader(&mut Cursor::new(&buf[..])) {
+        let mut vec = Vec::with_capacity(buf.len());
+        let _ = doc.to_writer(&mut vec);
+    }
 });
diff --git a/fuzz/fuzz_targets/iterate.rs b/fuzz/fuzz_targets/iterate.rs
index de7095e5..7dece7ca 100644
--- a/fuzz/fuzz_targets/iterate.rs
+++ b/fuzz/fuzz_targets/iterate.rs
@@ -1,5 +1,6 @@
 #![no_main]
-#[macro_use] extern crate libfuzzer_sys;
+#[macro_use]
+extern crate libfuzzer_sys;
 extern crate bson;
 use bson::RawDocument;
 
diff --git a/fuzz/fuzz_targets/raw_deserialize.rs b/fuzz/fuzz_targets/raw_deserialize.rs
index e0a9012a..4fb91b09 100644
--- a/fuzz/fuzz_targets/raw_deserialize.rs
+++ b/fuzz/fuzz_targets/raw_deserialize.rs
@@ -1,8 +1,12 @@
 #![no_main]
-#[macro_use] extern crate libfuzzer_sys;
+#[macro_use]
+extern crate libfuzzer_sys;
 extern crate bson;
 use bson::Document;
 
 fuzz_target!(|buf: &[u8]| {
-    let _ = bson::from_slice::<Document>(buf);
+    if let Ok(doc) = bson::from_slice::<Document>(buf) {
+        let mut vec = Vec::with_capacity(buf.len());
+        let _ = doc.to_writer(&mut vec);
+    }
 });
diff --git a/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs b/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
new file mode 100644
index 00000000..fb5343b4
--- /dev/null
+++ b/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
@@ -0,0 +1,11 @@
+#![no_main]
+#[macro_use] extern crate libfuzzer_sys;
+extern crate bson;
+use bson::Document;
+
+fuzz_target!(|buf: &[u8]| {
+    if let Ok(doc) = bson::from_slice_utf8_lossy::<Document>(buf) {
+        let mut vec = Vec::with_capacity(buf.len());
+        let _ = doc.to_writer(&mut vec);
+    }
+});

From e0c5ca55bf8ce92037ed7a229cf4cf2bdb5fcf5b Mon Sep 17 00:00:00 2001
From: Jada Lilleboe <82007190+jadalilleboe@users.noreply.github.com>
Date: Tue, 22 Oct 2024 14:50:52 -0400
Subject: [PATCH 082/156] RUST-2019 Respect pretty printing flag for Document
 and Bson (#501)

RUST-2019 Respect pretty printing for Bson and Document
---
 src/bson.rs                   |  39 +++++++++--
 src/document.rs               |  49 ++++++++++---
 src/tests/modules/document.rs | 125 ++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+), 13 deletions(-)

diff --git a/src/bson.rs b/src/bson.rs
index 01ce1bb3..9c732c50 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -134,19 +134,48 @@ impl Display for Bson {
             Bson::Array(ref vec) => {
                 fmt.write_str("[")?;
 
+                let indent = fmt.width().unwrap_or(2);
+                let indent_str = " ".repeat(indent);
+
                 let mut first = true;
                 for bson in vec {
                     if !first {
                         fmt.write_str(", ")?;
                     }
-
-                    write!(fmt, "{}", bson)?;
+                    if fmt.alternate() {
+                        write!(fmt, "\n{indent_str}")?;
+                        match bson {
+                            Bson::Array(_arr) => {
+                                let new_indent = indent + 2;
+                                write!(fmt, "{bson:#new_indent$}")?;
+                            }
+                            Bson::Document(ref doc) => {
+                                let new_indent = indent + 2;
+                                write!(fmt, "{doc:#new_indent$}")?;
+                            }
+                            _ => {
+                                write!(fmt, "{}", bson)?;
+                            }
+                        }
+                    } else {
+                        write!(fmt, "{}", bson)?;
+                    }
                     first = false;
                 }
-
-                fmt.write_str("]")
+                if fmt.alternate() && !vec.is_empty() {
+                    let closing_bracket_indent_str = " ".repeat(indent - 2);
+                    write!(fmt, "\n{closing_bracket_indent_str}]")
+                } else {
+                    fmt.write_str("]")
+                }
+            }
+            Bson::Document(ref doc) => {
+                if fmt.alternate() {
+                    write!(fmt, "{doc:#}")
+                } else {
+                    write!(fmt, "{doc}")
+                }
             }
-            Bson::Document(ref doc) => write!(fmt, "{}", doc),
             Bson::Boolean(b) => write!(fmt, "{}", b),
             Bson::Null => write!(fmt, "null"),
             Bson::RegularExpression(ref x) => write!(fmt, "{}", x),
diff --git a/src/document.rs b/src/document.rs
index 3a5f189f..18b57851 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -80,21 +80,54 @@ impl Hash for Document {
 
 impl Display for Document {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        fmt.write_str("{")?;
+        let indent = fmt.width().unwrap_or(2);
+        let indent_str = " ".repeat(indent);
+
+        write!(fmt, "{{")?;
+        if fmt.alternate() && !self.inner.is_empty() {
+            fmt.write_str("\n")?;
+        }
 
         let mut first = true;
         for (k, v) in self {
-            if first {
-                first = false;
-                fmt.write_str(" ")?;
-            } else {
-                fmt.write_str(", ")?;
+            if !fmt.alternate() {
+                if first {
+                    first = false;
+                    write!(fmt, " ")?;
+                } else {
+                    fmt.write_str(", ")?;
+                }
+                write!(fmt, "\"{}\": {}", k, v)?;
             }
 
-            write!(fmt, "\"{}\": {}", k, v)?;
+            if fmt.alternate() {
+                if first {
+                    first = false;
+                } else {
+                    fmt.write_str(",\n")?;
+                }
+                match v {
+                    Bson::Document(ref doc) => {
+                        let new_indent = indent + 2;
+                        write!(fmt, "{indent_str}\"{}\": {doc:#new_indent$}", k)?;
+                    }
+                    Bson::Array(_arr) => {
+                        let new_indent = indent + 2;
+                        write!(fmt, "{indent_str}\"{}\": {v:#new_indent$}", k)?;
+                    }
+                    _ => {
+                        write!(fmt, "{indent_str}\"{}\": {}", k, v)?;
+                    }
+                }
+            }
         }
 
-        write!(fmt, "{}}}", if !first { " " } else { "" })
+        let closing_bracket_indent_str = " ".repeat(indent - 2);
+        if fmt.alternate() && !self.inner.is_empty() {
+            write!(fmt, "\n{closing_bracket_indent_str}}}")
+        } else {
+            write!(fmt, "{}}}", if !first { " " } else { "" })
+        }
     }
 }
 
diff --git a/src/tests/modules/document.rs b/src/tests/modules/document.rs
index 85fc62ff..e8be3199 100644
--- a/src/tests/modules/document.rs
+++ b/src/tests/modules/document.rs
@@ -245,3 +245,128 @@ fn extend() {
         },
     );
 }
+
+#[test]
+fn test_display_empty_doc() {
+    let empty_expectation = "{}";
+    let doc = doc! {};
+    let doc_display = format!("{doc}");
+    assert_eq!(empty_expectation, doc_display);
+
+    let doc_display_pretty = format!("{doc:#}");
+    assert_eq!(empty_expectation, doc_display_pretty);
+}
+
+#[test]
+fn test_display_doc() {
+    let doc = doc! {
+        "hello": "world"
+    };
+
+    let doc_display_expectation = "{ \"hello\": \"world\" }";
+    assert_eq!(doc_display_expectation, format!("{doc}"));
+
+    let doc_display_pretty_expectation = r#"{
+  "hello": "world"
+}"#;
+    assert_eq!(doc_display_pretty_expectation, format!("{doc:#}"));
+}
+
+#[test]
+fn test_display_nested_doc() {
+    let doc = doc! {
+        "hello": {
+            "hello": 2
+        }
+    };
+
+    let doc_display_expectation = "{ \"hello\": { \"hello\": 2 } }";
+    assert_eq!(doc_display_expectation, format!("{doc}"));
+
+    let doc_display_pretty_expectation = r#"{
+  "hello": {
+    "hello": 2
+  }
+}"#;
+    let formatted = format!("{doc:#}");
+    assert_eq!(doc_display_pretty_expectation, formatted);
+}
+
+#[test]
+fn test_display_doc_with_array() {
+    let doc = doc! {
+        "hello": [1, 2, 3]
+    };
+
+    let doc_display_expectation = "{ \"hello\": [1, 2, 3] }";
+    assert_eq!(doc_display_expectation, format!("{doc}"));
+
+    let doc_display_pretty_expectation = r#"{
+  "hello": [
+    1, 
+    2, 
+    3
+  ]
+}"#;
+    let formatted = format!("{doc:#}");
+    assert_eq!(doc_display_pretty_expectation, formatted);
+
+    let nested_array_doc = doc! {
+        "a": [1, [1, 2]]
+    };
+
+    let expectation = r#"{
+  "a": [
+    1, 
+    [
+      1, 
+      2
+    ]
+  ]
+}"#;
+    assert_eq!(expectation, format!("{nested_array_doc:#}"));
+}
+
+#[test]
+fn test_pretty_printing() {
+    let d = doc! { "hello": "world!", "world": "hello", "key": "val" };
+    let expected = r#"{ "hello": "world!", "world": "hello", "key": "val" }"#;
+    let formatted = format!("{d}");
+    assert_eq!(
+        expected, formatted,
+        "expected:\n{expected}\ngot:\n{formatted}"
+    );
+
+    let d = doc! { "hello": "world!", "nested": { "key": "val", "double": { "a": "thing" } } };
+    let expected = r#"{
+  "hello": "world!",
+  "nested": {
+    "key": "val",
+    "double": {
+      "a": "thing"
+    }
+  }
+}"#;
+    let formatted = format!("{d:#}");
+    assert_eq!(
+        expected, formatted,
+        "expected:\n{expected}\ngot:\n{formatted}"
+    );
+
+    let d =
+        doc! { "hello": "world!", "nested": { "key": "val", "double": { "a": [1, 2], "c": "d"} } };
+    let expected = r#"{
+  "hello": "world!",
+  "nested": {
+    "key": "val",
+    "double": {
+      "a": [
+        1, 
+        2
+      ],
+      "c": "d"
+    }
+  }
+}"#;
+    assert_eq!(expected, format!("{d:#}"));
+}

From f1a08f8a551dcd1f895f12957946a3a6acf266ce Mon Sep 17 00:00:00 2001
From: Jada Lilleboe <82007190+jadalilleboe@users.noreply.github.com>
Date: Wed, 20 Nov 2024 09:42:31 -0500
Subject: [PATCH 083/156] RUST-622 Add document square bracket indexing (#503)

---
 src/bson.rs                   | 15 ++++++++++++
 src/document.rs               | 12 ++++++++++
 src/tests/modules/document.rs | 45 +++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+)

diff --git a/src/bson.rs b/src/bson.rs
index 9c732c50..806fee0b 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -25,6 +25,7 @@ use std::{
     convert::{TryFrom, TryInto},
     fmt::{self, Debug, Display, Formatter},
     hash::Hash,
+    ops::Index,
 };
 
 use serde_json::{json, Value};
@@ -236,6 +237,20 @@ impl Debug for Bson {
     }
 }
 
+impl Index<&str> for Bson {
+    type Output = Bson;
+
+    fn index(&self, index: &str) -> &Self::Output {
+        match *self {
+            Bson::Document(ref doc) => match doc.get(index) {
+                Some(v) => v,
+                None => &Bson::Null,
+            },
+            _ => &Bson::Null,
+        }
+    }
+}
+
 impl From<f32> for Bson {
     fn from(a: f32) -> Bson {
         Bson::Double(a.into())
diff --git a/src/document.rs b/src/document.rs
index 18b57851..b3e24067 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -7,6 +7,7 @@ use std::{
     fmt::{self, Debug, Display, Formatter},
     io::{Read, Write},
     iter::{Extend, FromIterator, IntoIterator},
+    ops::Index,
 };
 
 use ahash::RandomState;
@@ -139,6 +140,17 @@ impl Debug for Document {
     }
 }
 
+impl Index<&str> for Document {
+    type Output = Bson;
+
+    fn index(&self, index: &str) -> &Self::Output {
+        match self.get(index) {
+            Some(v) => v,
+            None => &Bson::Null,
+        }
+    }
+}
+
 /// An iterator over Document entries.
 pub struct IntoIter {
     inner: indexmap::map::IntoIter<String, Bson>,
diff --git a/src/tests/modules/document.rs b/src/tests/modules/document.rs
index e8be3199..c6f5390e 100644
--- a/src/tests/modules/document.rs
+++ b/src/tests/modules/document.rs
@@ -370,3 +370,48 @@ fn test_pretty_printing() {
 }"#;
     assert_eq!(expected, format!("{d:#}"));
 }
+
+#[test]
+fn test_indexing() {
+    let d = doc! {"x": 1};
+    let val = d["x"].as_i32().unwrap();
+    assert_eq!(val, 1);
+
+    let d = doc! {"x": {"y": 100}};
+    let val = d["x"]["y"].as_i32().unwrap();
+    assert_eq!(val, 100);
+
+    let d = doc! {"x" : true};
+    let val = d["x"].as_bool().unwrap();
+    assert!(val);
+
+    let d = doc! {"x": "y"};
+    let val = d["x"].as_str().unwrap();
+    assert_eq!(val, "y");
+
+    let d = doc! {"x": 1.9};
+    let val = d["x"].as_f64().unwrap();
+    assert_eq!(val, 1.9);
+
+    let d = doc! {"x": [1, 2, 3]};
+    let val = d["x"].as_array().unwrap();
+    assert_eq!(val.len(), 3);
+}
+
+#[test]
+fn test_indexing_key_not_found() {
+    let d = doc! {"x": 1};
+    let val = &d["y"];
+    assert!(val.as_null().is_some());
+
+    let d = doc! {"x": {"y": 1}};
+    let val = &d["x"]["z"];
+    assert!(val.as_null().is_some());
+}
+
+#[test]
+fn test_indexing_on_wrong_bson_type() {
+    let d = doc! {"x": {"y": 1}};
+    let val = &d["x"]["y"]["z"];
+    assert!(val.as_null().is_some());
+}

From 937998dd5124ed96d502ce4690074f2b72247803 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 12 Dec 2024 11:17:56 -0500
Subject: [PATCH 084/156] RUST-2121 Bump bson crate MSRV to 1.71.1 (#508)

---
 .evergreen/Cargo.lock.msrv      | 1429 -------------------------------
 .evergreen/MSRV-Cargo.toml.diff |   10 +
 .evergreen/compile-only.sh      |    4 +-
 .evergreen/config.yml           |    6 +-
 README.md                       |    2 +-
 clippy.toml                     |    2 +-
 src/lib.rs                      |    4 +-
 7 files changed, 19 insertions(+), 1438 deletions(-)
 delete mode 100644 .evergreen/Cargo.lock.msrv
 create mode 100644 .evergreen/MSRV-Cargo.toml.diff

diff --git a/.evergreen/Cargo.lock.msrv b/.evergreen/Cargo.lock.msrv
deleted file mode 100644
index 98545ca3..00000000
--- a/.evergreen/Cargo.lock.msrv
+++ /dev/null
@@ -1,1429 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "ahash"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d"
-dependencies = [
- "cfg-if",
- "getrandom",
- "once_cell",
- "version_check",
- "zerocopy",
-]
-
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "ansi_term"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "assert_matches"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
-
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi 0.1.19",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "base64"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
-
-[[package]]
-name = "base64"
-version = "0.21.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
-
-[[package]]
-name = "bit-set"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
-dependencies = [
- "bit-vec",
-]
-
-[[package]]
-name = "bit-vec"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitvec"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
-dependencies = [
- "funty",
- "radium",
- "tap",
- "wyz",
-]
-
-[[package]]
-name = "bson"
-version = "2.7.0"
-dependencies = [
- "ahash",
- "assert_matches",
- "base64 0.13.1",
- "bitvec",
- "chrono",
- "criterion",
- "hex",
- "indexmap",
- "js-sys",
- "once_cell",
- "pretty_assertions",
- "proptest",
- "rand",
- "serde",
- "serde_bytes",
- "serde_json",
- "serde_with 1.14.0",
- "serde_with 3.1.0",
- "time",
- "uuid 0.8.2",
- "uuid 1.1.2",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.12.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
-
-[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
-name = "cast"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
-
-[[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "chrono"
-version = "0.4.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
-dependencies = [
- "iana-time-zone",
- "num-integer",
- "num-traits",
- "serde",
- "winapi",
-]
-
-[[package]]
-name = "clap"
-version = "2.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
-dependencies = [
- "bitflags",
- "textwrap",
- "unicode-width",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
-
-[[package]]
-name = "criterion"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
-dependencies = [
- "atty",
- "cast",
- "clap",
- "criterion-plot",
- "csv",
- "itertools",
- "lazy_static",
- "num-traits",
- "oorandom",
- "plotters",
- "rayon",
- "regex",
- "serde",
- "serde_cbor",
- "serde_derive",
- "serde_json",
- "tinytemplate",
- "walkdir",
-]
-
-[[package]]
-name = "criterion-plot"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
-dependencies = [
- "cast",
- "itertools",
-]
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-deque"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
-dependencies = [
- "cfg-if",
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
-dependencies = [
- "autocfg",
- "cfg-if",
- "crossbeam-utils",
- "memoffset",
- "scopeguard",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "csv"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad"
-dependencies = [
- "csv-core",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "csv-core"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "ctor"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "darling"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
-dependencies = [
- "darling_core 0.13.4",
- "darling_macro 0.13.4",
-]
-
-[[package]]
-name = "darling"
-version = "0.20.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
-dependencies = [
- "darling_core 0.20.3",
- "darling_macro 0.20.3",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.20.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim",
- "syn 2.0.16",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
-dependencies = [
- "darling_core 0.13.4",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.20.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
-dependencies = [
- "darling_core 0.20.3",
- "quote",
- "syn 2.0.16",
-]
-
-[[package]]
-name = "difference"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
-
-[[package]]
-name = "either"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
-
-[[package]]
-name = "errno"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "fastrand"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
-dependencies = [
- "instant",
-]
-
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "funty"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
-
-[[package]]
-name = "getrandom"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "half"
-version = "1.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
-
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
-[[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "hermit-abi"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "iana-time-zone"
-version = "0.1.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "wasm-bindgen",
- "windows",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "ident_case"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
-
-[[package]]
-name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
-dependencies = [
- "autocfg",
- "hashbrown",
- "serde",
-]
-
-[[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "io-lifetimes"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
-dependencies = [
- "hermit-abi 0.3.1",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "itertools"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
-
-[[package]]
-name = "js-sys"
-version = "0.3.62"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "libc"
-version = "0.2.144"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
-
-[[package]]
-name = "libm"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
-
-[[package]]
-name = "log"
-version = "0.4.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "memchr"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-
-[[package]]
-name = "memoffset"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
-dependencies = [
- "autocfg",
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
-dependencies = [
- "autocfg",
- "libm",
-]
-
-[[package]]
-name = "num_cpus"
-version = "1.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
-dependencies = [
- "hermit-abi 0.2.6",
- "libc",
-]
-
-[[package]]
-name = "num_threads"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
-
-[[package]]
-name = "oorandom"
-version = "11.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
-
-[[package]]
-name = "output_vt100"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "plotters"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
-dependencies = [
- "num-traits",
- "plotters-backend",
- "plotters-svg",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "plotters-backend"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
-
-[[package]]
-name = "plotters-svg"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
-dependencies = [
- "plotters-backend",
-]
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "pretty_assertions"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
-dependencies = [
- "ansi_term",
- "ctor",
- "difference",
- "output_vt100",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.57"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "proptest"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70"
-dependencies = [
- "bit-set",
- "bitflags",
- "byteorder",
- "lazy_static",
- "num-traits",
- "quick-error 2.0.1",
- "rand",
- "rand_chacha",
- "rand_xorshift",
- "regex-syntax 0.6.29",
- "rusty-fork",
- "tempfile",
- "unarray",
-]
-
-[[package]]
-name = "quick-error"
-version = "1.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-
-[[package]]
-name = "quick-error"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
-
-[[package]]
-name = "quote"
-version = "1.0.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "radium"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rand_xorshift"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "rayon"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
-dependencies = [
- "either",
- "rayon-core",
-]
-
-[[package]]
-name = "rayon-core"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
-dependencies = [
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-utils",
- "num_cpus",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "regex"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
-dependencies = [
- "regex-syntax 0.7.1",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
-
-[[package]]
-name = "regex-syntax"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
-
-[[package]]
-name = "rustix"
-version = "0.37.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
-dependencies = [
- "bitflags",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rusty-fork"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
-dependencies = [
- "fnv",
- "quick-error 1.2.3",
- "tempfile",
- "wait-timeout",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
-
-[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "scopeguard"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-
-[[package]]
-name = "serde"
-version = "1.0.163"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_bytes"
-version = "0.11.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "serde_cbor"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
-dependencies = [
- "half",
- "serde",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.163"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.16",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.96"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
-dependencies = [
- "indexmap",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "serde_with"
-version = "1.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
-dependencies = [
- "serde",
- "serde_with_macros 1.5.2",
-]
-
-[[package]]
-name = "serde_with"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3"
-dependencies = [
- "base64 0.21.2",
- "chrono",
- "hex",
- "indexmap",
- "serde",
- "serde_json",
- "serde_with_macros 3.1.0",
- "time",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
-dependencies = [
- "darling 0.13.4",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65"
-dependencies = [
- "darling 0.20.3",
- "proc-macro2",
- "quote",
- "syn 2.0.16",
-]
-
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "tap"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
-
-[[package]]
-name = "tempfile"
-version = "3.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
-dependencies = [
- "cfg-if",
- "fastrand",
- "redox_syscall",
- "rustix",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
-[[package]]
-name = "time"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
-dependencies = [
- "itoa",
- "libc",
- "num_threads",
- "serde",
- "time-macros",
-]
-
-[[package]]
-name = "time-macros"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
-
-[[package]]
-name = "tinytemplate"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
-dependencies = [
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "unarray"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
-
-[[package]]
-name = "uuid"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
-dependencies = [
- "getrandom",
- "serde",
-]
-
-[[package]]
-name = "uuid"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
-dependencies = [
- "getrandom",
- "serde",
-]
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "wait-timeout"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "walkdir"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
-dependencies = [
- "same-file",
- "winapi-util",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
-dependencies = [
- "bumpalo",
- "log",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn 2.0.16",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.16",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
-
-[[package]]
-name = "web-sys"
-version = "0.3.62"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
-dependencies = [
- "windows-targets 0.48.0",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
-
-[[package]]
-name = "wyz"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
-dependencies = [
- "tap",
-]
-
-[[package]]
-name = "zerocopy"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a7af71d8643341260a65f89fa60c0eeaa907f34544d8f6d9b0df72f069b5e74"
-dependencies = [
- "zerocopy-derive",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9731702e2f0617ad526794ae28fbc6f6ca8849b5ba729666c2a5bc4b6ddee2cd"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.16",
-]
diff --git a/.evergreen/MSRV-Cargo.toml.diff b/.evergreen/MSRV-Cargo.toml.diff
new file mode 100644
index 00000000..437441ae
--- /dev/null
+++ b/.evergreen/MSRV-Cargo.toml.diff
@@ -0,0 +1,10 @@
+--- Cargo.toml	2024-12-12 10:00:04
++++ Cargo.toml.msrv	2024-12-12 10:20:57
+@@ -57,6 +57,7 @@
+ 
+ [dependencies]
+ ahash = "0.8.0"
++bumpalo = "=3.14.0"
+ chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
+ rand = "0.8"
+ serde = { version = "1.0", features = ["derive"] }
diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index 9dda7345..41a89ce7 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -10,9 +10,9 @@ if [ ! -z "$TARGET" ]; then
     TARGET="--target=$TARGET"
 fi
 
-# pin all dependencies when checking msrv compilation
+# pin necessary dependencies when checking msrv compilation
 if [ "$MSRV" = "true" ]; then
-    cp .evergreen/Cargo.lock.msrv Cargo.lock
+    patch Cargo.toml .evergreen/MSRV-Cargo.toml.diff
 fi
 
 rustup run $RUST_VERSION cargo build $TARGET
diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index d27fca57..956e50c0 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -195,9 +195,9 @@ axes:
   - id: "extra-rust-versions"
     values:
       - id: "min"
-        display_name: "1.64 (minimum supported version)"
+        display_name: "1.71.1 (minimum supported version)"
         variables:
-          RUST_VERSION: "1.64.0"
+          RUST_VERSION: "1.71.1"
           MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
@@ -229,7 +229,7 @@ buildvariants:
   matrix_spec:
     extra-rust-versions: "*"
     extra-targets: "*"
-  display_name: "Compile on Rust ${extra-rust-versions}"
+  display_name: "Compile on Rust ${extra-rust-versions} (${extra-targets})"
   run_on:
     - ubuntu1804-test
   tasks:
diff --git a/README.md b/README.md
index 875724a6..0f881635 100644
--- a/README.md
+++ b/README.md
@@ -269,7 +269,7 @@ This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `
 
 ## Minimum supported Rust version (MSRV)
 
-The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever is,
+The MSRV for this crate is currently 1.71.1. This will be rarely be increased, and if it ever is,
 it will only happen in a minor or major version release.
 
 ## Contributing
diff --git a/clippy.toml b/clippy.toml
index 3eb5fd06..49c31fa5 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1 +1 @@
-msrv = "1.64.0"
\ No newline at end of file
+msrv = "1.71.1"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index ab7c2c0f..7386720b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -277,7 +277,7 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever
+//! The MSRV for this crate is currently 1.71.1. This will be rarely be increased, and if it ever
 //! is, it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
@@ -327,7 +327,7 @@ pub use self::{
 };
 
 #[allow(deprecated)]
-pub use self::de::{from_reader_utf8_lossy, from_slice_utf8_lossy,};
+pub use self::de::{from_reader_utf8_lossy, from_slice_utf8_lossy};
 
 #[macro_use]
 mod macros;

From cea6aec610abcdc2c6ba480b5e7b8145fde200e3 Mon Sep 17 00:00:00 2001
From: Asger Hautop Drewsen <asger@tyilo.com>
Date: Thu, 12 Dec 2024 17:25:01 +0100
Subject: [PATCH 085/156] Add functions to DateTime to add milliseconds and
 Duration (#506)

---
 src/datetime.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/datetime.rs b/src/datetime.rs
index f52b16e9..f5c8e04e 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -363,6 +363,26 @@ impl crate::DateTime {
         self.0
     }
 
+    /// Adds `millis` milliseconds to the [`DateTime`] saturating at [`DateTime::MIN`] and
+    /// [`DateTime::MAX`].
+    pub const fn saturating_add_millis(self, millis: i64) -> Self {
+        Self::from_millis(self.0.saturating_add(millis))
+    }
+
+    /// Adds `duration` to the [`DateTime`] saturating at [`DateTime::MAX`].
+    ///
+    /// As [`DateTime`] only have millisecond-precision this will only use the whole milliseconds
+    /// of `duration`.
+    pub const fn saturating_add_duration(self, duration: Duration) -> Self {
+        // i64::try_from isn't const
+        let millis = duration.as_millis();
+        if millis > i64::MAX as u128 {
+            Self::from_millis(i64::MAX)
+        } else {
+            self.saturating_add_millis(millis as i64)
+        }
+    }
+
     #[deprecated(since = "2.3.0", note = "Use try_to_rfc3339_string instead.")]
     /// Convert this [`DateTime`] to an RFC 3339 formatted string.  Panics if it could not be
     /// represented in that format.

From e0aab6fedc8024612ae048ec599d1797ed23796f Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 12 Dec 2024 11:51:52 -0500
Subject: [PATCH 086/156] minor: bump clippy version to 1.83.0 (#509)

---
 .evergreen/check-clippy.sh         |  2 +-
 src/de/mod.rs                      |  2 +-
 src/de/raw.rs                      | 18 +++++++++---------
 src/document.rs                    |  4 ++--
 src/raw/array.rs                   |  4 ++--
 src/raw/array_buf.rs               |  2 +-
 src/raw/bson_ref.rs                | 30 +++++++++++++++---------------
 src/raw/document.rs                |  4 ++--
 src/raw/document_buf.rs            |  2 +-
 src/raw/iter.rs                    |  6 +++---
 src/raw/serde.rs                   | 10 +++++-----
 src/raw/serde/seeded_visitor.rs    |  6 +++---
 src/ser/raw/document_serializer.rs | 14 +++++++-------
 src/ser/raw/mod.rs                 |  6 +++---
 src/ser/raw/value_serializer.rs    |  6 +++---
 src/tests/serde_helpers.rs         |  2 +-
 src/tests/spec/corpus.rs           |  2 +-
 17 files changed, 60 insertions(+), 60 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index c41008d5..c2925c75 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.80.0
+CLIPPY_VERSION=1.83.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 73c108d4..1ee8e5a4 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -91,7 +91,7 @@ where
     let de = Deserializer::new(bson);
     #[cfg(feature = "serde_path_to_error")]
     {
-        return serde_path_to_error::deserialize(de).map_err(Error::with_path);
+        serde_path_to_error::deserialize(de).map_err(Error::with_path)
     }
     #[cfg(not(feature = "serde_path_to_error"))]
     {
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 58a2d2bc..e75b2b32 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -730,7 +730,7 @@ struct TimestampAccess<'d> {
     deserializer: &'d mut TimestampDeserializer,
 }
 
-impl<'de, 'd> serde::de::MapAccess<'de> for TimestampAccess<'d> {
+impl<'de> serde::de::MapAccess<'de> for TimestampAccess<'_> {
     type Error = Error;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
@@ -775,7 +775,7 @@ impl TimestampDeserializer {
     }
 }
 
-impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut TimestampDeserializer {
+impl<'de> serde::de::Deserializer<'de> for &mut TimestampDeserializer {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
@@ -823,7 +823,7 @@ struct DateTimeAccess<'d> {
     deserializer: &'d mut DateTimeDeserializer,
 }
 
-impl<'de, 'd> serde::de::MapAccess<'de> for DateTimeAccess<'d> {
+impl<'de> serde::de::MapAccess<'de> for DateTimeAccess<'_> {
     type Error = Error;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
@@ -875,7 +875,7 @@ impl DateTimeDeserializer {
     }
 }
 
-impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut DateTimeDeserializer {
+impl<'de> serde::de::Deserializer<'de> for &mut DateTimeDeserializer {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
@@ -932,7 +932,7 @@ struct BinaryAccess<'d, 'de> {
     deserializer: &'d mut BinaryDeserializer<'de>,
 }
 
-impl<'de, 'd> serde::de::MapAccess<'de> for BinaryAccess<'d, 'de> {
+impl<'de> serde::de::MapAccess<'de> for BinaryAccess<'_, 'de> {
     type Error = Error;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
@@ -976,7 +976,7 @@ impl<'a> BinaryDeserializer<'a> {
     }
 }
 
-impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut BinaryDeserializer<'de> {
+impl<'de> serde::de::Deserializer<'de> for &mut BinaryDeserializer<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
@@ -1084,7 +1084,7 @@ impl<'de> serde::de::MapAccess<'de> for CodeWithScopeAccess<'de> {
     }
 }
 
-impl<'a, 'de> serde::de::Deserializer<'de> for &'a CodeWithScopeAccess<'de> {
+impl<'de> serde::de::Deserializer<'de> for &CodeWithScopeAccess<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
@@ -1180,7 +1180,7 @@ impl<'de> serde::de::MapAccess<'de> for DbPointerAccess<'de> {
     }
 }
 
-impl<'a, 'de> serde::de::Deserializer<'de> for &'a mut DbPointerAccess<'de> {
+impl<'de> serde::de::Deserializer<'de> for &mut DbPointerAccess<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
@@ -1289,7 +1289,7 @@ impl<'de> serde::de::MapAccess<'de> for RegexAccess<'de> {
     }
 }
 
-impl<'a, 'de> serde::de::Deserializer<'de> for &'a mut RegexAccess<'de> {
+impl<'de> serde::de::Deserializer<'de> for &mut RegexAccess<'de> {
     type Error = Error;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
diff --git a/src/document.rs b/src/document.rs
index b3e24067..ed8e8101 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -696,7 +696,7 @@ pub struct VacantEntry<'a> {
     inner: indexmap::map::VacantEntry<'a, String, Bson>,
 }
 
-impl<'a> VacantEntry<'a> {
+impl VacantEntry<'_> {
     /// Gets a reference to the key that would be used when inserting a value through the
     /// [VacantEntry].
     fn key(&self) -> &str {
@@ -709,7 +709,7 @@ pub struct OccupiedEntry<'a> {
     inner: indexmap::map::OccupiedEntry<'a, String, Bson>,
 }
 
-impl<'a> OccupiedEntry<'a> {
+impl OccupiedEntry<'_> {
     /// Gets a reference to the key in the entry.
     pub fn key(&self) -> &str {
         self.inner.key()
diff --git a/src/raw/array.rs b/src/raw/array.rs
index dd13164c..f6ed11ea 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -304,14 +304,14 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray {
     }
 }
 
-impl<'a> Serialize for &'a RawArray {
+impl Serialize for &RawArray {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
         struct SeqSerializer<'a>(&'a RawArray);
 
-        impl<'a> Serialize for SeqSerializer<'a> {
+        impl Serialize for SeqSerializer<'_> {
             fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where
                 S: serde::Serializer,
diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index 96797996..57dc6a5e 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -136,7 +136,7 @@ impl<'a> IntoIterator for &'a RawArrayBuf {
     }
 }
 
-impl<'a> From<RawArrayBuf> for Cow<'a, RawArray> {
+impl From<RawArrayBuf> for Cow<'_, RawArray> {
     fn from(rd: RawArrayBuf) -> Self {
         Cow::Owned(rd)
     }
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index 8241d879..f1f0fde9 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -312,7 +312,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawBsonRef<'a> {
     }
 }
 
-impl<'a> Serialize for RawBsonRef<'a> {
+impl Serialize for RawBsonRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -371,13 +371,13 @@ impl<'a> TryFrom<RawBsonRef<'a>> for Bson {
     }
 }
 
-impl<'a> From<i32> for RawBsonRef<'a> {
+impl From<i32> for RawBsonRef<'_> {
     fn from(i: i32) -> Self {
         RawBsonRef::Int32(i)
     }
 }
 
-impl<'a> From<i64> for RawBsonRef<'a> {
+impl From<i64> for RawBsonRef<'_> {
     fn from(i: i64) -> Self {
         RawBsonRef::Int64(i)
     }
@@ -389,13 +389,13 @@ impl<'a> From<&'a str> for RawBsonRef<'a> {
     }
 }
 
-impl<'a> From<f64> for RawBsonRef<'a> {
+impl From<f64> for RawBsonRef<'_> {
     fn from(f: f64) -> Self {
         RawBsonRef::Double(f)
     }
 }
 
-impl<'a> From<bool> for RawBsonRef<'a> {
+impl From<bool> for RawBsonRef<'_> {
     fn from(b: bool) -> Self {
         RawBsonRef::Boolean(b)
     }
@@ -425,25 +425,25 @@ impl<'a> From<&'a RawArrayBuf> for RawBsonRef<'a> {
     }
 }
 
-impl<'a> From<crate::DateTime> for RawBsonRef<'a> {
+impl From<crate::DateTime> for RawBsonRef<'_> {
     fn from(dt: crate::DateTime) -> Self {
         RawBsonRef::DateTime(dt)
     }
 }
 
-impl<'a> From<Timestamp> for RawBsonRef<'a> {
+impl From<Timestamp> for RawBsonRef<'_> {
     fn from(ts: Timestamp) -> Self {
         RawBsonRef::Timestamp(ts)
     }
 }
 
-impl<'a> From<ObjectId> for RawBsonRef<'a> {
+impl From<ObjectId> for RawBsonRef<'_> {
     fn from(oid: ObjectId) -> Self {
         RawBsonRef::ObjectId(oid)
     }
 }
 
-impl<'a> From<Decimal128> for RawBsonRef<'a> {
+impl From<Decimal128> for RawBsonRef<'_> {
     fn from(d: Decimal128) -> Self {
         RawBsonRef::Decimal128(d)
     }
@@ -459,7 +459,7 @@ pub struct RawBinaryRef<'a> {
     pub bytes: &'a [u8],
 }
 
-impl<'a> RawBinaryRef<'a> {
+impl RawBinaryRef<'_> {
     /// Copy the contents into a [`Binary`].
     pub fn to_binary(&self) -> Binary {
         Binary {
@@ -491,7 +491,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawBinaryRef<'a> {
     }
 }
 
-impl<'a> Serialize for RawBinaryRef<'a> {
+impl Serialize for RawBinaryRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -569,7 +569,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawRegexRef<'a> {
     }
 }
 
-impl<'a> Serialize for RawRegexRef<'a> {
+impl Serialize for RawRegexRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -606,7 +606,7 @@ pub struct RawJavaScriptCodeWithScopeRef<'a> {
     pub scope: &'a RawDocument,
 }
 
-impl<'a> RawJavaScriptCodeWithScopeRef<'a> {
+impl RawJavaScriptCodeWithScopeRef<'_> {
     pub(crate) fn len(self) -> i32 {
         4 + 4 + self.code.len() as i32 + 1 + self.scope.as_bytes().len() as i32
     }
@@ -627,7 +627,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScopeRef<'a> {
     }
 }
 
-impl<'a> Serialize for RawJavaScriptCodeWithScopeRef<'a> {
+impl Serialize for RawJavaScriptCodeWithScopeRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -667,7 +667,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawDbPointerRef<'a> {
     }
 }
 
-impl<'a> Serialize for RawDbPointerRef<'a> {
+impl Serialize for RawDbPointerRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 710cf699..8f725a0a 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -548,14 +548,14 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
     }
 }
 
-impl<'a> Serialize for &'a RawDocument {
+impl Serialize for &RawDocument {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
         struct KvpSerializer<'a>(&'a RawDocument);
 
-        impl<'a> Serialize for KvpSerializer<'a> {
+        impl Serialize for KvpSerializer<'_> {
             fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where
                 S: serde::Serializer,
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 5a99fa72..6f7e73c3 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -268,7 +268,7 @@ impl std::fmt::Debug for RawDocumentBuf {
     }
 }
 
-impl<'a> From<RawDocumentBuf> for Cow<'a, RawDocument> {
+impl From<RawDocumentBuf> for Cow<'_, RawDocument> {
     fn from(rd: RawDocumentBuf) -> Self {
         Cow::Owned(rd)
     }
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index bff08502..9082dada 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -128,7 +128,7 @@ impl<'a> TryInto<RawBsonRef<'a>> for RawElement<'a> {
     }
 }
 
-impl<'a> TryInto<RawBson> for RawElement<'a> {
+impl TryInto<RawBson> for RawElement<'_> {
     type Error = Error;
 
     fn try_into(self) -> Result<RawBson> {
@@ -136,7 +136,7 @@ impl<'a> TryInto<RawBson> for RawElement<'a> {
     }
 }
 
-impl<'a> TryInto<Bson> for RawElement<'a> {
+impl TryInto<Bson> for RawElement<'_> {
     type Error = Error;
 
     fn try_into(self) -> Result<Bson> {
@@ -340,7 +340,7 @@ impl<'a> RawElement<'a> {
     }
 }
 
-impl<'a> RawIter<'a> {
+impl RawIter<'_> {
     fn get_next_length_at(&self, start_at: usize) -> Result<usize> {
         let len = i32_from_slice(&self.doc.as_bytes()[start_at..])?;
         if len < 0 {
diff --git a/src/raw/serde.rs b/src/raw/serde.rs
index 1f877c1d..40dc03fb 100644
--- a/src/raw/serde.rs
+++ b/src/raw/serde.rs
@@ -54,7 +54,7 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawBson<'a> {
     }
 }
 
-impl<'a> Debug for OwnedOrBorrowedRawBson<'a> {
+impl Debug for OwnedOrBorrowedRawBson<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             Self::Owned(o) => o.fmt(f),
@@ -69,7 +69,7 @@ impl<'a> From<RawBsonRef<'a>> for OwnedOrBorrowedRawBson<'a> {
     }
 }
 
-impl<'a> From<RawBson> for OwnedOrBorrowedRawBson<'a> {
+impl From<RawBson> for OwnedOrBorrowedRawBson<'_> {
     fn from(b: RawBson) -> Self {
         OwnedOrBorrowedRawBson::Owned(b)
     }
@@ -82,7 +82,7 @@ pub(crate) enum OwnedOrBorrowedRawDocument<'a> {
     Borrowed(&'a RawDocument),
 }
 
-impl<'a> OwnedOrBorrowedRawDocument<'a> {
+impl OwnedOrBorrowedRawDocument<'_> {
     pub(crate) fn into_owned(self) -> RawDocumentBuf {
         match self {
             Self::Owned(o) => o,
@@ -91,7 +91,7 @@ impl<'a> OwnedOrBorrowedRawDocument<'a> {
     }
 }
 
-impl<'a> From<RawDocumentBuf> for OwnedOrBorrowedRawDocument<'a> {
+impl From<RawDocumentBuf> for OwnedOrBorrowedRawDocument<'_> {
     fn from(doc: RawDocumentBuf) -> Self {
         Self::Owned(doc)
     }
@@ -160,7 +160,7 @@ pub(crate) enum OwnedOrBorrowedRawArray<'a> {
     Borrowed(&'a RawArray),
 }
 
-impl<'a> OwnedOrBorrowedRawArray<'a> {
+impl OwnedOrBorrowedRawArray<'_> {
     pub(crate) fn into_owned(self) -> RawArrayBuf {
         match self {
             Self::Owned(o) => o,
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
index 1d6f7ca9..16bbf466 100644
--- a/src/raw/serde/seeded_visitor.rs
+++ b/src/raw/serde/seeded_visitor.rs
@@ -82,7 +82,7 @@ pub(crate) struct SeededVisitor<'a, 'de> {
     buffer: &'a mut CowByteBuffer<'de>,
 }
 
-impl<'a, 'de> DeserializeSeed<'de> for SeededVisitor<'a, 'de> {
+impl<'de> DeserializeSeed<'de> for SeededVisitor<'_, 'de> {
     type Value = ElementType;
 
     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
@@ -93,7 +93,7 @@ impl<'a, 'de> DeserializeSeed<'de> for SeededVisitor<'a, 'de> {
     }
 }
 
-impl<'a, 'de> DeserializeSeed<'de> for &mut SeededVisitor<'a, 'de> {
+impl<'de> DeserializeSeed<'de> for &mut SeededVisitor<'_, 'de> {
     type Value = ElementType;
 
     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
@@ -233,7 +233,7 @@ impl<'a, 'de> SeededVisitor<'a, 'de> {
     }
 }
 
-impl<'a, 'de> Visitor<'de> for SeededVisitor<'a, 'de> {
+impl<'de> Visitor<'de> for SeededVisitor<'_, 'de> {
     type Value = ElementType;
 
     fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index 9b20f5b8..114a11e9 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -66,7 +66,7 @@ impl<'a> DocumentSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeSeq for DocumentSerializer<'a> {
+impl serde::ser::SerializeSeq for DocumentSerializer<'_> {
     type Ok = ();
     type Error = Error;
 
@@ -91,7 +91,7 @@ impl<'a> serde::ser::SerializeSeq for DocumentSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeMap for DocumentSerializer<'a> {
+impl serde::ser::SerializeMap for DocumentSerializer<'_> {
     type Ok = ();
 
     type Error = Error;
@@ -117,7 +117,7 @@ impl<'a> serde::ser::SerializeMap for DocumentSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeStruct for DocumentSerializer<'a> {
+impl serde::ser::SerializeStruct for DocumentSerializer<'_> {
     type Ok = ();
 
     type Error = Error;
@@ -137,7 +137,7 @@ impl<'a> serde::ser::SerializeStruct for DocumentSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeTuple for DocumentSerializer<'a> {
+impl serde::ser::SerializeTuple for DocumentSerializer<'_> {
     type Ok = ();
 
     type Error = Error;
@@ -157,7 +157,7 @@ impl<'a> serde::ser::SerializeTuple for DocumentSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeTupleStruct for DocumentSerializer<'a> {
+impl serde::ser::SerializeTupleStruct for DocumentSerializer<'_> {
     type Ok = ();
 
     type Error = Error;
@@ -183,13 +183,13 @@ struct KeySerializer<'a> {
     root_serializer: &'a mut Serializer,
 }
 
-impl<'a> KeySerializer<'a> {
+impl KeySerializer<'_> {
     fn invalid_key<T: Serialize>(v: T) -> Error {
         Error::InvalidDocumentKey(to_bson(&v).unwrap_or(Bson::Null))
     }
 }
 
-impl<'a> serde::Serializer for KeySerializer<'a> {
+impl serde::Serializer for KeySerializer<'_> {
     type Ok = ();
 
     type Error = Error;
diff --git a/src/ser/raw/mod.rs b/src/ser/raw/mod.rs
index 1fb904f5..69b7320e 100644
--- a/src/ser/raw/mod.rs
+++ b/src/ser/raw/mod.rs
@@ -391,7 +391,7 @@ pub(crate) enum StructSerializer<'a> {
     Document(DocumentSerializer<'a>),
 }
 
-impl<'a> SerializeStruct for StructSerializer<'a> {
+impl SerializeStruct for StructSerializer<'_> {
     type Ok = ();
     type Error = Error;
 
@@ -493,7 +493,7 @@ impl<'a> VariantSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeTupleVariant for VariantSerializer<'a> {
+impl serde::ser::SerializeTupleVariant for VariantSerializer<'_> {
     type Ok = ();
 
     type Error = Error;
@@ -512,7 +512,7 @@ impl<'a> serde::ser::SerializeTupleVariant for VariantSerializer<'a> {
     }
 }
 
-impl<'a> serde::ser::SerializeStructVariant for VariantSerializer<'a> {
+impl serde::ser::SerializeStructVariant for VariantSerializer<'_> {
     type Ok = ();
 
     type Error = Error;
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 46fb8623..8ed93eda 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -148,7 +148,7 @@ impl<'a> ValueSerializer<'a> {
     }
 }
 
-impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
+impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     type Ok = ();
     type Error = Error;
 
@@ -450,7 +450,7 @@ impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> {
     }
 }
 
-impl<'a, 'b> SerializeStruct for &'b mut ValueSerializer<'a> {
+impl SerializeStruct for &mut ValueSerializer<'_> {
     type Ok = ();
     type Error = Error;
 
@@ -597,7 +597,7 @@ impl<'a> CodeWithScopeSerializer<'a> {
     }
 }
 
-impl<'a> SerializeMap for CodeWithScopeSerializer<'a> {
+impl SerializeMap for CodeWithScopeSerializer<'_> {
     type Ok = ();
     type Error = Error;
 
diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs
index 805aa93b..54df88cf 100644
--- a/src/tests/serde_helpers.rs
+++ b/src/tests/serde_helpers.rs
@@ -41,7 +41,7 @@ fn human_readable_wrapper() {
             D: serde::Deserializer<'de>,
         {
             struct V;
-            impl<'de> Visitor<'de> for V {
+            impl Visitor<'_> for V {
                 type Value = bool;
 
                 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 6df2487e..796d1a70 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -71,7 +71,7 @@ struct ParseError {
 
 struct FieldVisitor<'a, T>(&'a str, PhantomData<T>);
 
-impl<'de, 'a, T> serde::de::Visitor<'de> for FieldVisitor<'a, T>
+impl<'de, T> serde::de::Visitor<'de> for FieldVisitor<'_, T>
 where
     T: Deserialize<'de>,
 {

From 896a5e18ffc31e74640b6b03262586c357aa38ac Mon Sep 17 00:00:00 2001
From: Patrick Meredith <pmeredit@protonmail.com>
Date: Tue, 17 Dec 2024 17:28:39 -0500
Subject: [PATCH 087/156] New PR with Devin's complete changes (#507)

Mostly generated by devin, serialization test updated personally, and removed redundant fuzz tests
---
 .evergreen/config.yml                |  31 +++++-
 .evergreen/run-fuzzer.sh             |  37 ++++++-
 fuzz/Cargo.toml                      |  30 +++++-
 fuzz/fuzz_targets/serialization.rs   |  55 +++++++++++
 fuzz/fuzz_targets/string_handling.rs |  23 +++++
 fuzz/fuzz_targets/type_markers.rs    |  14 +++
 fuzz/generate_corpus.rs              | 143 +++++++++++++++++++++++++++
 src/spec.rs                          |   9 +-
 8 files changed, 330 insertions(+), 12 deletions(-)
 create mode 100644 fuzz/fuzz_targets/serialization.rs
 create mode 100644 fuzz/fuzz_targets/string_handling.rs
 create mode 100644 fuzz/fuzz_targets/type_markers.rs
 create mode 100644 fuzz/generate_corpus.rs

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 956e50c0..673b5ffc 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -13,15 +13,18 @@ stepback: true
 command_type: system
 
 # Protect ourself against rogue test case, or curl gone wild, that runs forever
-# 12 minutes is the longest we'll ever run
-exec_timeout_secs: 3600 # 12 minutes is the longest we'll ever run
+# 60 minutes is the longest we'll ever run
+exec_timeout_secs: 3600 # 1 hour total for security-focused fuzzing
 
 # What to do when evergreen hits the timeout (`post:` tasks are run automatically)
 timeout:
   - command: shell.exec
     params:
       script: |
-        ls -la
+        echo "Fuzzing timed out. Collecting any available artifacts..."
+        if [ -d "src/fuzz/artifacts" ]; then
+          tar czf "${PROJECT_DIRECTORY}/crash-artifacts.tar.gz" src/fuzz/artifacts/
+        fi
 
 functions:
   "fetch source":
@@ -154,7 +157,25 @@ functions:
     - command: shell.exec
       params:
         script: |
-            # Nothing needs to be done here
+          # Archive crash artifacts if they exist and contain crashes
+          if [ -d "src/fuzz/artifacts" ] && [ "$(ls -A src/fuzz/artifacts)" ]; then
+            echo "Creating artifacts archive..."
+            tar czf "${PROJECT_DIRECTORY}/crash-artifacts.tar.gz" src/fuzz/artifacts/
+          else
+            echo "No crashes found in artifacts directory. Skipping archive creation."
+          fi
+    # Upload crash artifacts if they exist
+    - command: s3.put
+      params:
+        aws_key: ${aws_key}
+        aws_secret: ${aws_secret}
+        local_file: ${PROJECT_DIRECTORY}/crash-artifacts.tar.gz
+        remote_file: ${CURRENT_VERSION}/crash-artifacts.tar.gz
+        bucket: mciuploads
+        permissions: public-read
+        content_type: application/x-gzip
+        optional: true
+
 pre:
   - func: "fetch source"
   - func: "install dependencies"
@@ -259,4 +280,4 @@ buildvariants:
   run_on:
     - ubuntu1804-test
   tasks:
-    - name: "wasm-test"
\ No newline at end of file
+    - name: "wasm-test"
diff --git a/.evergreen/run-fuzzer.sh b/.evergreen/run-fuzzer.sh
index 511799cb..b66abf1b 100755
--- a/.evergreen/run-fuzzer.sh
+++ b/.evergreen/run-fuzzer.sh
@@ -6,7 +6,36 @@ set -o errexit
 
 cd fuzz
 
-# each runs for a minute
-cargo +nightly fuzz run deserialize -- -rss_limit_mb=4096 -max_total_time=60
-cargo +nightly fuzz run raw_deserialize -- -rss_limit_mb=4096 -max_total_time=60
-cargo +nightly fuzz run iterate -- -rss_limit_mb=4096 -max_total_time=60
+# Create directories for crashes and corpus
+mkdir -p artifacts
+mkdir -p corpus
+
+# Generate initial corpus if directory is empty
+if [ -z "$(ls -A corpus)" ]; then
+    echo "Generating initial corpus..."
+    cargo run --bin generate_corpus
+fi
+
+# Function to run fuzzer and collect crashes
+run_fuzzer() {
+    target=$1
+    echo "Running fuzzer for $target"
+    # Run fuzzer and redirect crashes to artifacts directory
+    RUST_BACKTRACE=1 cargo +nightly fuzz run $target -- \
+        -rss_limit_mb=4096 \
+        -max_total_time=60 \
+        -artifact_prefix=artifacts/ \
+        -print_final_stats=1 \
+        corpus/
+}
+
+# Run existing targets
+run_fuzzer "deserialize"
+run_fuzzer "raw_deserialize"
+run_fuzzer "iterate"
+
+# Run new security-focused targets
+run_fuzzer "malformed_length"
+run_fuzzer "type_markers"
+run_fuzzer "string_handling"
+run_fuzzer "serialization"
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 25c60712..abdcffb5 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -1,19 +1,25 @@
-
 [package]
 name = "bson-fuzz"
 version = "0.0.1"
 authors = ["Automatically generated"]
 publish = false
+edition = "2021"
 
 [package.metadata]
 cargo-fuzz = true
 
 [dependencies.bson]
 path = ".."
+
 [dependencies.libfuzzer-sys]
 version = "0.4.0"
 
-# Prevent this from interfering with workspaces
+[dependencies.serde]
+version = "1.0"
+
+[dependencies.serde_json]
+version = "1.0"
+
 [workspace]
 members = ["."]
 
@@ -32,3 +38,23 @@ path = "fuzz_targets/raw_deserialize.rs"
 [[bin]]
 name = "raw_deserialize_utf8_lossy"
 path = "fuzz_targets/raw_deserialize_utf8_lossy.rs"
+
+[[bin]]
+name = "malformed_length"
+path = "fuzz_targets/malformed_length.rs"
+
+[[bin]]
+name = "type_markers"
+path = "fuzz_targets/type_markers.rs"
+
+[[bin]]
+name = "string_handling"
+path = "fuzz_targets/string_handling.rs"
+
+[[bin]]
+name = "serialization"
+path = "fuzz_targets/serialization.rs"
+
+[[bin]]
+name = "generate_corpus"
+path = "generate_corpus.rs"
diff --git a/fuzz/fuzz_targets/serialization.rs b/fuzz/fuzz_targets/serialization.rs
new file mode 100644
index 00000000..e5ba621d
--- /dev/null
+++ b/fuzz/fuzz_targets/serialization.rs
@@ -0,0 +1,55 @@
+#![no_main]
+use bson::{
+    raw::{RawDocument, RawDocumentBuf},
+    Bson,
+    Document,
+};
+use libfuzzer_sys::fuzz_target;
+
+fn compare_docs(doc1: &Document, doc2: &Document) -> bool {
+    if doc1.len() != doc2.len() {
+        return false;
+    }
+    for (key, value) in doc1 {
+        if !doc2.contains_key(key) {
+            return false;
+        }
+        if let Some(val2) = doc2.get(key) {
+            match (value, val2) {
+                (Bson::Double(d1), Bson::Double(d2)) => {
+                    if (!d1.is_nan() || !d2.is_nan()) && d1 != d2 {
+                        return false;
+                    }
+                }
+                (v1, v2) => {
+                    if v1 != v2 {
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+    true
+}
+
+fuzz_target!(|input: &[u8]| {
+    if let Ok(rawdoc) = RawDocument::from_bytes(&input) {
+        if let Ok(doc) = Document::try_from(rawdoc) {
+            let out = RawDocumentBuf::try_from(&doc).unwrap();
+            let out_bytes = out.as_bytes();
+            if input != out_bytes {
+                let reserialized = RawDocument::from_bytes(&out_bytes).unwrap();
+                let reserialized_doc = Document::try_from(reserialized).unwrap();
+                // Ensure that the reserialized document is the same as the original document, the
+                // bytes can differ while still resulting in the same Document.
+                if !compare_docs(&doc, &reserialized_doc) {
+                    panic!(
+                        "Reserialized document is not the same as the original document: {:?} != \
+                         {:?}",
+                        doc, reserialized_doc
+                    );
+                }
+            }
+        }
+    }
+});
diff --git a/fuzz/fuzz_targets/string_handling.rs b/fuzz/fuzz_targets/string_handling.rs
new file mode 100644
index 00000000..090d132f
--- /dev/null
+++ b/fuzz/fuzz_targets/string_handling.rs
@@ -0,0 +1,23 @@
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+extern crate bson;
+use bson::{RawBsonRef, RawDocument};
+use std::convert::TryInto;
+
+fuzz_target!(|buf: &[u8]| {
+    if let Ok(doc) = RawDocument::from_bytes(buf) {
+        for elem in doc.iter_elements().flatten() {
+            // Convert to RawBsonRef and check string-related types
+            if let Ok(bson) = elem.try_into() {
+                match bson {
+                    RawBsonRef::String(s) => {
+                        let _ = s.len();
+                        let _ = s.chars().count();
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+});
diff --git a/fuzz/fuzz_targets/type_markers.rs b/fuzz/fuzz_targets/type_markers.rs
new file mode 100644
index 00000000..3506b96e
--- /dev/null
+++ b/fuzz/fuzz_targets/type_markers.rs
@@ -0,0 +1,14 @@
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+extern crate bson;
+use bson::{RawBsonRef, RawDocument};
+use std::convert::TryInto;
+
+fuzz_target!(|buf: &[u8]| {
+    if let Ok(doc) = RawDocument::from_bytes(buf) {
+        for elem in doc.iter_elements().flatten() {
+            let _: Result<RawBsonRef, _> = elem.try_into();
+        }
+    }
+});
diff --git a/fuzz/generate_corpus.rs b/fuzz/generate_corpus.rs
new file mode 100644
index 00000000..c67c4cfc
--- /dev/null
+++ b/fuzz/generate_corpus.rs
@@ -0,0 +1,143 @@
+use bson::{doc, Bson, Decimal128};
+use std::{
+    fs,
+    io::{Error, ErrorKind},
+    path::Path,
+    str::FromStr,
+};
+
+fn main() -> std::io::Result<()> {
+    let corpus_dir = Path::new("fuzz/corpus");
+    fs::create_dir_all(corpus_dir)?;
+
+    // Generate edge cases for each fuzz target
+    generate_length_edge_cases(corpus_dir)?;
+    generate_type_marker_cases(corpus_dir)?;
+    generate_string_edge_cases(corpus_dir)?;
+    generate_serialization_cases(corpus_dir)?;
+    Ok(())
+}
+
+fn generate_length_edge_cases(dir: &Path) -> std::io::Result<()> {
+    let target_dir = dir.join("malformed_length");
+    fs::create_dir_all(&target_dir)?;
+
+    // Invalid length
+    fs::write(target_dir.join("invalid_len"), vec![4, 5])?;
+
+    // Minimal valid document
+    let min_doc = doc! {};
+    fs::write(
+        target_dir.join("min_doc"),
+        bson::to_vec(&min_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+    )?;
+
+    // Document with length near i32::MAX
+    let large_doc = doc! { "a": "b".repeat(i32::MAX as usize / 2) };
+    fs::write(
+        target_dir.join("large_doc"),
+        bson::to_vec(&large_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+    )?;
+
+    Ok(())
+}
+
+fn generate_type_marker_cases(dir: &Path) -> std::io::Result<()> {
+    let target_dir = dir.join("type_markers");
+    fs::create_dir_all(&target_dir)?;
+
+    // Document with all BSON types
+    let all_types = doc! {
+        "double": 1.0f64,
+        "double_nan": f64::NAN,
+        "double_infinity": f64::INFINITY,
+        "double_neg_infinity": f64::NEG_INFINITY,
+        "string": "test",
+        "document": doc! {},
+        "array": vec![1, 2, 3],
+        "binary": Bson::Binary(bson::Binary { subtype: bson::spec::BinarySubtype::Generic, bytes: vec![1, 2, 3] }),
+        "object_id": bson::oid::ObjectId::new(),
+        "bool": true,
+        "date": bson::DateTime::now(),
+        "null": Bson::Null,
+        "regex": Bson::RegularExpression(bson::Regex { pattern: "pattern".into(), options: "i".into() }),
+        "int32": 123i32,
+        "timestamp": bson::Timestamp { time: 12345, increment: 1 },
+        "int64": 123i64,
+        "decimal128_nan": Decimal128::from_str("NaN").unwrap(),
+        "decimal128_infinity": Decimal128::from_str("Infinity").unwrap(),
+        "decimal128_neg_infinity": Decimal128::from_str("-Infinity").unwrap(),
+        "min_key": Bson::MinKey,
+        "max_key": Bson::MaxKey,
+        "undefined": Bson::Undefined
+    };
+    fs::write(
+        target_dir.join("all_types"),
+        bson::to_vec(&all_types).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+    )?;
+
+    Ok(())
+}
+
+fn generate_string_edge_cases(dir: &Path) -> std::io::Result<()> {
+    let target_dir = dir.join("string_handling");
+    fs::create_dir_all(&target_dir)?;
+
+    // UTF-8 edge cases
+    let utf8_cases = doc! {
+        "empty": "",
+        "null_bytes": "hello\0world",
+        "unicode": "🦀💻🔒",
+        "high_surrogate": "\u{10000}",
+        "invalid_continuation": Bson::Binary(bson::Binary {
+            subtype: bson::spec::BinarySubtype::Generic,
+            bytes: vec![0x80u8, 0x80u8, 0x80u8]
+        }),
+        "overlong": Bson::Binary(bson::Binary {
+            subtype: bson::spec::BinarySubtype::Generic,
+            bytes: vec![0xC0u8, 0x80u8]
+        })
+    };
+    fs::write(
+        target_dir.join("utf8_cases"),
+        bson::to_vec(&utf8_cases).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+    )?;
+
+    Ok(())
+}
+
+fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
+    let target_dir = dir.join("serialization");
+    fs::create_dir_all(&target_dir)?;
+
+    // Deeply nested document
+    let mut nested_doc = doc! {};
+    let mut current = &mut nested_doc;
+    for i in 0..100 {
+        let next_doc = doc! {};
+        current.insert(i.to_string(), next_doc);
+        current = current
+            .get_mut(&i.to_string())
+            .unwrap()
+            .as_document_mut()
+            .unwrap();
+    }
+    fs::write(
+        target_dir.join("nested_doc"),
+        bson::to_vec(&nested_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+    )?;
+
+    // Document with large binary data
+    let large_binary = doc! {
+        "binary": Bson::Binary(bson::Binary {
+            subtype: bson::spec::BinarySubtype::Generic,
+            bytes: vec![0xFF; 1024 * 1024] // 1MB of data
+        })
+    };
+    fs::write(
+        target_dir.join("large_binary"),
+        bson::to_vec(&large_binary).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+    )?;
+
+    Ok(())
+}
diff --git a/src/spec.rs b/src/spec.rs
index 04ec7708..e853c150 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -21,7 +21,14 @@
 
 //! Constants derived from the [BSON Specification Version 1.1](http://bsonspec.org/spec.html).
 
-use std::convert::From;
+use std::{convert::From, fmt};
+
+impl fmt::LowerHex for BinarySubtype {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let value: u8 = (*self).into();
+        fmt::LowerHex::fmt(&value, f)
+    }
+}
 
 const ELEMENT_TYPE_FLOATING_POINT: u8 = 0x01;
 const ELEMENT_TYPE_UTF8_STRING: u8 = 0x02;

From 16084d9d2cf1b50da9f2f456ccbec5bb6e2e1937 Mon Sep 17 00:00:00 2001
From: manunio <maxnair.dev@gmail.com>
Date: Thu, 9 Jan 2025 00:46:53 +0530
Subject: [PATCH 088/156] fuzz: remove malformed_length entry (#510)

---
 .evergreen/run-fuzzer.sh | 1 -
 fuzz/Cargo.toml          | 4 ----
 2 files changed, 5 deletions(-)

diff --git a/.evergreen/run-fuzzer.sh b/.evergreen/run-fuzzer.sh
index b66abf1b..559913d2 100755
--- a/.evergreen/run-fuzzer.sh
+++ b/.evergreen/run-fuzzer.sh
@@ -35,7 +35,6 @@ run_fuzzer "raw_deserialize"
 run_fuzzer "iterate"
 
 # Run new security-focused targets
-run_fuzzer "malformed_length"
 run_fuzzer "type_markers"
 run_fuzzer "string_handling"
 run_fuzzer "serialization"
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index abdcffb5..abd24a57 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -39,10 +39,6 @@ path = "fuzz_targets/raw_deserialize.rs"
 name = "raw_deserialize_utf8_lossy"
 path = "fuzz_targets/raw_deserialize_utf8_lossy.rs"
 
-[[bin]]
-name = "malformed_length"
-path = "fuzz_targets/malformed_length.rs"
-
 [[bin]]
 name = "type_markers"
 path = "fuzz_targets/type_markers.rs"

From 04d15495187c4c429ca523c08df353df357438b7 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 21 Jan 2025 16:40:08 -0500
Subject: [PATCH 089/156] RUST-2058 Fix BSON WASM tests (#512)

---
 .evergreen/compile-only.sh   | 4 ++++
 .evergreen/run-wasm-tests.sh | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index 41a89ce7..395267e7 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -6,6 +6,10 @@ set -o errexit
 rustup update $RUST_VERSION
 
 if [ ! -z "$TARGET" ]; then
+    if [[ "$TARGET" = "wasm32-wasi" && "$RUST_VERSION" = "nightly" ]]; then
+        # renamed in newer versions of rustc
+        TARGET="wasm32-wasip1"
+    fi
     rustup target add $TARGET --toolchain $RUST_VERSION
     TARGET="--target=$TARGET"
 fi
diff --git a/.evergreen/run-wasm-tests.sh b/.evergreen/run-wasm-tests.sh
index 806c675e..18c835ca 100755
--- a/.evergreen/run-wasm-tests.sh
+++ b/.evergreen/run-wasm-tests.sh
@@ -4,6 +4,9 @@ set -o errexit
 
 . ~/.cargo/env
 
+rustup update 1.81
+rustup default 1.81
+
 curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
 
 cd $(dirname $0)/../wasm-test

From 098e1a17e34cbe7f28aac87609eeea2a191b93a3 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Fri, 24 Jan 2025 11:11:58 -0500
Subject: [PATCH 090/156] RUST-2003 Binary vector subtype support (#513)

---
 Cargo.toml                                    |   1 +
 src/binary.rs                                 |  12 +-
 src/binary/vector.rs                          | 288 ++++++++++++++++++
 src/spec.rs                                   |   4 +
 .../spec/json/bson-binary-vector/README.md    |  58 ++++
 .../spec/json/bson-binary-vector/float32.json |  51 ++++
 .../spec/json/bson-binary-vector/int8.json    |  57 ++++
 .../json/bson-binary-vector/packed_bit.json   |  98 ++++++
 src/tests/spec/mod.rs                         |  20 +-
 src/tests/spec/vector.rs                      | 219 +++++++++++++
 10 files changed, 799 insertions(+), 9 deletions(-)
 create mode 100644 src/binary/vector.rs
 create mode 100644 src/tests/spec/json/bson-binary-vector/README.md
 create mode 100644 src/tests/spec/json/bson-binary-vector/float32.json
 create mode 100644 src/tests/spec/json/bson-binary-vector/int8.json
 create mode 100644 src/tests/spec/json/bson-binary-vector/packed_bit.json
 create mode 100644 src/tests/spec/vector.rs

diff --git a/Cargo.toml b/Cargo.toml
index 1fb1626b..5fd8df36 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -82,6 +82,7 @@ criterion = "0.3.0"
 pretty_assertions = "0.6.1"
 proptest = "1.0.0"
 serde_bytes = "0.11"
+serde_path_to_error = "0.1.16"
 chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false }
 [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
 getrandom = { version = "0.2", features = ["js"] }
diff --git a/src/binary.rs b/src/binary.rs
index 18cf8a3d..ae5240b9 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -1,3 +1,7 @@
+#! Module containing functionality related to BSON binary values.
+
+mod vector;
+
 use crate::{spec::BinarySubtype, Document, RawBinaryRef};
 use std::{
     convert::TryFrom,
@@ -5,6 +9,8 @@ use std::{
     fmt::{self, Display},
 };
 
+pub use vector::{PackedBitVector, Vector};
+
 /// Represents a BSON binary value.
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct Binary {
@@ -98,6 +104,9 @@ impl Binary {
 pub enum Error {
     /// While trying to decode from base64, an error was returned.
     DecodingError { message: String },
+
+    /// A [`Vector`]-related error occurred.
+    Vector { message: String },
 }
 
 impl error::Error for Error {}
@@ -105,7 +114,8 @@ impl error::Error for Error {}
 impl std::fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            Error::DecodingError { message: m } => fmt.write_str(m),
+            Error::DecodingError { message } => fmt.write_str(message),
+            Error::Vector { message } => fmt.write_str(message),
         }
     }
 }
diff --git a/src/binary/vector.rs b/src/binary/vector.rs
new file mode 100644
index 00000000..4f74e8f8
--- /dev/null
+++ b/src/binary/vector.rs
@@ -0,0 +1,288 @@
+use std::{
+    convert::{TryFrom, TryInto},
+    mem::size_of,
+};
+
+use serde::{Deserialize, Serialize};
+
+use super::{Binary, Error, Result};
+use crate::{spec::BinarySubtype, Bson, RawBson};
+
+const INT8: u8 = 0x03;
+const FLOAT32: u8 = 0x27;
+const PACKED_BIT: u8 = 0x10;
+
+/// A vector of numeric values. This type can be converted into a [`Binary`] of subtype
+/// [`BinarySubtype::Vector`].
+///
+/// ```rust
+/// # use bson::binary::{Binary, Vector};
+/// let vector = Vector::Int8(vec![0, 1, 2]);
+/// let binary = Binary::from(vector);
+/// ```
+///
+/// `Vector` serializes to and deserializes from a `Binary`.
+///
+/// ```rust
+/// # use serde::{Serialize, Deserialize};
+/// # use bson::{binary::{Result, Vector}, spec::ElementType};
+/// #[derive(Serialize, Deserialize)]
+/// struct Data {
+///     vector: Vector,
+/// }
+///
+/// let data = Data { vector: Vector::Int8(vec![0, 1, 2]) };
+/// let document = bson::to_document(&data).unwrap();
+/// assert_eq!(document.get("vector").unwrap().element_type(), ElementType::Binary);
+///
+/// let data: Data = bson::from_document(document).unwrap();
+/// assert_eq!(data.vector, Vector::Int8(vec![0, 1, 2]));
+/// ```
+///
+/// See the
+/// [specification](https://github.com/mongodb/specifications/blob/master/source/bson-binary-vector/bson-binary-vector.md)
+/// for more details.
+#[derive(Clone, Debug, PartialEq)]
+pub enum Vector {
+    /// A vector of `i8` values.
+    Int8(Vec<i8>),
+
+    /// A vector of `f32` values.
+    Float32(Vec<f32>),
+
+    /// A vector of packed bits. See [`PackedBitVector::new`] for more details.
+    PackedBit(PackedBitVector),
+}
+
+/// A vector of packed bits. This type can be constructed by calling [`PackedBitVector::new`].
+#[derive(Clone, Debug, PartialEq)]
+pub struct PackedBitVector {
+    vector: Vec<u8>,
+    padding: u8,
+}
+
+impl PackedBitVector {
+    /// Construct a new `PackedBitVector`. Each `u8` value in the provided `vector` represents 8
+    /// single-bit elements in little-endian format. For example, the following vector:
+    ///
+    /// ```rust
+    /// # use bson::binary::{Result, PackedBitVector};
+    /// # fn main() -> Result<()> {
+    /// let packed_bits = vec![238, 224];
+    /// let vector = PackedBitVector::new(packed_bits, 0)?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// represents a 16-bit vector containing the following values:
+    ///
+    /// ```text
+    /// [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0]
+    /// ```
+    ///
+    /// Padding can optionally be specified to ignore a number of least-significant bits in the
+    /// final byte. For example, the vector in the previous example with a padding of 4 would
+    /// represent a 12-bit vector containing the following values:
+    ///
+    /// ```text
+    /// [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0]
+    /// ```
+    ///
+    /// Padding must be within 0-7 inclusive. Padding must be 0 or unspecified if the provided
+    /// vector is empty.
+    pub fn new(vector: Vec<u8>, padding: impl Into<Option<u8>>) -> Result<Self> {
+        let padding = padding.into().unwrap_or(0);
+        if !(0..8).contains(&padding) {
+            return Err(Error::Vector {
+                message: format!("padding must be within 0-7 inclusive, got {}", padding),
+            });
+        }
+        if padding != 0 && vector.is_empty() {
+            return Err(Error::Vector {
+                message: format!(
+                    "cannot specify non-zero padding if the provided vector is empty, got {}",
+                    padding
+                ),
+            });
+        }
+        Ok(Self { vector, padding })
+    }
+}
+
+impl Vector {
+    /// Construct a [`Vector`] from the given bytes. See the
+    /// [specification](https://github.com/mongodb/specifications/blob/master/source/bson-binary-vector/bson-binary-vector.md#specification)
+    /// for details on the expected byte format.
+    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self> {
+        let bytes = bytes.as_ref();
+
+        if bytes.len() < 2 {
+            return Err(Error::Vector {
+                message: format!(
+                    "the provided bytes must have a length of at least 2, got {}",
+                    bytes.len()
+                ),
+            });
+        }
+
+        let d_type = bytes[0];
+        let padding = bytes[1];
+        if d_type != PACKED_BIT && padding != 0 {
+            return Err(Error::Vector {
+                message: format!(
+                    "padding can only be specified for a packed bit vector (data type {}), got \
+                     type {}",
+                    PACKED_BIT, d_type
+                ),
+            });
+        }
+        let number_bytes = &bytes[2..];
+
+        match d_type {
+            INT8 => {
+                let vector = number_bytes
+                    .iter()
+                    .map(|n| i8::from_le_bytes([*n]))
+                    .collect();
+                Ok(Self::Int8(vector))
+            }
+            FLOAT32 => {
+                const F32_BYTES: usize = size_of::<f32>();
+
+                let mut vector = Vec::new();
+                for chunk in number_bytes.chunks(F32_BYTES) {
+                    let bytes: [u8; F32_BYTES] = chunk.try_into().map_err(|_| Error::Vector {
+                        message: format!(
+                            "f32 vector values must be {} bytes, got {:?}",
+                            F32_BYTES, chunk,
+                        ),
+                    })?;
+                    vector.push(f32::from_le_bytes(bytes));
+                }
+                Ok(Self::Float32(vector))
+            }
+            PACKED_BIT => {
+                let packed_bit_vector = PackedBitVector::new(number_bytes.to_vec(), padding)?;
+                Ok(Self::PackedBit(packed_bit_vector))
+            }
+            other => Err(Error::Vector {
+                message: format!("unsupported vector data type: {}", other),
+            }),
+        }
+    }
+
+    fn d_type(&self) -> u8 {
+        match self {
+            Self::Int8(_) => INT8,
+            Self::Float32(_) => FLOAT32,
+            Self::PackedBit(_) => PACKED_BIT,
+        }
+    }
+
+    fn padding(&self) -> u8 {
+        match self {
+            Self::Int8(_) => 0,
+            Self::Float32(_) => 0,
+            Self::PackedBit(PackedBitVector { padding, .. }) => *padding,
+        }
+    }
+}
+
+impl From<&Vector> for Binary {
+    fn from(vector: &Vector) -> Self {
+        let d_type = vector.d_type();
+        let padding = vector.padding();
+        let mut bytes = vec![d_type, padding];
+
+        match vector {
+            Vector::Int8(vector) => {
+                for n in vector {
+                    bytes.extend_from_slice(&n.to_le_bytes());
+                }
+            }
+            Vector::Float32(vector) => {
+                for n in vector {
+                    bytes.extend_from_slice(&n.to_le_bytes());
+                }
+            }
+            Vector::PackedBit(PackedBitVector { vector, .. }) => {
+                for n in vector {
+                    bytes.extend_from_slice(&n.to_le_bytes());
+                }
+            }
+        }
+
+        Self {
+            subtype: BinarySubtype::Vector,
+            bytes,
+        }
+    }
+}
+
+impl From<Vector> for Binary {
+    fn from(vector: Vector) -> Binary {
+        Self::from(&vector)
+    }
+}
+
+impl TryFrom<&Binary> for Vector {
+    type Error = Error;
+
+    fn try_from(binary: &Binary) -> Result<Self> {
+        if binary.subtype != BinarySubtype::Vector {
+            return Err(Error::Vector {
+                message: format!("expected vector binary subtype, got {:?}", binary.subtype),
+            });
+        }
+        Self::from_bytes(&binary.bytes)
+    }
+}
+
+impl TryFrom<Binary> for Vector {
+    type Error = Error;
+
+    fn try_from(binary: Binary) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(&binary)
+    }
+}
+
+// Convenience impl to allow passing a Vector directly into the doc! macro. From<Vector> is already
+// implemented by a blanket impl in src/bson.rs.
+impl From<&Vector> for Bson {
+    fn from(vector: &Vector) -> Self {
+        Self::Binary(Binary::from(vector))
+    }
+}
+
+// Convenience impls to allow passing a Vector directly into the rawdoc! macro
+impl From<&Vector> for RawBson {
+    fn from(vector: &Vector) -> Self {
+        Self::Binary(Binary::from(vector))
+    }
+}
+
+impl From<Vector> for RawBson {
+    fn from(vector: Vector) -> Self {
+        Self::from(&vector)
+    }
+}
+
+impl Serialize for Vector {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        let binary = Binary::from(self);
+        binary.serialize(serializer)
+    }
+}
+
+impl<'de> Deserialize<'de> for Vector {
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        let binary = Binary::deserialize(deserializer)?;
+        Self::try_from(binary).map_err(serde::de::Error::custom)
+    }
+}
diff --git a/src/spec.rs b/src/spec.rs
index e853c150..dc082ff7 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -62,6 +62,7 @@ const BINARY_SUBTYPE_MD5: u8 = 0x05;
 const BINARY_SUBTYPE_ENCRYPTED: u8 = 0x06;
 const BINARY_SUBTYPE_COLUMN: u8 = 0x07;
 const BINARY_SUBTYPE_SENSITIVE: u8 = 0x08;
+const BINARY_SUBTYPE_VECTOR: u8 = 0x09;
 const BINARY_SUBTYPE_USER_DEFINED: u8 = 0x80;
 
 /// All available BSON element types.
@@ -162,6 +163,7 @@ pub enum BinarySubtype {
     Encrypted,
     Column,
     Sensitive,
+    Vector,
     UserDefined(u8),
     Reserved(u8),
 }
@@ -179,6 +181,7 @@ impl From<BinarySubtype> for u8 {
             BinarySubtype::Encrypted => BINARY_SUBTYPE_ENCRYPTED,
             BinarySubtype::Column => BINARY_SUBTYPE_COLUMN,
             BinarySubtype::Sensitive => BINARY_SUBTYPE_SENSITIVE,
+            BinarySubtype::Vector => BINARY_SUBTYPE_VECTOR,
             BinarySubtype::UserDefined(x) => x,
             BinarySubtype::Reserved(x) => x,
         }
@@ -198,6 +201,7 @@ impl From<u8> for BinarySubtype {
             BINARY_SUBTYPE_ENCRYPTED => BinarySubtype::Encrypted,
             BINARY_SUBTYPE_COLUMN => BinarySubtype::Column,
             BINARY_SUBTYPE_SENSITIVE => BinarySubtype::Sensitive,
+            BINARY_SUBTYPE_VECTOR => BinarySubtype::Vector,
             _ if t < BINARY_SUBTYPE_USER_DEFINED => BinarySubtype::Reserved(t),
             _ => BinarySubtype::UserDefined(t),
         }
diff --git a/src/tests/spec/json/bson-binary-vector/README.md b/src/tests/spec/json/bson-binary-vector/README.md
new file mode 100644
index 00000000..3357ebb2
--- /dev/null
+++ b/src/tests/spec/json/bson-binary-vector/README.md
@@ -0,0 +1,58 @@
+# Testing Binary subtype 9: Vector
+
+The JSON files in this directory tree are platform-independent tests that drivers can use to prove their conformance to
+the specification.
+
+These tests focus on the roundtrip of the list of numbers as input/output, along with their data type and byte padding.
+
+Additional tests exist in `bson_corpus/tests/binary.json` but do not sufficiently test the end-to-end process of Vector
+to BSON. For this reason, drivers must create a bespoke test runner for the vector subtype.
+
+## Format
+
+The test data corpus consists of a JSON file for each data type (dtype). Each file contains a number of test cases,
+under the top-level key "tests". Each test case pertains to a single vector. The keys provide the specification of the
+vector. Valid cases also include the Canonical BSON format of a document {test_key: binary}. The "test_key" is common,
+and specified at the top level.
+
+#### Top level keys
+
+Each JSON file contains three top-level keys.
+
+- `description`: human-readable description of what is in the file
+- `test_key`: name used for key when encoding/decoding a BSON document containing the single BSON Binary for the test
+    case. Applies to *every* case.
+- `tests`: array of test case objects, each of which have the following keys. Valid cases will also contain additional
+    binary and json encoding values.
+
+#### Keys of individual tests cases
+
+- `description`: string describing the test.
+- `valid`: boolean indicating if the vector, dtype, and padding should be considered a valid input.
+- `vector`: list of numbers
+- `dtype_hex`: string defining the data type in hex (e.g. "0x10", "0x27")
+- `dtype_alias`: (optional) string defining the data dtype, perhaps as Enum.
+- `padding`: (optional) integer for byte padding. Defaults to 0.
+- `canonical_bson`: (required if valid is true) an (uppercase) big-endian hex representation of a BSON byte string.
+
+## Required tests
+
+#### To prove correct in a valid case (`valid: true`), one MUST
+
+- encode a document from the numeric values, dtype, and padding, along with the "test_key", and assert this matches the
+    canonical_bson string.
+- decode the canonical_bson into its binary form, and then assert that the numeric values, dtype, and padding all match
+    those provided in the JSON.
+
+Note: For floating point number types, exact numerical matches may not be possible. Drivers that natively support the
+floating-point type being tested (e.g., when testing float32 vector values in a driver that natively supports float32),
+MUST assert that the input float array is the same after encoding and decoding.
+
+#### To prove correct in an invalid case (`valid:false`), one MUST
+
+- raise an exception when attempting to encode a document from the numeric values, dtype, and padding.
+
+## FAQ
+
+- What MongoDB Server version does this apply to?
+    - Files in the "specifications" repository have no version scheme. They are not tied to a MongoDB server version.
diff --git a/src/tests/spec/json/bson-binary-vector/float32.json b/src/tests/spec/json/bson-binary-vector/float32.json
new file mode 100644
index 00000000..872c4353
--- /dev/null
+++ b/src/tests/spec/json/bson-binary-vector/float32.json
@@ -0,0 +1,51 @@
+{
+  "description": "Tests of Binary subtype 9, Vectors, with dtype FLOAT32",
+  "test_key": "vector",
+  "tests": [
+    {
+      "description": "Simple Vector FLOAT32",
+      "valid": true,
+      "vector": [127.0, 7.0],
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "padding": 0,
+      "canonical_bson": "1C00000005766563746F72000A0000000927000000FE420000E04000"
+    },
+    {
+      "description": "Vector with decimals and negative value FLOAT32",
+      "valid": true,
+      "vector": [127.7, -7.7],
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "padding": 0,
+      "canonical_bson": "1C00000005766563746F72000A0000000927006666FF426666F6C000"
+    },
+    {
+      "description": "Empty Vector FLOAT32",
+      "valid": true,
+      "vector": [],
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "padding": 0,
+      "canonical_bson": "1400000005766563746F72000200000009270000"
+    },
+    {
+      "description": "Infinity Vector FLOAT32",
+      "valid": true,
+      "vector": ["-inf", 0.0, "inf"],
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "padding": 0,
+      "canonical_bson": "2000000005766563746F72000E000000092700000080FF000000000000807F00"
+    },
+    {
+      "description": "FLOAT32 with padding",
+      "valid": false,
+      "vector": [127.0, 7.0],
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "padding": 3
+    }
+  ]
+}
+
diff --git a/src/tests/spec/json/bson-binary-vector/int8.json b/src/tests/spec/json/bson-binary-vector/int8.json
new file mode 100644
index 00000000..7529721e
--- /dev/null
+++ b/src/tests/spec/json/bson-binary-vector/int8.json
@@ -0,0 +1,57 @@
+{
+  "description": "Tests of Binary subtype 9, Vectors, with dtype INT8",
+  "test_key": "vector",
+  "tests": [
+    {
+      "description": "Simple Vector INT8",
+      "valid": true,
+      "vector": [127, 7],
+      "dtype_hex": "0x03",
+      "dtype_alias": "INT8",
+      "padding": 0,
+      "canonical_bson": "1600000005766563746F7200040000000903007F0700"
+    },
+    {
+      "description": "Empty Vector INT8",
+      "valid": true,
+      "vector": [],
+      "dtype_hex": "0x03",
+      "dtype_alias": "INT8",
+      "padding": 0,
+      "canonical_bson": "1400000005766563746F72000200000009030000"
+    },
+    {
+      "description": "Overflow Vector INT8",
+      "valid": false,
+      "vector": [128],
+      "dtype_hex": "0x03",
+      "dtype_alias": "INT8",
+      "padding": 0
+    },
+    {
+      "description": "Underflow Vector INT8",
+      "valid": false,
+      "vector": [-129],
+      "dtype_hex": "0x03",
+      "dtype_alias": "INT8",
+      "padding": 0
+    },
+    {
+      "description": "INT8 with padding",
+      "valid": false,
+      "vector": [127, 7],
+      "dtype_hex": "0x03",
+      "dtype_alias": "INT8",
+      "padding": 3
+    },
+    {
+      "description": "INT8 with float inputs",
+      "valid": false,
+      "vector": [127.77, 7.77],
+      "dtype_hex": "0x03",
+      "dtype_alias": "INT8",
+      "padding": 0
+    }
+  ]
+}
+
diff --git a/src/tests/spec/json/bson-binary-vector/packed_bit.json b/src/tests/spec/json/bson-binary-vector/packed_bit.json
new file mode 100644
index 00000000..035776e8
--- /dev/null
+++ b/src/tests/spec/json/bson-binary-vector/packed_bit.json
@@ -0,0 +1,98 @@
+{
+  "description": "Tests of Binary subtype 9, Vectors, with dtype PACKED_BIT",
+  "test_key": "vector",
+  "tests": [
+    {
+      "description": "Padding specified with no vector data PACKED_BIT",
+      "valid": false,
+      "vector": [],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 1
+    },
+    {
+      "description": "Simple Vector PACKED_BIT",
+      "valid": true,
+      "vector": [127, 7],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 0,
+      "canonical_bson": "1600000005766563746F7200040000000910007F0700"
+    },
+    {
+      "description": "Empty Vector PACKED_BIT",
+      "valid": true,
+      "vector": [],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 0,
+      "canonical_bson": "1400000005766563746F72000200000009100000"
+    },
+    {
+      "description": "PACKED_BIT with padding",
+      "valid": true,
+      "vector": [127, 7],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 3,
+      "canonical_bson": "1600000005766563746F7200040000000910037F0700"
+    },
+    {
+      "description": "Overflow Vector PACKED_BIT",
+      "valid": false,
+      "vector": [256],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 0
+    },
+    {
+      "description": "Underflow Vector PACKED_BIT",
+      "valid": false,
+      "vector": [-1],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 0
+    },
+    {
+      "description": "Vector with float values PACKED_BIT",
+      "valid": false,
+      "vector": [127.5],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 0
+    },
+    {
+      "description": "Padding specified with no vector data PACKED_BIT",
+      "valid": false,
+      "vector": [],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 1
+    },
+    {
+      "description": "Exceeding maximum padding PACKED_BIT",
+      "valid": false,
+      "vector": [1],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 8
+    },
+    {
+      "description": "Negative padding PACKED_BIT",
+      "valid": false,
+      "vector": [1],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": -1
+    },
+    {
+      "description": "Vector with float values PACKED_BIT",
+      "valid": false,
+      "vector": [127.5],
+      "dtype_hex": "0x10",
+      "dtype_alias": "PACKED_BIT",
+      "padding": 0
+    }
+  ]
+}
+
diff --git a/src/tests/spec/mod.rs b/src/tests/spec/mod.rs
index 36ff825e..6174aea0 100644
--- a/src/tests/spec/mod.rs
+++ b/src/tests/spec/mod.rs
@@ -1,4 +1,5 @@
 mod corpus;
+mod vector;
 
 use std::{
     any::type_name,
@@ -7,7 +8,7 @@ use std::{
     path::PathBuf,
 };
 
-use crate::RawDocumentBuf;
+use crate::Bson;
 use serde::de::DeserializeOwned;
 
 pub(crate) fn run_spec_test<T, F>(spec: &[&str], run_test_file: F)
@@ -31,13 +32,16 @@ where
         let file = File::open(&path)
             .unwrap_or_else(|e| panic!("Failed to open file at {:?}: {}", path, e));
 
-        let test_bson: RawDocumentBuf = serde_json::from_reader(file).unwrap_or_else(|e| {
-            panic!(
-                "Failed to deserialize test JSON to BSON in {:?}: {}",
-                path, e
-            )
-        });
-        let test: T = crate::from_slice(test_bson.as_bytes()).unwrap_or_else(|e| {
+        let mut json_deserializer = serde_json::Deserializer::from_reader(file);
+        let test_bson: Bson = serde_path_to_error::deserialize(&mut json_deserializer)
+            .unwrap_or_else(|e| {
+                panic!(
+                    "Failed to deserialize test JSON to BSON in {:?}: {}",
+                    path, e
+                )
+            });
+        let bson_deserializer = crate::Deserializer::new(test_bson);
+        let test: T = serde_path_to_error::deserialize(bson_deserializer).unwrap_or_else(|e| {
             panic!(
                 "Failed to deserialize test BSON to {} in {:?}: {}",
                 type_name::<T>(),
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
new file mode 100644
index 00000000..c297e285
--- /dev/null
+++ b/src/tests/spec/vector.rs
@@ -0,0 +1,219 @@
+use std::convert::TryFrom;
+
+use serde::{Deserialize, Deserializer, Serialize};
+
+use crate::{
+    binary::{Binary, PackedBitVector, Vector},
+    from_document,
+    from_slice,
+    spec::BinarySubtype,
+    to_document,
+    to_raw_document_buf,
+    Bson,
+    Document,
+    RawDocumentBuf,
+};
+
+use super::run_spec_test;
+
+const INT8: u8 = 0x03;
+const FLOAT32: u8 = 0x27;
+const PACKED_BIT: u8 = 0x10;
+
+#[derive(Deserialize)]
+struct TestFile {
+    description: String,
+    test_key: String,
+    tests: Vec<Test>,
+}
+
+#[derive(Deserialize)]
+struct Test {
+    description: String,
+    valid: bool,
+    vector: Vec<Number>,
+    #[serde(
+        rename = "dtype_hex",
+        deserialize_with = "deserialize_u8_from_hex_string"
+    )]
+    d_type: u8,
+    padding: Option<i16>,
+    canonical_bson: Option<String>,
+}
+
+fn deserialize_u8_from_hex_string<'de, D>(deserializer: D) -> Result<u8, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    let s = String::deserialize(deserializer)?;
+    u8::from_str_radix(s.trim_start_matches("0x"), 16).map_err(serde::de::Error::custom)
+}
+
+enum Number {
+    Int(i16),
+    Float(f32),
+}
+
+impl<'de> Deserialize<'de> for Number {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        #[serde(untagged)]
+        enum NumberHelper {
+            Int(i16),
+            Float(f32),
+            String(String),
+        }
+
+        let helper = NumberHelper::deserialize(deserializer)?;
+        match helper {
+            NumberHelper::Int(n) => Ok(Self::Int(n)),
+            NumberHelper::Float(n) => Ok(Self::Float(n)),
+            NumberHelper::String(s) => match s.as_str() {
+                "inf" => Ok(Self::Float(f32::INFINITY)),
+                "-inf" => Ok(Self::Float(f32::NEG_INFINITY)),
+                other => Err(serde::de::Error::custom(format!(
+                    "unsupported number value {}",
+                    other
+                ))),
+            },
+        }
+    }
+}
+
+// Some of the invalid cases (e.g. mixed number types, padding for non-packed-bit vectors) are
+// impossible to construct, so we return an error from this method.
+fn vector_from_numbers(
+    numbers: Vec<Number>,
+    d_type: u8,
+    padding: Option<i16>,
+) -> Result<Vector, String> {
+    let padding = u8::try_from(padding.unwrap_or(0)).map_err(|e| e.to_string())?;
+    if padding != 0 && d_type != PACKED_BIT {
+        return Err(format!("got nonzero padding for data type {}", d_type));
+    }
+    match d_type {
+        INT8 => {
+            let vector = numbers
+                .into_iter()
+                .map(|n| match n {
+                    Number::Int(n) => i8::try_from(n).map_err(|e| e.to_string()),
+                    Number::Float(n) => Err(format!("expected i8, got float {}", n)),
+                })
+                .collect::<Result<Vec<i8>, String>>()?;
+            Ok(Vector::Int8(vector))
+        }
+        FLOAT32 => {
+            let vector = numbers
+                .into_iter()
+                .map(|n| match n {
+                    Number::Int(n) => Err(format!("expected f32, got int {}", n)),
+                    Number::Float(n) => Ok(n),
+                })
+                .collect::<Result<Vec<f32>, String>>()?;
+            Ok(Vector::Float32(vector))
+        }
+        PACKED_BIT => {
+            let vector = numbers
+                .into_iter()
+                .map(|n| match n {
+                    Number::Int(n) => u8::try_from(n).map_err(|e| e.to_string()),
+                    Number::Float(n) => Err(format!("expected u8, got float {}", n)),
+                })
+                .collect::<Result<Vec<u8>, String>>()?;
+            Ok(Vector::PackedBit(
+                PackedBitVector::new(vector, padding).map_err(|e| e.to_string())?,
+            ))
+        }
+        other => Err(format!("invalid data type: {}", other)),
+    }
+}
+
+fn run_test_file(test_file: TestFile) {
+    for test in test_file.tests {
+        let description = format!("{} ({})", test.description, test_file.description);
+
+        let test_vector = match (
+            vector_from_numbers(test.vector, test.d_type, test.padding),
+            test.valid,
+        ) {
+            (Ok(vector), true) => vector,
+            (Err(_), false) => return,
+            (Ok(vector), false) => panic!(
+                "{}: valid was false but successfully constructed vector {:?}",
+                description, vector
+            ),
+            (Err(error), true) => panic!(
+                "{}: valid was true but vector construction failed with error {}",
+                description, error
+            ),
+        };
+
+        let Some(canonical_bson) = test.canonical_bson else {
+            return;
+        };
+
+        let bytes = hex::decode(canonical_bson).expect(&description);
+        let mut test_document = Document::from_reader(bytes.as_slice()).expect(&description);
+        // Rename the field to match the name used in the struct below.
+        let vector = test_document
+            .remove(&test_file.test_key)
+            .expect(&description);
+        test_document.insert("vector", vector);
+        let bson = test_document.get("vector").expect(&description);
+        let test_binary = match bson {
+            Bson::Binary(binary) => binary,
+            other => panic!("{}: expected binary, got {}", description, other),
+        };
+
+        // TryFrom<Binary> for Vector
+        let parsed_vector = Vector::try_from(test_binary).expect(&description);
+        assert_eq!(parsed_vector, test_vector);
+
+        // From<Vector> for Binary
+        let binary = Binary::from(&test_vector);
+        assert_eq!(binary.subtype, BinarySubtype::Vector);
+        assert_eq!(&binary, test_binary);
+
+        // From<Vector> for Bson
+        let document = doc! { "vector": &test_vector };
+        assert_eq!(document, test_document);
+
+        // From<Vector> for RawBson
+        let raw_document = rawdoc! { "vector": &test_vector };
+        let test_raw_document = RawDocumentBuf::from_document(&test_document).expect(&description);
+        assert_eq!(raw_document, test_raw_document);
+
+        #[derive(Debug, Deserialize, PartialEq, Serialize)]
+        struct Data {
+            vector: Vector,
+        }
+        let data = Data {
+            vector: test_vector,
+        };
+
+        // Serialize for Vector (Document)
+        let serialized_document = to_document(&data).expect(&description);
+        assert_eq!(serialized_document, test_document);
+
+        // Deserialize for Vector (Document)
+        let deserialized_data: Data = from_document(serialized_document).expect(&description);
+        assert_eq!(deserialized_data, data);
+
+        // Serialize for Vector (RawDocumentBuf)
+        let serialized_raw_document = to_raw_document_buf(&data).expect(&description);
+        assert_eq!(serialized_raw_document, test_raw_document);
+
+        // Deserialize for Vector (RawDocumentBuf)
+        let deserialized_data: Data =
+            from_slice(serialized_raw_document.as_bytes()).expect(&description);
+        assert_eq!(deserialized_data, data);
+    }
+}
+
+#[test]
+fn run_vector_tests() {
+    run_spec_test(&["bson-binary-vector"], run_test_file);
+}

From 3b756a75afbfe1530fafc887b7fe61be3716f604 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Wed, 12 Feb 2025 12:30:37 -0500
Subject: [PATCH 091/156] RUST-2149 Sync additional vector tests (#514)

---
 .../spec/json/bson-binary-vector/README.md    |  7 +-
 .../spec/json/bson-binary-vector/float32.json | 18 ++++-
 .../spec/json/bson-binary-vector/int8.json    |  4 +-
 .../json/bson-binary-vector/packed_bit.json   | 23 +-----
 src/tests/spec/vector.rs                      | 77 +++++++++++--------
 5 files changed, 74 insertions(+), 55 deletions(-)

diff --git a/src/tests/spec/json/bson-binary-vector/README.md b/src/tests/spec/json/bson-binary-vector/README.md
index 3357ebb2..1a2cd871 100644
--- a/src/tests/spec/json/bson-binary-vector/README.md
+++ b/src/tests/spec/json/bson-binary-vector/README.md
@@ -29,7 +29,7 @@ Each JSON file contains three top-level keys.
 
 - `description`: string describing the test.
 - `valid`: boolean indicating if the vector, dtype, and padding should be considered a valid input.
-- `vector`: list of numbers
+- `vector`: (required if valid is true) list of numbers
 - `dtype_hex`: string defining the data type in hex (e.g. "0x10", "0x27")
 - `dtype_alias`: (optional) string defining the data dtype, perhaps as Enum.
 - `padding`: (optional) integer for byte padding. Defaults to 0.
@@ -50,7 +50,10 @@ MUST assert that the input float array is the same after encoding and decoding.
 
 #### To prove correct in an invalid case (`valid:false`), one MUST
 
-- raise an exception when attempting to encode a document from the numeric values, dtype, and padding.
+- if the vector field is present, raise an exception when attempting to encode a document from the numeric values,
+    dtype, and padding.
+- if the canonical_bson field is present, raise an exception when attempting to deserialize it into the corresponding
+    numeric values, as the field contains corrupted data.
 
 ## FAQ
 
diff --git a/src/tests/spec/json/bson-binary-vector/float32.json b/src/tests/spec/json/bson-binary-vector/float32.json
index 872c4353..845f504f 100644
--- a/src/tests/spec/json/bson-binary-vector/float32.json
+++ b/src/tests/spec/json/bson-binary-vector/float32.json
@@ -44,8 +44,22 @@
       "vector": [127.0, 7.0],
       "dtype_hex": "0x27",
       "dtype_alias": "FLOAT32",
-      "padding": 3
+      "padding": 3,
+      "canonical_bson": "1C00000005766563746F72000A0000000927030000FE420000E04000"
+    },
+    {
+      "description": "Insufficient vector data with 3 bytes FLOAT32",
+      "valid": false,
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "canonical_bson": "1700000005766563746F7200050000000927002A2A2A00"
+    },
+    {
+      "description": "Insufficient vector data with 5 bytes FLOAT32",
+      "valid": false,
+      "dtype_hex": "0x27",
+      "dtype_alias": "FLOAT32",
+      "canonical_bson": "1900000005766563746F7200070000000927002A2A2A2A2A00"
     }
   ]
 }
-
diff --git a/src/tests/spec/json/bson-binary-vector/int8.json b/src/tests/spec/json/bson-binary-vector/int8.json
index 7529721e..29524fb6 100644
--- a/src/tests/spec/json/bson-binary-vector/int8.json
+++ b/src/tests/spec/json/bson-binary-vector/int8.json
@@ -42,7 +42,8 @@
       "vector": [127, 7],
       "dtype_hex": "0x03",
       "dtype_alias": "INT8",
-      "padding": 3
+      "padding": 3,
+      "canonical_bson": "1600000005766563746F7200040000000903037F0700"
     },
     {
       "description": "INT8 with float inputs",
@@ -54,4 +55,3 @@
     }
   ]
 }
-
diff --git a/src/tests/spec/json/bson-binary-vector/packed_bit.json b/src/tests/spec/json/bson-binary-vector/packed_bit.json
index 035776e8..a220e7e3 100644
--- a/src/tests/spec/json/bson-binary-vector/packed_bit.json
+++ b/src/tests/spec/json/bson-binary-vector/packed_bit.json
@@ -8,7 +8,8 @@
       "vector": [],
       "dtype_hex": "0x10",
       "dtype_alias": "PACKED_BIT",
-      "padding": 1
+      "padding": 1,
+      "canonical_bson": "1400000005766563746F72000200000009100100"
     },
     {
       "description": "Simple Vector PACKED_BIT",
@@ -61,21 +62,14 @@
       "dtype_alias": "PACKED_BIT",
       "padding": 0
     },
-    {
-      "description": "Padding specified with no vector data PACKED_BIT",
-      "valid": false,
-      "vector": [],
-      "dtype_hex": "0x10",
-      "dtype_alias": "PACKED_BIT",
-      "padding": 1
-    },
     {
       "description": "Exceeding maximum padding PACKED_BIT",
       "valid": false,
       "vector": [1],
       "dtype_hex": "0x10",
       "dtype_alias": "PACKED_BIT",
-      "padding": 8
+      "padding": 8,
+      "canonical_bson": "1500000005766563746F7200030000000910080100"
     },
     {
       "description": "Negative padding PACKED_BIT",
@@ -84,15 +78,6 @@
       "dtype_hex": "0x10",
       "dtype_alias": "PACKED_BIT",
       "padding": -1
-    },
-    {
-      "description": "Vector with float values PACKED_BIT",
-      "valid": false,
-      "vector": [127.5],
-      "dtype_hex": "0x10",
-      "dtype_alias": "PACKED_BIT",
-      "padding": 0
     }
   ]
 }
-
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
index c297e285..8a9b9b0d 100644
--- a/src/tests/spec/vector.rs
+++ b/src/tests/spec/vector.rs
@@ -31,7 +31,7 @@ struct TestFile {
 struct Test {
     description: String,
     valid: bool,
-    vector: Vec<Number>,
+    vector: Option<Vec<Number>>,
     #[serde(
         rename = "dtype_hex",
         deserialize_with = "deserialize_u8_from_hex_string"
@@ -131,51 +131,68 @@ fn vector_from_numbers(
     }
 }
 
+// Only return the binary if it represents a valid vector; otherwise, return an error.
+fn binary_from_bytes(bson: &str, test_key: &str, description: &str) -> Result<Binary, String> {
+    let bytes = hex::decode(bson).expect(description);
+    let mut test_document = Document::from_reader(bytes.as_slice()).expect(description);
+    let bson = test_document.remove(test_key).expect(description);
+    let binary = match bson {
+        Bson::Binary(binary) => binary,
+        other => panic!("{}: expected binary, got {}", description, other),
+    };
+    if let Err(error) = Vector::try_from(&binary) {
+        Err(error.to_string())
+    } else {
+        Ok(binary)
+    }
+}
+
 fn run_test_file(test_file: TestFile) {
     for test in test_file.tests {
         let description = format!("{} ({})", test.description, test_file.description);
 
-        let test_vector = match (
-            vector_from_numbers(test.vector, test.d_type, test.padding),
-            test.valid,
-        ) {
-            (Ok(vector), true) => vector,
-            (Err(_), false) => return,
-            (Ok(vector), false) => panic!(
-                "{}: valid was false but successfully constructed vector {:?}",
-                description, vector
-            ),
-            (Err(error), true) => panic!(
-                "{}: valid was true but vector construction failed with error {}",
-                description, error
-            ),
+        let test_vector = match test.vector {
+            Some(vector) => match vector_from_numbers(vector, test.d_type, test.padding) {
+                Ok(vector) => {
+                    assert!(test.valid, "{}", description);
+                    Some(vector)
+                }
+                Err(error) => {
+                    assert!(!test.valid, "{}: {}", description, error);
+                    None
+                }
+            },
+            None => None,
+        };
+
+        let test_binary = match test.canonical_bson {
+            Some(bson) => match binary_from_bytes(&bson, &test_file.test_key, &description) {
+                Ok(vector) => {
+                    assert!(test.valid, "{}", description);
+                    Some(vector)
+                }
+                Err(error) => {
+                    assert!(!test.valid, "{}: {}", description, error);
+                    None
+                }
+            },
+            None => None,
         };
 
-        let Some(canonical_bson) = test.canonical_bson else {
+        let (Some(test_vector), Some(test_binary)) = (test_vector, test_binary) else {
             return;
         };
 
-        let bytes = hex::decode(canonical_bson).expect(&description);
-        let mut test_document = Document::from_reader(bytes.as_slice()).expect(&description);
-        // Rename the field to match the name used in the struct below.
-        let vector = test_document
-            .remove(&test_file.test_key)
-            .expect(&description);
-        test_document.insert("vector", vector);
-        let bson = test_document.get("vector").expect(&description);
-        let test_binary = match bson {
-            Bson::Binary(binary) => binary,
-            other => panic!("{}: expected binary, got {}", description, other),
-        };
+        let test_document = doc! { "vector": &test_binary };
 
         // TryFrom<Binary> for Vector
-        let parsed_vector = Vector::try_from(test_binary).expect(&description);
+        let parsed_vector = Vector::try_from(&test_binary).expect(&description);
         assert_eq!(parsed_vector, test_vector);
 
         // From<Vector> for Binary
         let binary = Binary::from(&test_vector);
         assert_eq!(binary.subtype, BinarySubtype::Vector);
-        assert_eq!(&binary, test_binary);
+        assert_eq!(binary, test_binary);
 
         // From<Vector> for Bson
         let document = doc! { "vector": &test_vector };

From aff37cf052a6ae92b98daa41e9f1982aef679559 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Barv=C3=AD=C5=99?= <barvirm@gmail.com>
Date: Thu, 13 Feb 2025 18:16:25 +0100
Subject: [PATCH 092/156] Update `base64` dependency (#515)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---------

Co-authored-by: Marek Barvíř <barvir@cadwork.cz>
Co-authored-by: Isabel Atkinson <isabel.atkinson@mongodb.com>
---
 Cargo.toml                      | 2 +-
 src/base64.rs                   | 9 +++++++++
 src/binary.rs                   | 2 +-
 src/bson.rs                     | 1 +
 src/de/raw.rs                   | 1 +
 src/extjson/models.rs           | 2 +-
 src/lib.rs                      | 1 +
 src/raw/bson_ref.rs             | 1 +
 src/ser/raw/value_serializer.rs | 1 +
 src/ser/serde.rs                | 1 +
 src/tests/modules/binary.rs     | 2 +-
 src/tests/modules/bson.rs       | 1 +
 src/tests/modules/macros.rs     | 1 +
 13 files changed, 21 insertions(+), 4 deletions(-)
 create mode 100644 src/base64.rs

diff --git a/Cargo.toml b/Cargo.toml
index 5fd8df36..bec0c3db 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -63,7 +63,7 @@ serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", features = ["preserve_order"] }
 indexmap = "2.1.0"
 hex = "0.4.2"
-base64 = "0.13.0"
+base64 = "0.22.1"
 once_cell = "1.5.1"
 uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true }
 uuid = { version = "1.1.2", features = ["serde", "v4"] }
diff --git a/src/base64.rs b/src/base64.rs
new file mode 100644
index 00000000..113f5fdf
--- /dev/null
+++ b/src/base64.rs
@@ -0,0 +1,9 @@
+use base64::{engine::general_purpose::STANDARD, DecodeError, Engine};
+
+pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
+    STANDARD.decode(input)
+}
+
+pub fn encode<T: AsRef<[u8]>>(input: T) -> String {
+    STANDARD.encode(input)
+}
diff --git a/src/binary.rs b/src/binary.rs
index ae5240b9..f977088b 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -2,7 +2,7 @@
 
 mod vector;
 
-use crate::{spec::BinarySubtype, Document, RawBinaryRef};
+use crate::{base64, spec::BinarySubtype, Document, RawBinaryRef};
 use std::{
     convert::TryFrom,
     error,
diff --git a/src/bson.rs b/src/bson.rs
index 806fee0b..b112ac47 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -32,6 +32,7 @@ use serde_json::{json, Value};
 
 pub use crate::document::Document;
 use crate::{
+    base64,
     oid::{self, ObjectId},
     spec::{BinarySubtype, ElementType},
     Binary,
diff --git a/src/de/raw.rs b/src/de/raw.rs
index e75b2b32..69607bc6 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -7,6 +7,7 @@ use serde::{
 };
 
 use crate::{
+    base64,
     oid::ObjectId,
     raw::{
         RawBinaryRef,
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index b91d5f67..b726aa41 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -7,7 +7,7 @@ use serde::{
 };
 use std::borrow::Cow;
 
-use crate::{extjson, oid, raw::serde::CowStr, spec::BinarySubtype, Bson};
+use crate::{base64, extjson, oid, raw::serde::CowStr, spec::BinarySubtype, Bson};
 
 #[derive(Deserialize)]
 #[serde(deny_unknown_fields)]
diff --git a/src/lib.rs b/src/lib.rs
index 7386720b..077a2db6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -331,6 +331,7 @@ pub use self::de::{from_reader_utf8_lossy, from_slice_utf8_lossy};
 
 #[macro_use]
 mod macros;
+mod base64;
 pub mod binary;
 mod bson;
 pub mod datetime;
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index f1f0fde9..94a9b9fb 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -12,6 +12,7 @@ use super::{
     Result,
 };
 use crate::{
+    base64,
     extjson,
     oid::{self, ObjectId},
     raw::{RawJavaScriptCodeWithScope, RAW_BSON_NEWTYPE},
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 8ed93eda..8c0b2215 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -6,6 +6,7 @@ use serde::{
 };
 
 use crate::{
+    base64,
     oid::ObjectId,
     raw::RAW_DOCUMENT_NEWTYPE,
     ser::{write_binary, write_cstring, write_i32, write_i64, write_string, Error, Result},
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index 9b5ce313..469babee 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -12,6 +12,7 @@ use serde::ser::{
 };
 
 use crate::{
+    base64,
     bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
     extjson,
diff --git a/src/tests/modules/binary.rs b/src/tests/modules/binary.rs
index d26c4d65..5ecba080 100644
--- a/src/tests/modules/binary.rs
+++ b/src/tests/modules/binary.rs
@@ -1,4 +1,4 @@
-use crate::{spec::BinarySubtype, tests::LOCK, Binary};
+use crate::{base64, spec::BinarySubtype, tests::LOCK, Binary};
 
 #[test]
 fn binary_from_base64() {
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index d5362d20..1e4f7b1d 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -4,6 +4,7 @@ use std::{
 };
 
 use crate::{
+    base64,
     doc,
     oid::ObjectId,
     spec::BinarySubtype,
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
index 150e22d2..12e718dd 100644
--- a/src/tests/modules/macros.rs
+++ b/src/tests/modules/macros.rs
@@ -1,4 +1,5 @@
 use crate::{
+    base64,
     doc,
     oid::ObjectId,
     spec::BinarySubtype,

From f2cbaf1d9b521fc4d1714f455cf7a9a1e5ea14d6 Mon Sep 17 00:00:00 2001
From: Biswajit Thakur <63996316+BiswajitThakur@users.noreply.github.com>
Date: Wed, 19 Feb 2025 22:35:27 +0530
Subject: [PATCH 093/156] RUST-2158 update edition & rand crate (#516)

---------

Co-authored-by: Isabel Atkinson <isabel.atkinson@mongodb.com>
---
 Cargo.toml | 4 ++--
 src/oid.rs | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index bec0c3db..683c2299 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ description = "Encoding and decoding support for BSON in Rust"
 license = "MIT"
 readme = "README.md"
 repository = "https://github.com/mongodb/bson-rust"
-edition = "2018"
+edition = "2021"
 keywords = ["bson", "mongodb", "serde", "serialization", "deserialization"]
 categories = ["encoding"]
 
@@ -58,7 +58,7 @@ name = "bson"
 [dependencies]
 ahash = "0.8.0"
 chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
-rand = "0.8"
+rand = "0.9"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", features = ["preserve_order"] }
 indexmap = "2.1.0"
diff --git a/src/oid.rs b/src/oid.rs
index 8281d802..a6bb7dbd 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -14,7 +14,7 @@ use std::{convert::TryInto, time::SystemTime};
 
 use hex::{self, FromHexError};
 use once_cell::sync::Lazy;
-use rand::{random, thread_rng, Rng};
+use rand::{random, rng, Rng};
 
 const TIMESTAMP_SIZE: usize = 4;
 const PROCESS_ID_SIZE: usize = 5;
@@ -27,7 +27,7 @@ const COUNTER_OFFSET: usize = PROCESS_ID_OFFSET + PROCESS_ID_SIZE;
 const MAX_U24: usize = 0xFF_FFFF;
 
 static OID_COUNTER: Lazy<AtomicUsize> =
-    Lazy::new(|| AtomicUsize::new(thread_rng().gen_range(0..=MAX_U24)));
+    Lazy::new(|| AtomicUsize::new(rng().random_range(0..=MAX_U24)));
 
 /// Errors that can occur during [`ObjectId`] construction and generation.
 #[derive(Clone, Debug)]

From 8cf62fcbdb49a1ba97210ee17b4d7a0e029b6aec Mon Sep 17 00:00:00 2001
From: xiangjinwu <17769960+xiangjinwu@users.noreply.github.com>
Date: Mon, 10 Mar 2025 23:25:54 +0800
Subject: [PATCH 094/156] feat(extjson): parse legacy `{"$date": <ms since
 epoch>}` (#519)

---
 src/extjson/models.rs |  2 ++
 src/tests/serde.rs    | 13 +++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index b726aa41..297b47d6 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -256,6 +256,7 @@ pub(crate) struct DateTime {
 pub(crate) enum DateTimeBody {
     Canonical(Int64),
     Relaxed(String),
+    Legacy(i64),
 }
 
 impl DateTimeBody {
@@ -282,6 +283,7 @@ impl DateTime {
                 })?;
                 Ok(datetime)
             }
+            DateTimeBody::Legacy(ms) => Ok(crate::DateTime::from_millis(ms)),
         }
     }
 }
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 595cc312..cb49f9d1 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -665,6 +665,19 @@ fn test_de_uuid_extjson_string() {
     assert_eq!(actual_uuid_bson, expected_uuid_bson);
 }
 
+#[test]
+fn test_de_date_extjson_number() {
+    let _guard = LOCK.run_concurrently();
+
+    let ext_json_canonical = r#"{ "$date": { "$numberLong": "1136239445000" } }"#;
+    let expected_date_bson: Bson = serde_json::from_str(ext_json_canonical).unwrap();
+
+    let ext_json_legacy_java = r#"{ "$date": 1136239445000 }"#;
+    let actual_date_bson: Bson = serde_json::from_str(ext_json_legacy_java).unwrap();
+
+    assert_eq!(actual_date_bson, expected_date_bson);
+}
+
 #[test]
 fn test_de_oid_string() {
     let _guard = LOCK.run_concurrently();

From cc292ea227d3268a8c197ca79794aa2fe4fab684 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 10 Mar 2025 14:35:05 -0400
Subject: [PATCH 095/156] RUST-1375 Update bson crate MSRV policy (#520)

---
 README.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 0f881635..efb48dc4 100644
--- a/README.md
+++ b/README.md
@@ -269,8 +269,7 @@ This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `
 
 ## Minimum supported Rust version (MSRV)
 
-The MSRV for this crate is currently 1.71.1. This will be rarely be increased, and if it ever is,
-it will only happen in a minor or major version release.
+The MSRV for this crate is currently 1.71.1. Increases to the MSRV will only happen in a minor or major version release, and will be to a Rust version at least six months old.
 
 ## Contributing
 

From 8468724bea8a5224a8c7b20bcdb02a4041747924 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 13 Mar 2025 12:30:31 -0400
Subject: [PATCH 096/156] RUST-2177 Fix WASM compilation failures (#521)

---
 .evergreen/MSRV-Cargo.toml.diff | 10 ----------
 .evergreen/compile-only.sh      |  3 +++
 .evergreen/config.yml           | 14 +++++++-------
 .evergreen/run-wasm-tests.sh    | 10 +++++++---
 Cargo.toml                      |  6 ++++--
 README.md                       |  2 +-
 clippy.toml                     |  2 +-
 src/lib.rs                      |  2 +-
 wasm-test/.cargo/config.toml    |  2 ++
 wasm-test/Cargo.toml            |  1 -
 10 files changed, 26 insertions(+), 26 deletions(-)
 create mode 100644 wasm-test/.cargo/config.toml

diff --git a/.evergreen/MSRV-Cargo.toml.diff b/.evergreen/MSRV-Cargo.toml.diff
index 437441ae..e69de29b 100644
--- a/.evergreen/MSRV-Cargo.toml.diff
+++ b/.evergreen/MSRV-Cargo.toml.diff
@@ -1,10 +0,0 @@
---- Cargo.toml	2024-12-12 10:00:04
-+++ Cargo.toml.msrv	2024-12-12 10:20:57
-@@ -57,6 +57,7 @@
- 
- [dependencies]
- ahash = "0.8.0"
-+bumpalo = "=3.14.0"
- chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
- rand = "0.8"
- serde = { version = "1.0", features = ["derive"] }
diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index 395267e7..dc56e238 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -10,6 +10,9 @@ if [ ! -z "$TARGET" ]; then
         # renamed in newer versions of rustc
         TARGET="wasm32-wasip1"
     fi
+    if [[ "$TARGET" = "wasm32-unknown-unknown" ]]; then
+        export RUSTFLAGS='--cfg getrandom_backend="wasm_js"'
+    fi
     rustup target add $TARGET --toolchain $RUST_VERSION
     TARGET="--target=$TARGET"
 fi
diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 673b5ffc..ae773d9f 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -216,9 +216,9 @@ axes:
   - id: "extra-rust-versions"
     values:
       - id: "min"
-        display_name: "1.71.1 (minimum supported version)"
+        display_name: "1.81 (minimum supported version)"
         variables:
-          RUST_VERSION: "1.71.1"
+          RUST_VERSION: "1.81"
           MSRV: "true"
       - id: "nightly"
         display_name: "nightly"
@@ -242,7 +242,7 @@ buildvariants:
   name: "tests"
   display_name: "Tests"
   run_on:
-    - ubuntu1804-test
+    - ubuntu2204-small
   tasks:
     - name: "test"
 
@@ -252,7 +252,7 @@ buildvariants:
     extra-targets: "*"
   display_name: "Compile on Rust ${extra-rust-versions} (${extra-targets})"
   run_on:
-    - ubuntu1804-test
+    - ubuntu2204-small
   tasks:
     - name: "compile-only"
 
@@ -260,7 +260,7 @@ buildvariants:
   name: "lint"
   display_name: "Lint"
   run_on:
-    - ubuntu1804-test
+    - ubuntu2204-small
   tasks:
     - name: "check-clippy"
     - name: "check-rustfmt"
@@ -270,7 +270,7 @@ buildvariants:
   name: "fuzz"
   display_name: "Raw BSON Fuzzer"
   run_on:
-    - ubuntu1804-test
+    - ubuntu2204-small
   tasks:
     - name: "run-fuzzer"
 
@@ -278,6 +278,6 @@ buildvariants:
   name: "wasm"
   display_name: "WASM"
   run_on:
-    - ubuntu1804-test
+    - ubuntu2204-small
   tasks:
     - name: "wasm-test"
diff --git a/.evergreen/run-wasm-tests.sh b/.evergreen/run-wasm-tests.sh
index 18c835ca..4f7d8666 100755
--- a/.evergreen/run-wasm-tests.sh
+++ b/.evergreen/run-wasm-tests.sh
@@ -4,10 +4,14 @@ set -o errexit
 
 . ~/.cargo/env
 
-rustup update 1.81
-rustup default 1.81
-
 curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
 
+# install nvm
+curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
+. ~/.nvm/nvm.sh
+# install node
+nvm install --no-progress node
+node --version
+
 cd $(dirname $0)/../wasm-test
 wasm-pack test --node
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 683c2299..16cd6c60 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -73,8 +73,12 @@ serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
 serde_path_to_error = { version = "0.1.16", optional = true }
+
 [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
 js-sys = "0.3"
+uuid = { version = "1.1.2", features = ["serde", "v4", "js"] }
+getrandom = { version = "0.2", features = ["js"] }
+getrandom_03 = { package = "getrandom", version = "0.3", features = ["wasm_js"] }
 
 [dev-dependencies]
 assert_matches = "1.2"
@@ -84,8 +88,6 @@ proptest = "1.0.0"
 serde_bytes = "0.11"
 serde_path_to_error = "0.1.16"
 chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false }
-[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
-getrandom = { version = "0.2", features = ["js"] }
 
 [package.metadata.docs.rs]
 all-features = true
diff --git a/README.md b/README.md
index efb48dc4..d9ba4093 100644
--- a/README.md
+++ b/README.md
@@ -269,7 +269,7 @@ This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `
 
 ## Minimum supported Rust version (MSRV)
 
-The MSRV for this crate is currently 1.71.1. Increases to the MSRV will only happen in a minor or major version release, and will be to a Rust version at least six months old.
+The MSRV for this crate is currently 1.81. Increases to the MSRV will only happen in a minor or major version release, and will be to a Rust version at least six months old.
 
 ## Contributing
 
diff --git a/clippy.toml b/clippy.toml
index 49c31fa5..40d6ec53 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1 +1 @@
-msrv = "1.71.1"
\ No newline at end of file
+msrv = "1.81"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 077a2db6..11fc5373 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -277,7 +277,7 @@
 //!
 //! ## Minimum supported Rust version (MSRV)
 //!
-//! The MSRV for this crate is currently 1.71.1. This will be rarely be increased, and if it ever
+//! The MSRV for this crate is currently 1.81. This will be rarely be increased, and if it ever
 //! is, it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
diff --git a/wasm-test/.cargo/config.toml b/wasm-test/.cargo/config.toml
new file mode 100644
index 00000000..fa995ebe
--- /dev/null
+++ b/wasm-test/.cargo/config.toml
@@ -0,0 +1,2 @@
+[build]
+rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
\ No newline at end of file
diff --git a/wasm-test/Cargo.toml b/wasm-test/Cargo.toml
index fb583123..92c37de6 100644
--- a/wasm-test/Cargo.toml
+++ b/wasm-test/Cargo.toml
@@ -11,7 +11,6 @@ crate-type = ["cdylib", "rlib"]
 
 [dependencies]
 bson = { path = ".." }
-getrandom = { version = "0.2", features = ["js"] }
 
 [dev-dependencies]
 wasm-bindgen-test = "0.3.0"
\ No newline at end of file

From ff8742eb70a66ba7eb841204992e5fca327a5dcf Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 13 Mar 2025 14:09:24 -0400
Subject: [PATCH 097/156] release v2.14.0 (#522)

---
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 16cd6c60..f26a1091 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.13.0"
+version = "2.14.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index d9ba4093..26ce2700 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.13.0"
+bson = "2.14.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 11fc5373..b7021b0f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.13.0"
+//! bson = "2.14.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From a3ceaf344fb313342872441fd176aa3a1c0ef87d Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 24 Mar 2025 11:49:37 -0400
Subject: [PATCH 098/156] RUST-2147 Update float32 vector test and remove
 special casing (#523)

---
 .../spec/json/bson-binary-vector/float32.json |  2 +-
 src/tests/spec/vector.rs                      | 31 ++-----------------
 2 files changed, 3 insertions(+), 30 deletions(-)

diff --git a/src/tests/spec/json/bson-binary-vector/float32.json b/src/tests/spec/json/bson-binary-vector/float32.json
index 845f504f..72dafce1 100644
--- a/src/tests/spec/json/bson-binary-vector/float32.json
+++ b/src/tests/spec/json/bson-binary-vector/float32.json
@@ -32,7 +32,7 @@
     {
       "description": "Infinity Vector FLOAT32",
       "valid": true,
-      "vector": ["-inf", 0.0, "inf"],
+      "vector": [{"$numberDouble": "-Infinity"}, 0.0, {"$numberDouble": "Infinity"} ],
       "dtype_hex": "0x27",
       "dtype_alias": "FLOAT32",
       "padding": 0,
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
index 8a9b9b0d..6874d8fc 100644
--- a/src/tests/spec/vector.rs
+++ b/src/tests/spec/vector.rs
@@ -49,40 +49,13 @@ where
     u8::from_str_radix(s.trim_start_matches("0x"), 16).map_err(serde::de::Error::custom)
 }
 
+#[derive(Deserialize)]
+#[serde(untagged)]
 enum Number {
     Int(i16),
     Float(f32),
 }
 
-impl<'de> Deserialize<'de> for Number {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        #[derive(Deserialize)]
-        #[serde(untagged)]
-        enum NumberHelper {
-            Int(i16),
-            Float(f32),
-            String(String),
-        }
-
-        let helper = NumberHelper::deserialize(deserializer)?;
-        match helper {
-            NumberHelper::Int(n) => Ok(Self::Int(n)),
-            NumberHelper::Float(n) => Ok(Self::Float(n)),
-            NumberHelper::String(s) => match s.as_str() {
-                "inf" => Ok(Self::Float(f32::INFINITY)),
-                "-inf" => Ok(Self::Float(f32::NEG_INFINITY)),
-                other => Err(serde::de::Error::custom(format!(
-                    "unsupported number value {}",
-                    other
-                ))),
-            },
-        }
-    }
-}
-
 // Some of the invalid cases (e.g. mixed number types, padding for non-packed-bit vectors) are
 // impossible to construct, so we return an error from this method.
 fn vector_from_numbers(

From 7029790b17a7e06be4d270ab2149f710a1935f18 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Wed, 26 Mar 2025 10:50:28 -0400
Subject: [PATCH 099/156] Allow passing owned `Vector` to `doc` macro (#524)

---
 src/binary/vector.rs     | 6 +++---
 src/tests/spec/vector.rs | 2 ++
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/binary/vector.rs b/src/binary/vector.rs
index 4f74e8f8..7226e867 100644
--- a/src/binary/vector.rs
+++ b/src/binary/vector.rs
@@ -246,10 +246,10 @@ impl TryFrom<Binary> for Vector {
     }
 }
 
-// Convenience impl to allow passing a Vector directly into the doc! macro. From<Vector> is already
+// Convenience impl to allow passing a Vector directly into the doc! macro. From<&Vector> is already
 // implemented by a blanket impl in src/bson.rs.
-impl From<&Vector> for Bson {
-    fn from(vector: &Vector) -> Self {
+impl From<Vector> for Bson {
+    fn from(vector: Vector) -> Self {
         Self::Binary(Binary::from(vector))
     }
 }
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
index 6874d8fc..95f389ce 100644
--- a/src/tests/spec/vector.rs
+++ b/src/tests/spec/vector.rs
@@ -170,6 +170,8 @@ fn run_test_file(test_file: TestFile) {
         // From<Vector> for Bson
         let document = doc! { "vector": &test_vector };
         assert_eq!(document, test_document);
+        let document = doc! { "vector": test_vector.clone() };
+        assert_eq!(document, test_document);
 
         // From<Vector> for RawBson
         let raw_document = rawdoc! { "vector": &test_vector };

From 2a638a1adbb7b0e85daba1d0648d862c70db88c7 Mon Sep 17 00:00:00 2001
From: Kevin Albertson <kevin.eric.albertson@gmail.com>
Date: Thu, 17 Apr 2025 14:13:06 -0400
Subject: [PATCH 100/156] RUST-2195 add CODEOWNERS (#527)

---
 .github/CODEOWNERS | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 .github/CODEOWNERS

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..4bf1c6ee
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# Listing code owners is required by DRIVERS-3098
+* @mongodb/dbx-rust

From fdbf863ab5531ade49c09a27019b32e3573ad437 Mon Sep 17 00:00:00 2001
From: Trevor <trklingler3@gmail.com>
Date: Fri, 2 May 2025 11:09:23 -0600
Subject: [PATCH 101/156] add `uncapped_max_size` feature to allow increasing
 max BSON size (#528)

* add `uncapped_max_size` feature to allow increasing max BSON size

* fix typo in `uncapped_max_size` feature table in readme

---------

Co-authored-by: Trevor Klingler <trevorklingler@gmail.com>
---
 Cargo.toml    | 3 +++
 README.md     | 1 +
 src/de/mod.rs | 3 +++
 3 files changed, 7 insertions(+)

diff --git a/Cargo.toml b/Cargo.toml
index f26a1091..8bf6b31f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,6 +45,9 @@ uuid-1 = []
 time-0_3 = []
 # If enabled, implement Hash/Eq for Bson and Document
 hashable = []
+# If enabled, the maximum document size will be increased from the MongoDB cap
+# of 16 MB to the BSON spec maximum size of 2^31 - 1
+uncapped_max_size = []
 serde_path_to_error = ["dep:serde_path_to_error"]
 # if enabled, include serde_with interop.
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
diff --git a/README.md b/README.md
index 26ce2700..2f230d80 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | serde_path_to_error  | no |
 | `hashable`   | Implement `core::hash::Hash` and `std::cmp::Eq` on `Bson` and `Document`.                  | n/a                | no      |
+| `uncapped_max_size` | Increase the maximum document size from the MongoDB cap of 16 MB to the BSON spec maximum size of 2^31 - 1 bytes. | n/a | no |
 
 ## Overview of the BSON Format
 
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 1ee8e5a4..f9f6814c 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -47,7 +47,10 @@ pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor};
 
 pub(crate) use self::raw::Deserializer as RawDeserializer;
 
+#[cfg(not(feature = "uncapped_max_size"))]
 pub(crate) const MAX_BSON_SIZE: i32 = 16 * 1024 * 1024;
+#[cfg(feature = "uncapped_max_size")]
+pub(crate) const MAX_BSON_SIZE: i32 = i32::MAX;
 pub(crate) const MIN_BSON_DOCUMENT_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
 pub(crate) const MIN_BSON_STRING_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
 pub(crate) const MIN_CODE_WITH_SCOPE_SIZE: i32 = 4 + MIN_BSON_STRING_SIZE + MIN_BSON_DOCUMENT_SIZE;

From 806d68f5800f5baf9fab3c8e367ab6780e06873f Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 8 May 2025 16:06:15 -0400
Subject: [PATCH 102/156] RUST-2173 Check in `Cargo.lock` (#532)

---
 .evergreen/MSRV-Cargo.toml.diff |    0
 .evergreen/compile-only.sh      |    4 +-
 .gitignore                      |    1 -
 Cargo.lock                      | 1471 +++++++++++++++++++++++++++++++
 Cargo.toml                      |    1 +
 README.md                       |    2 +-
 serde-tests/Cargo.lock          |  880 ++++++++++++++++++
 wasm-test/Cargo.lock            |  700 +++++++++++++++
 8 files changed, 3055 insertions(+), 4 deletions(-)
 delete mode 100644 .evergreen/MSRV-Cargo.toml.diff
 create mode 100644 Cargo.lock
 create mode 100644 serde-tests/Cargo.lock
 create mode 100644 wasm-test/Cargo.lock

diff --git a/.evergreen/MSRV-Cargo.toml.diff b/.evergreen/MSRV-Cargo.toml.diff
deleted file mode 100644
index e69de29b..00000000
diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh
index dc56e238..b5aa3838 100755
--- a/.evergreen/compile-only.sh
+++ b/.evergreen/compile-only.sh
@@ -17,9 +17,9 @@ if [ ! -z "$TARGET" ]; then
     TARGET="--target=$TARGET"
 fi
 
-# pin necessary dependencies when checking msrv compilation
+# Generate a new lockfile with MSRV-compatible dependencies.
 if [ "$MSRV" = "true" ]; then
-    patch Cargo.toml .evergreen/MSRV-Cargo.toml.diff
+    CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS=fallback cargo +nightly -Zmsrv-policy generate-lockfile
 fi
 
 rustup run $RUST_VERSION cargo build $TARGET
diff --git a/.gitignore b/.gitignore
index 95f06a2b..f52b0def 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
 target
-Cargo.lock
 .vscode
 .idea
 *~
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 00000000..fb4cf2f1
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,1471 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "ahash"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
+dependencies = [
+ "cfg-if",
+ "getrandom 0.3.2",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "bson"
+version = "2.14.0"
+dependencies = [
+ "ahash",
+ "assert_matches",
+ "base64",
+ "bitvec",
+ "chrono",
+ "criterion",
+ "getrandom 0.2.16",
+ "getrandom 0.3.2",
+ "hex",
+ "indexmap 2.9.0",
+ "js-sys",
+ "once_cell",
+ "pretty_assertions",
+ "proptest",
+ "rand 0.9.1",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "serde_path_to_error",
+ "serde_with 1.14.0",
+ "serde_with 3.12.0",
+ "time",
+ "uuid 0.8.2",
+ "uuid 1.16.0",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
+name = "cc"
+version = "1.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "serde",
+ "windows-link",
+]
+
+[[package]]
+name = "clap"
+version = "2.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+dependencies = [
+ "bitflags 1.3.2",
+ "textwrap",
+ "unicode-width",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "criterion"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
+dependencies = [
+ "atty",
+ "cast",
+ "clap",
+ "criterion-plot",
+ "csv",
+ "itertools",
+ "lazy_static",
+ "num-traits",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_cbor",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
+dependencies = [
+ "cast",
+ "itertools",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "csv"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
+dependencies = [
+ "csv-core",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ctor"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
+dependencies = [
+ "darling_core 0.13.4",
+ "darling_macro 0.13.4",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+dependencies = [
+ "darling_core 0.20.11",
+ "darling_macro 0.20.11",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim 0.10.0",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim 0.11.1",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
+dependencies = [
+ "darling_core 0.13.4",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+dependencies = [
+ "darling_core 0.20.11",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "deranged"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
+dependencies = [
+ "powerfmt",
+ "serde",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "half"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.3",
+ "serde",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.172"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "oorandom"
+version = "11.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
+
+[[package]]
+name = "output_vt100"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "plotters"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
+dependencies = [
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "plotters-backend"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
+
+[[package]]
+name = "plotters-svg"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
+dependencies = [
+ "plotters-backend",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "pretty_assertions"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
+dependencies = [
+ "ansi_term",
+ "ctor",
+ "difference",
+ "output_vt100",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "proptest"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50"
+dependencies = [
+ "bit-set",
+ "bit-vec",
+ "bitflags 2.9.0",
+ "lazy_static",
+ "num-traits",
+ "rand 0.8.5",
+ "rand_chacha 0.3.1",
+ "rand_xorshift",
+ "regex-syntax",
+ "rusty-fork",
+ "tempfile",
+ "unarray",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.2",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "rustix"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+dependencies = [
+ "bitflags 2.9.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+
+[[package]]
+name = "rusty-fork"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
+dependencies = [
+ "fnv",
+ "quick-error",
+ "tempfile",
+ "wait-timeout",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_cbor"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
+dependencies = [
+ "half",
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "indexmap 2.9.0",
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
+dependencies = [
+ "serde",
+ "serde_with_macros 1.5.2",
+]
+
+[[package]]
+name = "serde_with"
+version = "3.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
+dependencies = [
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.9.0",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_with_macros 3.12.0",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
+dependencies = [
+ "darling 0.13.4",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
+dependencies = [
+ "darling 0.20.11",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "tempfile"
+version = "3.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
+dependencies = [
+ "fastrand",
+ "getrandom 0.3.2",
+ "once_cell",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "time"
+version = "0.3.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
+
+[[package]]
+name = "time-macros"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "unarray"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom 0.2.16",
+ "serde",
+]
+
+[[package]]
+name = "uuid"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+dependencies = [
+ "getrandom 0.3.2",
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-core"
+version = "0.61.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
+[[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags 2.9.0",
+]
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 8bf6b31f..2fbbcbd4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,7 @@ repository = "https://github.com/mongodb/bson-rust"
 edition = "2021"
 keywords = ["bson", "mongodb", "serde", "serialization", "deserialization"]
 categories = ["encoding"]
+rust-version = "1.81"
 
 # By default cargo include everything git include
 # cargo diet can help to manage what's not useful.
diff --git a/README.md b/README.md
index 2f230d80..6567e94d 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ Encoding and decoding support for BSON in Rust
 
 ## Installation
 ### Requirements
-- Rust 1.48+
+- Rust 1.81+
 
 ### Importing
 This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application, simply add it to your project's `Cargo.toml`.
diff --git a/serde-tests/Cargo.lock b/serde-tests/Cargo.lock
new file mode 100644
index 00000000..ff854ffd
--- /dev/null
+++ b/serde-tests/Cargo.lock
@@ -0,0 +1,880 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "ahash"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+dependencies = [
+ "cfg-if",
+ "getrandom 0.2.8",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "bson"
+version = "2.14.0"
+dependencies = [
+ "ahash",
+ "base64 0.22.1",
+ "bitvec",
+ "chrono",
+ "getrandom 0.2.8",
+ "getrandom 0.3.2",
+ "hex",
+ "indexmap 2.1.0",
+ "js-sys",
+ "once_cell",
+ "rand",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "serde_with",
+ "time 0.3.17",
+ "uuid 0.8.2",
+ "uuid 1.2.2",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cc"
+version = "1.0.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-integer",
+ "num-traits",
+ "time 0.1.45",
+ "wasm-bindgen",
+ "winapi",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
+dependencies = [
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+
+[[package]]
+name = "ctor"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
+dependencies = [
+ "quote",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "cxx"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453"
+dependencies = [
+ "cc",
+ "cxxbridge-flags",
+ "cxxbridge-macro",
+ "link-cplusplus",
+]
+
+[[package]]
+name = "cxx-build"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0"
+dependencies = [
+ "cc",
+ "codespan-reporting",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "scratch",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "cxxbridge-flags"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71"
+
+[[package]]
+name = "cxxbridge-macro"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "darling"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
+name = "getrandom"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "winapi",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
+dependencies = [
+ "cxx",
+ "cxx-build",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indexmap"
+version = "1.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.3",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.172"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+
+[[package]]
+name = "link-cplusplus"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "output_vt100"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "pretty_assertions"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
+dependencies = [
+ "ansi_term",
+ "ctor",
+ "difference",
+ "output_vt100",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.2",
+]
+
+[[package]]
+name = "rmp"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f"
+dependencies = [
+ "byteorder",
+ "num-traits",
+ "paste",
+]
+
+[[package]]
+name = "rmp-serde"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "723ecff9ad04f4ad92fe1c8ca6c20d2196d9286e9c60727c4cb5511629260e9d"
+dependencies = [
+ "byteorder",
+ "rmp",
+ "serde",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+
+[[package]]
+name = "ryu"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+
+[[package]]
+name = "scratch"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
+
+[[package]]
+name = "serde"
+version = "1.0.148"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde-tests"
+version = "0.1.0"
+dependencies = [
+ "base64 0.13.1",
+ "bson",
+ "chrono",
+ "hex",
+ "pretty_assertions",
+ "rmp-serde",
+ "serde",
+ "serde_json",
+ "serde_with",
+ "uuid 0.8.2",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.148"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
+dependencies = [
+ "indexmap 1.9.2",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
+dependencies = [
+ "serde",
+ "serde_with_macros",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.104",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "time"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
+dependencies = [
+ "libc",
+ "wasi 0.10.0+wasi-snapshot-preview1",
+ "winapi",
+]
+
+[[package]]
+name = "time"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
+dependencies = [
+ "itoa",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+
+[[package]]
+name = "time-macros"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
+dependencies = [
+ "time-core",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom 0.2.8",
+ "serde",
+]
+
+[[package]]
+name = "uuid"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
+dependencies = [
+ "getrandom 0.2.8",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
diff --git a/wasm-test/Cargo.lock b/wasm-test/Cargo.lock
new file mode 100644
index 00000000..d6f79298
--- /dev/null
+++ b/wasm-test/Cargo.lock
@@ -0,0 +1,700 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "getrandom 0.2.15",
+ "once_cell",
+ "version_check",
+ "zerocopy 0.7.35",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
+
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "bson"
+version = "2.13.0"
+dependencies = [
+ "ahash",
+ "base64",
+ "bitvec",
+ "hex",
+ "indexmap",
+ "js-sys",
+ "once_cell",
+ "rand",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "time",
+ "uuid",
+]
+
+[[package]]
+name = "bson-wasm-test"
+version = "0.1.0"
+dependencies = [
+ "bson",
+ "getrandom 0.3.1",
+ "wasm-bindgen-test",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cc"
+version = "1.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.13.3+wasi-0.2.2",
+ "wasm-bindgen",
+ "windows-targets",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "indexmap"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.169"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+
+[[package]]
+name = "log"
+version = "0.4.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "minicov"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
+dependencies = [
+ "cc",
+ "walkdir",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "once_cell"
+version = "1.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy 0.7.35",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+ "zerocopy 0.8.23",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.1",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+
+[[package]]
+name = "ryu"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.138"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "syn"
+version = "2.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "time"
+version = "0.3.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
+[[package]]
+name = "time-macros"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
+
+[[package]]
+name = "uuid"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6"
+dependencies = [
+ "getrandom 0.3.1",
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-bindgen-test"
+version = "0.3.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3"
+dependencies = [
+ "js-sys",
+ "minicov",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-bindgen-test-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-test-macro"
+version = "0.3.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive 0.7.35",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
+dependencies = [
+ "zerocopy-derive 0.8.23",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]

From fc106787b2f0b1559dfef261e3f108d91518557f Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Fri, 9 May 2025 13:14:09 -0400
Subject: [PATCH 103/156] RUST-1906 Remove human readable options (#531)

---
 serde-tests/options.rs     | 218 -------------------------------------
 serde-tests/test.rs        |  79 --------------
 src/de/mod.rs              |  59 +---------
 src/de/raw.rs              |  14 +--
 src/de/serde.rs            |  41 +------
 src/lib.rs                 |  22 +---
 src/ser/mod.rs             |  59 ++--------
 src/ser/serde.rs           |  40 +------
 src/serde_helpers.rs       |   6 +-
 src/tests/serde_helpers.rs |  44 +++-----
 10 files changed, 46 insertions(+), 536 deletions(-)
 delete mode 100644 serde-tests/options.rs

diff --git a/serde-tests/options.rs b/serde-tests/options.rs
deleted file mode 100644
index 63324dc0..00000000
--- a/serde-tests/options.rs
+++ /dev/null
@@ -1,218 +0,0 @@
-use std::collections::HashMap;
-
-use bson::{doc, Bson, DeserializerOptions, SerializerOptions};
-
-use serde::{
-    ser::{
-        SerializeMap,
-        SerializeSeq,
-        SerializeStruct,
-        SerializeStructVariant,
-        SerializeTupleStruct,
-        SerializeTupleVariant,
-    },
-    Deserialize,
-    Serialize,
-};
-
-/// Type whose serialize and deserialize implementations assert that the (de)serializer
-/// is not human readable.
-#[derive(Deserialize)]
-struct Foo {
-    a: i32,
-    unit: Unit,
-    tuple: Tuple,
-    map: Map,
-    unit_variant: Bar,
-    tuple_variant: Bar,
-    struct_variant: Bar,
-    seq: Seq,
-}
-
-impl Serialize for Foo {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        assert!(!serializer.is_human_readable());
-
-        let mut state = serializer.serialize_struct("Foo", 7)?;
-        state.serialize_field("a", &self.a)?;
-        state.serialize_field("unit", &self.unit)?;
-        state.serialize_field("tuple", &self.tuple)?;
-        state.serialize_field("map", &self.map)?;
-        state.serialize_field("unit_variant", &self.unit_variant)?;
-        state.serialize_field("tuple_variant", &self.tuple_variant)?;
-        state.serialize_field("struct_variant", &self.struct_variant)?;
-        state.serialize_field("seq", &self.seq)?;
-        state.end()
-    }
-}
-
-#[derive(Deserialize)]
-enum Bar {
-    Unit,
-    Tuple(Unit),
-    Struct { a: Unit },
-}
-
-impl Serialize for Bar {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        assert!(!serializer.is_human_readable());
-        match self {
-            Self::Unit => serializer.serialize_unit_variant("Bar", 0, "Unit"),
-            Self::Tuple(t) => {
-                let mut state = serializer.serialize_tuple_variant("Bar", 1, "Tuple", 1)?;
-                state.serialize_field(t)?;
-                state.end()
-            }
-            Self::Struct { a } => {
-                let mut state = serializer.serialize_struct_variant("Foo", 2, "Struct", 1)?;
-                state.serialize_field("a", a)?;
-                state.end()
-            }
-        }
-    }
-}
-
-struct Unit;
-
-impl Serialize for Unit {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        assert!(!serializer.is_human_readable());
-        serializer.serialize_unit_struct("Unit")
-    }
-}
-
-impl<'de> Deserialize<'de> for Unit {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        assert!(!deserializer.is_human_readable());
-        Ok(Unit)
-    }
-}
-
-#[derive(Deserialize)]
-struct Tuple(Unit);
-
-impl Serialize for Tuple {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        assert!(!serializer.is_human_readable());
-        let mut state = serializer.serialize_tuple_struct("Tuple", 1)?;
-        state.serialize_field(&self.0)?;
-        state.end()
-    }
-}
-
-struct Map {
-    map: HashMap<String, Unit>,
-}
-
-impl Serialize for Map {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        assert!(!serializer.is_human_readable());
-
-        let mut state = serializer.serialize_map(Some(self.map.len()))?;
-        for (k, v) in self.map.iter() {
-            state.serialize_entry(k, &v)?;
-        }
-        state.end()
-    }
-}
-
-impl<'de> Deserialize<'de> for Map {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        assert!(!deserializer.is_human_readable());
-        let map = Deserialize::deserialize(deserializer)?;
-        Ok(Self { map })
-    }
-}
-
-struct Seq {
-    seq: Vec<Unit>,
-}
-
-impl Serialize for Seq {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        assert!(!serializer.is_human_readable());
-
-        let mut state = serializer.serialize_seq(Some(self.seq.len()))?;
-        for v in self.seq.iter() {
-            state.serialize_element(&v)?;
-        }
-        state.end()
-    }
-}
-
-impl<'de> Deserialize<'de> for Seq {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        assert!(!deserializer.is_human_readable());
-        let v = Vec::<Unit>::deserialize(deserializer)?;
-        Ok(Self { seq: v })
-    }
-}
-
-#[test]
-fn to_bson_with_options() {
-    #[allow(deprecated)]
-    let options = SerializerOptions::builder().human_readable(false).build();
-
-    let mut hm = HashMap::new();
-    hm.insert("ok".to_string(), Unit);
-    hm.insert("other".to_string(), Unit);
-    let f = Foo {
-        a: 5,
-        unit: Unit,
-        tuple: Tuple(Unit),
-        unit_variant: Bar::Unit,
-        tuple_variant: Bar::Tuple(Unit),
-        struct_variant: Bar::Struct { a: Unit },
-        map: Map { map: hm },
-        seq: Seq {
-            seq: vec![Unit, Unit],
-        },
-    };
-    bson::to_bson_with_options(&f, options).unwrap();
-}
-
-#[test]
-fn from_bson_with_options() {
-    #[allow(deprecated)]
-    let options = DeserializerOptions::builder().human_readable(false).build();
-
-    let doc = doc! {
-        "a": 5,
-        "unit": Bson::Null,
-        "tuple": [Bson::Null],
-        "unit_variant": { "Unit": Bson::Null },
-        "tuple_variant": { "Tuple": [Bson::Null] },
-        "struct_variant": { "Struct": { "a": Bson::Null } },
-        "map": { "a": Bson::Null, "b": Bson::Null },
-        "seq": [Bson::Null, Bson::Null],
-    };
-
-    let _: Foo = bson::from_bson_with_options(doc.into(), options).unwrap();
-}
diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index 44d55ac0..719f63c6 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -2,7 +2,6 @@
 #![allow(clippy::vec_init_then_push)]
 
 mod json;
-mod options;
 
 use pretty_assertions::assert_eq;
 use serde::{
@@ -19,7 +18,6 @@ use std::{
 };
 
 use bson::{
-    bson,
     doc,
     oid::ObjectId,
     spec::BinarySubtype,
@@ -28,7 +26,6 @@ use bson::{
     DateTime,
     Decimal128,
     Deserializer,
-    DeserializerOptions,
     Document,
     JavaScriptCodeWithScope,
     RawArray,
@@ -43,7 +40,6 @@ use bson::{
     RawJavaScriptCodeWithScopeRef,
     RawRegexRef,
     Regex,
-    SerializerOptions,
     Timestamp,
     Uuid,
 };
@@ -86,25 +82,6 @@ where
         description
     );
 
-    let non_human_readable_doc = bson::to_document_with_options(
-        &expected_value,
-        #[allow(deprecated)]
-        SerializerOptions::builder().human_readable(false).build(),
-    )
-    .expect(description);
-    assert_eq!(&non_human_readable_doc, expected_doc, "{}", description);
-    assert_eq!(
-        expected_value,
-        &bson::from_document_with_options::<T>(
-            non_human_readable_doc,
-            #[allow(deprecated)]
-            DeserializerOptions::builder().human_readable(false).build()
-        )
-        .expect(description),
-        "{}",
-        description
-    );
-
     assert_eq!(
         &bson::from_reader::<_, T>(expected_bytes.as_slice()).expect(description),
         expected_value,
@@ -1353,62 +1330,6 @@ fn hint_cleared() {
     assert_eq!(round_doc, doc! { "doc": doc_value, "binary": binary_value });
 }
 
-#[test]
-fn non_human_readable() {
-    let bytes = vec![1, 2, 3, 4];
-    let binary = RawBinaryRef {
-        bytes: &bytes,
-        subtype: BinarySubtype::BinaryOld,
-    };
-
-    let doc_bytes = bson::to_vec(&doc! { "a": "b", "array": [1, 2, 3] }).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();
-
-    #[derive(Debug, Deserialize, Serialize)]
-    struct Foo<'a> {
-        #[serde(borrow)]
-        binary: RawBinaryRef<'a>,
-        #[serde(borrow)]
-        doc: &'a RawDocument,
-        #[serde(borrow)]
-        arr: &'a RawArray,
-        oid: ObjectId,
-        uuid: Uuid,
-    }
-
-    let val = Foo {
-        binary,
-        doc,
-        arr,
-        oid,
-        uuid,
-    };
-
-    let human_readable = bson::to_bson(&val).unwrap();
-    let non_human_readable = bson::to_bson_with_options(
-        &val,
-        #[allow(deprecated)]
-        SerializerOptions::builder().human_readable(false).build(),
-    )
-    .unwrap();
-
-    let expected = bson!({
-        "binary": Binary { bytes: bytes.clone(), subtype: BinarySubtype::BinaryOld },
-        "doc": {
-            "a": "b",
-            "array": [1, 2, 3],
-        },
-        "arr": [1, 2, 3],
-        "oid": oid,
-        "uuid": uuid
-    });
-    assert_eq!(human_readable, expected);
-    assert_eq!(human_readable, non_human_readable);
-}
-
 #[test]
 fn invalid_length() {
     // This is a regression test for fuzzer-generated input (RUST-1240).
diff --git a/src/de/mod.rs b/src/de/mod.rs
index f9f6814c..68d943de 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -27,7 +27,7 @@ mod serde;
 
 pub use self::{
     error::{Error, Result},
-    serde::{Deserializer, DeserializerOptions},
+    serde::Deserializer,
 };
 
 use std::io::Read;
@@ -38,6 +38,7 @@ use crate::{
     spec::BinarySubtype,
 };
 
+#[rustfmt::skip]
 use ::serde::{
     de::{DeserializeOwned, Error as _},
     Deserialize,
@@ -84,9 +85,7 @@ impl Timestamp {
 /// The [`Deserializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`from_slice`] does not. This means that this function may deserialize differently
 /// than [`from_slice`] for types that change their deserialization logic depending on whether
-/// the format is human readable or not. To deserialize from [`Bson`] with a deserializer that
-/// presents itself as not human readable, use [`from_bson_with_options`] with
-/// [`DeserializerOptions::human_readable`] set to false.
+/// the format is human readable or not.
 pub fn from_bson<T>(bson: Bson) -> Result<T>
 where
     T: DeserializeOwned,
@@ -102,38 +101,12 @@ where
     }
 }
 
-/// Deserialize a `T` from the provided [`Bson`] value, configuring the underlying
-/// deserializer with the provided options.
-/// ```
-/// # use serde::Deserialize;
-/// # use bson::{bson, DeserializerOptions};
-/// #[derive(Debug, Deserialize, PartialEq)]
-/// struct MyData {
-///     a: String,
-/// }
-///
-/// let bson = bson!({ "a": "hello" });
-/// let options = DeserializerOptions::builder().human_readable(false).build();
-/// let data: MyData = bson::from_bson_with_options(bson, options)?;
-/// assert_eq!(data, MyData { a: "hello".to_string() });
-/// # Ok::<(), Box<dyn std::error::Error>>(())
-/// ```
-pub fn from_bson_with_options<T>(bson: Bson, options: DeserializerOptions) -> Result<T>
-where
-    T: DeserializeOwned,
-{
-    let de = Deserializer::new_with_options(bson, options);
-    Deserialize::deserialize(de)
-}
-
 /// Deserialize a `T` from the provided [`Document`].
 ///
 /// The [`Deserializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`from_slice`] does not. This means that this function may deserialize differently
 /// than [`from_slice`] for types that change their deserialization logic depending on whether
-/// the format is human readable or not. To deserialize from [`Document`] with a deserializer that
-/// presents itself as not human readable, use [`from_document_with_options`] with
-/// [`DeserializerOptions::human_readable`] set to false.
+/// the format is human readable or not.
 pub fn from_document<T>(doc: Document) -> Result<T>
 where
     T: DeserializeOwned,
@@ -141,30 +114,6 @@ where
     from_bson(Bson::Document(doc))
 }
 
-/// Deserialize a `T` from the provided [`Document`], configuring the underlying
-/// deserializer with the provided options.
-/// ```
-/// # use serde::Deserialize;
-/// # use bson::{doc, DeserializerOptions};
-/// #[derive(Debug, Deserialize, PartialEq)]
-/// struct MyData {
-///     a: String,
-/// }
-///
-/// let doc = doc! { "a": "hello" };
-/// let options = DeserializerOptions::builder().human_readable(false).build();
-/// let data: MyData = bson::from_document_with_options(doc, options)?;
-/// assert_eq!(data, MyData { a: "hello".to_string() });
-/// # Ok::<(), Box<dyn std::error::Error>>(())
-/// ```
-pub fn from_document_with_options<T>(doc: Document, options: DeserializerOptions) -> Result<T>
-where
-    T: DeserializeOwned,
-{
-    let de = Deserializer::new_with_options(Bson::Document(doc), options);
-    Deserialize::deserialize(de)
-}
-
 pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
     let mut buf = [0; 4];
     reader.read_exact(&mut buf)?;
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 69607bc6..6ec3e437 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -79,10 +79,9 @@ impl<'de> Deserializer<'de> {
                     }
                     Utf8LossyBson::JavaScriptCode(code) => visitor.visit_map(MapDeserializer::new(
                         doc! { "$code": code },
-                        #[allow(deprecated)]
-                        crate::DeserializerOptions::builder()
-                            .human_readable(false)
-                            .build(),
+                        crate::de::serde::DeserializerOptions {
+                            human_readable: Some(false),
+                        },
                     )),
                     Utf8LossyBson::JavaScriptCodeWithScope(jsc) => visitor.visit_map(
                         CodeWithScopeAccess::new(BsonCow::Owned(jsc), hint, self.options.clone()),
@@ -92,10 +91,9 @@ impl<'de> Deserializer<'de> {
                     }
                     Utf8LossyBson::Symbol(s) => visitor.visit_map(MapDeserializer::new(
                         doc! { "$symbol": s },
-                        #[allow(deprecated)]
-                        crate::DeserializerOptions::builder()
-                            .human_readable(false)
-                            .build(),
+                        crate::de::serde::DeserializerOptions {
+                            human_readable: Some(false),
+                        },
                     )),
                 };
             }
diff --git a/src/de/serde.rs b/src/de/serde.rs
index ecf35935..bba415a4 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -580,44 +580,13 @@ pub struct Deserializer {
     options: DeserializerOptions,
 }
 
-/// Options used to configure a [`Deserializer`]. These can also be passed into
-/// [`crate::from_bson_with_options`] and [`crate::from_document_with_options`].
+/// Options used to configure a [`Deserializer`].
 #[derive(Debug, Clone, Default)]
 #[non_exhaustive]
-pub struct DeserializerOptions {
+pub(crate) struct DeserializerOptions {
     /// Whether the [`Deserializer`] should present itself as human readable or not.
-    /// The default is true.
-    #[deprecated = "use bson::serde_helpers::HumanReadable"]
-    pub human_readable: Option<bool>,
-}
-
-impl DeserializerOptions {
-    /// Create a builder struct used to construct a [`DeserializerOptions`].
-    pub fn builder() -> DeserializerOptionsBuilder {
-        DeserializerOptionsBuilder {
-            options: Default::default(),
-        }
-    }
-}
-
-/// Builder used to construct a [`DeserializerOptions`].
-pub struct DeserializerOptionsBuilder {
-    options: DeserializerOptions,
-}
-
-impl DeserializerOptionsBuilder {
-    /// Set the value for [`DeserializerOptions::human_readable`].
-    #[deprecated = "use bson::serde_helpers::HumanReadable"]
-    #[allow(deprecated)]
-    pub fn human_readable(mut self, val: impl Into<Option<bool>>) -> Self {
-        self.options.human_readable = val.into();
-        self
-    }
-
-    /// Consume this builder and produce a [`DeserializerOptions`].
-    pub fn build(self) -> DeserializerOptions {
-        self.options
-    }
+    /// The default is true. For internal use only.
+    pub(crate) human_readable: Option<bool>,
 }
 
 impl Deserializer {
@@ -627,7 +596,7 @@ impl Deserializer {
     }
 
     /// Create a new [`Deserializer`] using the provided options.
-    pub fn new_with_options(value: Bson, options: DeserializerOptions) -> Self {
+    pub(crate) fn new_with_options(value: Bson, options: DeserializerOptions) -> Self {
         Deserializer {
             value: Some(value),
             options,
diff --git a/src/lib.rs b/src/lib.rs
index b7021b0f..5be35f0e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -289,16 +289,7 @@ pub use self::{
     binary::Binary,
     bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
-    de::{
-        from_bson,
-        from_bson_with_options,
-        from_document,
-        from_document_with_options,
-        from_reader,
-        from_slice,
-        Deserializer,
-        DeserializerOptions,
-    },
+    de::{from_bson, from_document, from_reader, from_slice, Deserializer},
     decimal128::Decimal128,
     raw::{
         RawArray,
@@ -313,16 +304,7 @@ pub use self::{
         RawJavaScriptCodeWithScopeRef,
         RawRegexRef,
     },
-    ser::{
-        to_bson,
-        to_bson_with_options,
-        to_document,
-        to_document_with_options,
-        to_raw_document_buf,
-        to_vec,
-        Serializer,
-        SerializerOptions,
-    },
+    ser::{to_bson, to_document, to_raw_document_buf, to_vec, Serializer},
     uuid::{Uuid, UuidRepresentation},
 };
 
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index 10fb8037..65f6c9b1 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -27,18 +27,21 @@ mod serde;
 
 pub use self::{
     error::{Error, Result},
-    serde::{Serializer, SerializerOptions},
+    serde::Serializer,
 };
 
 use std::io::Write;
 
+#[rustfmt::skip]
+use ::serde::{ser::Error as SerdeError, Serialize};
+
 use crate::{
     bson::{Bson, Document},
     de::MAX_BSON_SIZE,
+    ser::serde::SerializerOptions,
     spec::BinarySubtype,
     RawDocumentBuf,
 };
-use ::serde::{ser::Error as SerdeError, Serialize};
 
 pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
     buf.extend(&(s.len() as i32 + 1).to_le_bytes());
@@ -109,9 +112,7 @@ fn write_binary<W: Write>(mut writer: W, bytes: &[u8], subtype: BinarySubtype) -
 /// The [`Serializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`to_vec`] does not. This means that this function will produce different BSON than
 /// [`to_vec`] for types that change their serialization output depending on whether
-/// the format is human readable or not. To serialize to a [`Document`] with a serializer that
-/// presents itself as not human readable, use [`to_bson_with_options`] with
-/// [`SerializerOptions::human_readable`] set to false.
+/// the format is human readable or not.
 pub fn to_bson<T>(value: &T) -> Result<Bson>
 where
     T: Serialize + ?Sized,
@@ -125,23 +126,8 @@ where
     value.serialize(ser)
 }
 
-/// Encode a `T` into a [`Bson`] value, configuring the underlying serializer with the provided
-/// options.
-/// ```
-/// # use serde::Serialize;
-/// # use bson::{bson, SerializerOptions};
-/// #[derive(Debug, Serialize)]
-/// struct MyData {
-///     a: String,
-/// }
-///
-/// let data = MyData { a: "ok".to_string() };
-/// let options = SerializerOptions::builder().human_readable(false).build();
-/// let bson = bson::to_bson_with_options(&data, options)?;
-/// assert_eq!(bson, bson!({ "a": "ok" }));
-/// # Ok::<(), Box<dyn std::error::Error>>(())
-/// ```
-pub fn to_bson_with_options<T>(value: &T, options: SerializerOptions) -> Result<Bson>
+/// Internal-only method to serialize data to BSON with the given options.
+pub(crate) fn to_bson_with_options<T>(value: &T, options: SerializerOptions) -> Result<Bson>
 where
     T: Serialize + ?Sized,
 {
@@ -154,37 +140,12 @@ where
 /// The [`Serializer`] used by this function presents itself as human readable, whereas the
 /// one used in [`to_vec`] does not. This means that this function will produce different BSON than
 /// [`to_vec`] for types that change their serialization output depending on whether
-/// the format is human readable or not. To serialize to a [`Document`] with a serializer that
-/// presents itself as not human readable, use [`to_document_with_options`] with
-/// [`SerializerOptions::human_readable`] set to false.
+/// the format is human readable or not.
 pub fn to_document<T>(value: &T) -> Result<Document>
 where
     T: Serialize + ?Sized,
 {
-    to_document_with_options(value, Default::default())
-}
-
-/// Encode a `T` into a [`Document`], configuring the underlying serializer with the provided
-/// options.
-/// ```
-/// # use serde::Serialize;
-/// # use bson::{doc, SerializerOptions};
-/// #[derive(Debug, Serialize)]
-/// struct MyData {
-///     a: String,
-/// }
-///
-/// let data = MyData { a: "ok".to_string() };
-/// let options = SerializerOptions::builder().human_readable(false).build();
-/// let doc = bson::to_document_with_options(&data, options)?;
-/// assert_eq!(doc, doc! { "a": "ok" });
-/// # Ok::<(), Box<dyn std::error::Error>>(())
-/// ```
-pub fn to_document_with_options<T>(value: &T, options: SerializerOptions) -> Result<Document>
-where
-    T: Serialize + ?Sized,
-{
-    match to_bson_with_options(value, options)? {
+    match to_bson(value)? {
         Bson::Document(doc) => Ok(doc),
         bson => Err(Error::SerializationError {
             message: format!(
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index 469babee..053f1e93 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -114,40 +114,10 @@ pub struct Serializer {
 /// Options used to configure a [`Serializer`].
 #[derive(Debug, Clone, Default)]
 #[non_exhaustive]
-pub struct SerializerOptions {
+pub(crate) struct SerializerOptions {
     /// Whether the [`Serializer`] should present itself as human readable or not.
-    /// The default value is true.
-    #[deprecated = "use bson::serde_helpers::HumanReadable"]
-    pub human_readable: Option<bool>,
-}
-
-impl SerializerOptions {
-    /// Create a builder used to construct a new [`SerializerOptions`].
-    pub fn builder() -> SerializerOptionsBuilder {
-        SerializerOptionsBuilder {
-            options: Default::default(),
-        }
-    }
-}
-
-/// A builder used to construct new [`SerializerOptions`] structs.
-pub struct SerializerOptionsBuilder {
-    options: SerializerOptions,
-}
-
-impl SerializerOptionsBuilder {
-    /// Set the value for [`SerializerOptions::is_human_readable`].
-    #[deprecated = "use bson::serde_helpers::HumanReadable"]
-    #[allow(deprecated)]
-    pub fn human_readable(mut self, value: impl Into<Option<bool>>) -> Self {
-        self.options.human_readable = value.into();
-        self
-    }
-
-    /// Consume this builder and produce a [`SerializerOptions`].
-    pub fn build(self) -> SerializerOptions {
-        self.options
-    }
+    /// The default value is true. For internal use only.
+    pub(crate) human_readable: Option<bool>,
 }
 
 impl Serializer {
@@ -160,7 +130,7 @@ impl Serializer {
     }
 
     /// Construct a new [`Serializer`] configured with the provided [`SerializerOptions`].
-    pub fn new_with_options(options: SerializerOptions) -> Self {
+    pub(crate) fn new_with_options(options: SerializerOptions) -> Self {
         Serializer { options }
     }
 }
@@ -348,7 +318,6 @@ impl ser::Serializer for Serializer {
                     b
                 ))),
             },
-            #[allow(deprecated)]
             HUMAN_READABLE_NEWTYPE => {
                 self.options.human_readable = Some(true);
                 value.serialize(self)
@@ -452,7 +421,6 @@ impl ser::Serializer for Serializer {
         })
     }
 
-    #[allow(deprecated)]
     fn is_human_readable(&self) -> bool {
         self.options.human_readable.unwrap_or(true)
     }
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 56702b8e..98b2e00b 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -847,10 +847,8 @@ pub mod timestamp_as_u32 {
 }
 
 /// Wrapping a type in `HumanReadable` signals to the BSON serde integration that it and all
-/// recursively contained types should be handled as if
-/// [`SerializerOptions::human_readable`](crate::SerializerOptions::human_readable) and
-/// [`DeserializerOptions::human_readable`](crate::DeserializerOptions::human_readable) are
-/// set to `true`.
+/// recursively contained types should be serialized to and deserialized from their human-readable
+/// formats.
 #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct HumanReadable<T>(pub T);
 
diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs
index 54df88cf..817b8d88 100644
--- a/src/tests/serde_helpers.rs
+++ b/src/tests/serde_helpers.rs
@@ -78,6 +78,7 @@ fn human_readable_wrapper() {
     struct SubData {
         value: Detector,
     }
+
     let data = Data {
         first: HumanReadable(Detector::new()),
         outer: Detector::new(),
@@ -86,34 +87,19 @@ fn human_readable_wrapper() {
             value: Detector::new(),
         }),
     };
-    let bson = crate::to_bson_with_options(
-        &data,
-        #[allow(deprecated)]
-        crate::SerializerOptions::builder()
-            .human_readable(false)
-            .build(),
-    )
-    .unwrap();
-    assert_eq!(
-        bson.as_document().unwrap(),
-        &doc! {
-            "first": "human readable",
-            "outer": "not human readable",
-            "wrapped": "human readable",
-            "inner": {
-                "value": "human readable",
-            }
+    // use the raw serializer, which is non-human-readable
+    let data_doc = crate::to_raw_document_buf(&data).unwrap();
+    let expected_data_doc = rawdoc! {
+        "first": "human readable",
+        "outer": "not human readable",
+        "wrapped": "human readable",
+        "inner": {
+            "value": "human readable",
         }
-    );
-
-    let tripped: Data = crate::from_bson_with_options(
-        bson,
-        #[allow(deprecated)]
-        crate::DeserializerOptions::builder()
-            .human_readable(false)
-            .build(),
-    )
-    .unwrap();
+    };
+    assert_eq!(data_doc, expected_data_doc);
+
+    let tripped: Data = crate::from_slice(expected_data_doc.as_bytes()).unwrap();
     let expected = Data {
         first: HumanReadable(Detector {
             serialized_as: true,
@@ -135,10 +121,6 @@ fn human_readable_wrapper() {
         }),
     };
     assert_eq!(&tripped, &expected);
-
-    let bytes = crate::to_vec(&data).unwrap();
-    let raw_tripped: Data = crate::from_slice(&bytes).unwrap();
-    assert_eq!(&raw_tripped, &expected);
 }
 
 #[test]

From dff0e559c811bc6333d1a46e03ec70bbe9fc0735 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 19 May 2025 16:40:11 -0400
Subject: [PATCH 104/156] RUST-1380 Drop support for `uuid` 0.8 (#534)

---
 Cargo.lock             |  13 +---
 Cargo.toml             |   5 --
 README.md              |   1 -
 serde-tests/Cargo.lock |  15 +----
 serde-tests/Cargo.toml |   4 +-
 src/bson.rs            |   8 ---
 src/serde_helpers.rs   | 131 -----------------------------------------
 src/tests/serde.rs     |  76 ------------------------
 src/uuid/mod.rs        |  34 -----------
 src/uuid/test.rs       |  16 -----
 10 files changed, 5 insertions(+), 298 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index fb4cf2f1..8dd02413 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -142,8 +142,7 @@ dependencies = [
  "serde_with 1.14.0",
  "serde_with 3.12.0",
  "time",
- "uuid 0.8.2",
- "uuid 1.16.0",
+ "uuid",
 ]
 
 [[package]]
@@ -1139,16 +1138,6 @@ version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
-[[package]]
-name = "uuid"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
-dependencies = [
- "getrandom 0.2.16",
- "serde",
-]
-
 [[package]]
 name = "uuid"
 version = "1.16.0"
diff --git a/Cargo.toml b/Cargo.toml
index 2fbbcbd4..052ec07b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,10 +36,6 @@ exclude = [
 default = []
 # if enabled, include API for interfacing with chrono 0.4
 chrono-0_4 = ["chrono"]
-# if enabled, include API for interfacing with uuid 0.8
-# This is commented out because Cargo implicitly adds this feature since
-# uuid-0_8 is also an optional dependency.
-# uuid-0_8 = []
 # if enabled, include API for interfacing with uuid 1.x
 uuid-1 = []
 # if enabled, include API for interfacing with time 0.3
@@ -69,7 +65,6 @@ indexmap = "2.1.0"
 hex = "0.4.2"
 base64 = "0.22.1"
 once_cell = "1.5.1"
-uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true }
 uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
 serde_with = { version = "1.3.1", optional = true }
diff --git a/README.md b/README.md
index 6567e94d..43446159 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,6 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | Feature      | Description                                                                                                 | Extra dependencies | Default |
 | :----------- | :---------------------------------------------------------------------------------------------------------- | :----------------- | :------ |
 | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
-| `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.                  | n/a                | no      |
 | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
 | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.                  | n/a                | no      |
 | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
diff --git a/serde-tests/Cargo.lock b/serde-tests/Cargo.lock
index ff854ffd..3577fc13 100644
--- a/serde-tests/Cargo.lock
+++ b/serde-tests/Cargo.lock
@@ -88,8 +88,7 @@ dependencies = [
  "serde_json",
  "serde_with",
  "time 0.3.17",
- "uuid 0.8.2",
- "uuid 1.2.2",
+ "uuid",
 ]
 
 [[package]]
@@ -574,7 +573,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_with",
- "uuid 0.8.2",
+ "uuid",
 ]
 
 [[package]]
@@ -724,16 +723,6 @@ version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
-[[package]]
-name = "uuid"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
-dependencies = [
- "getrandom 0.2.8",
- "serde",
-]
-
 [[package]]
 name = "uuid"
 version = "1.2.2"
diff --git a/serde-tests/Cargo.toml b/serde-tests/Cargo.toml
index c129f428..61695e28 100644
--- a/serde-tests/Cargo.toml
+++ b/serde-tests/Cargo.toml
@@ -8,13 +8,13 @@ edition = "2018"
 default = []
 
 [dependencies]
-bson = { path = "..", features = ["uuid-0_8", "chrono-0_4", "serde_with"] }
+bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde_with"] }
 serde = { version = "1.0", features = ["derive"] }
 pretty_assertions = "0.6.1"
 hex = "0.4.2"
 serde_with = "1"
 chrono = "0.4"
-uuid = "0.8"
+uuid = "1"
 
 [dev-dependencies]
 serde_json = "1"
diff --git a/src/bson.rs b/src/bson.rs
index b112ac47..f0133567 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -414,14 +414,6 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for Bson {
     }
 }
 
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-impl From<uuid_0_8::Uuid> for Bson {
-    fn from(uuid: uuid_0_8::Uuid) -> Self {
-        Bson::Binary(uuid.into())
-    }
-}
-
 #[cfg(feature = "uuid-1")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
 impl From<uuid::Uuid> for Bson {
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 98b2e00b..04917f1c 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -83,30 +83,6 @@ pub use uuid_1_as_python_legacy_binary::{
     deserialize as deserialize_uuid_1_from_python_legacy_binary,
     serialize as serialize_uuid_1_as_python_legacy_binary,
 };
-#[cfg(feature = "uuid-0_8")]
-#[doc(inline)]
-pub use uuid_as_binary::{
-    deserialize as deserialize_uuid_from_binary,
-    serialize as serialize_uuid_as_binary,
-};
-#[cfg(feature = "uuid-0_8")]
-#[doc(inline)]
-pub use uuid_as_c_sharp_legacy_binary::{
-    deserialize as deserialize_uuid_from_c_sharp_legacy_binary,
-    serialize as serialize_uuid_as_c_sharp_legacy_binary,
-};
-#[cfg(feature = "uuid-0_8")]
-#[doc(inline)]
-pub use uuid_as_java_legacy_binary::{
-    deserialize as deserialize_uuid_from_java_legacy_binary,
-    serialize as serialize_uuid_as_java_legacy_binary,
-};
-#[cfg(feature = "uuid-0_8")]
-#[doc(inline)]
-pub use uuid_as_python_legacy_binary::{
-    deserialize as deserialize_uuid_from_python_legacy_binary,
-    serialize as serialize_uuid_as_python_legacy_binary,
-};
 
 /// Attempts to serialize a u32 as an i32. Errors if an exact conversion is not possible.
 pub fn serialize_u32_as_i32<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> {
@@ -527,29 +503,6 @@ macro_rules! as_binary_mod {
     };
 }
 
-/// Contains functions to serialize a [`uuid_0_8::Uuid`] as a [`crate::Binary`] and deserialize a
-/// [`uuid_0_8::Uuid`] from a [`crate::Binary`].
-///
-/// ```rust
-/// # #[cfg(feature = "uuid-0_8")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid_0_8::Uuid;
-/// use bson::serde_helpers::uuid_as_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_as_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-pub mod uuid_as_binary {
-    as_binary_mod!(cfg(feature = "uuid-0_8"), uuid_0_8::Uuid);
-}
-
 /// Contains functions to serialize a [`uuid::Uuid`] as a [`crate::Binary`] and deserialize a
 /// [`uuid::Uuid`] from a [`crate::Binary`].
 ///
@@ -603,34 +556,6 @@ macro_rules! as_legacy_binary_mod {
     };
 }
 
-/// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy
-/// Java driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the
-/// legacy Java driver format.
-///
-/// ```rust
-/// #[cfg(feature = "uuid-0_8")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid_0_8::Uuid;
-/// use bson::serde_helpers::uuid_as_java_legacy_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_as_java_legacy_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-pub mod uuid_as_java_legacy_binary {
-    as_legacy_binary_mod!(
-        cfg(feature = "uuid-0_8"),
-        uuid_0_8::Uuid,
-        UuidRepresentation::JavaLegacy
-    );
-}
-
 /// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy
 /// Java driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy
 /// Java driver format.
@@ -659,34 +584,6 @@ pub mod uuid_1_as_java_legacy_binary {
     );
 }
 
-/// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy Python
-/// driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the legacy
-/// Python driver format.
-///
-/// ```rust
-/// # #[cfg(feature = "uuid-0_8")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid_0_8::Uuid;
-/// use bson::serde_helpers::uuid_as_python_legacy_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_as_python_legacy_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-pub mod uuid_as_python_legacy_binary {
-    as_legacy_binary_mod!(
-        cfg(feature = "uuid-0_8"),
-        uuid_0_8::Uuid,
-        UuidRepresentation::PythonLegacy
-    );
-}
-
 /// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy Python
 /// driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy Python
 /// driver format.
@@ -715,34 +612,6 @@ pub mod uuid_1_as_python_legacy_binary {
     );
 }
 
-/// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy C#
-/// driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the legacy C#
-/// driver format.
-///
-/// ```rust
-/// # #[cfg(feature = "uuid-0_8")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid_0_8::Uuid;
-/// use bson::serde_helpers::uuid_as_c_sharp_legacy_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_as_c_sharp_legacy_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-pub mod uuid_as_c_sharp_legacy_binary {
-    as_legacy_binary_mod!(
-        cfg(feature = "uuid-0_8"),
-        uuid_0_8::Uuid,
-        UuidRepresentation::CSharpLegacy
-    );
-}
-
 /// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy C# driver
 /// UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy C# driver
 /// format.
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index cb49f9d1..f92d064d 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -554,54 +554,6 @@ fn test_de_db_pointer() {
     assert_eq!(foo.db_pointer, db_pointer.clone());
 }
 
-#[cfg(feature = "uuid-0_8")]
-#[test]
-fn test_serde_legacy_uuid_0_8() {
-    use uuid_0_8::Uuid;
-
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Serialize, Deserialize)]
-    struct Foo {
-        #[serde(with = "serde_helpers::uuid_as_java_legacy_binary")]
-        java_legacy: Uuid,
-        #[serde(with = "serde_helpers::uuid_as_python_legacy_binary")]
-        python_legacy: Uuid,
-        #[serde(with = "serde_helpers::uuid_as_c_sharp_legacy_binary")]
-        csharp_legacy: Uuid,
-    }
-    let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap();
-    let foo = Foo {
-        java_legacy: uuid,
-        python_legacy: uuid,
-        csharp_legacy: uuid,
-    };
-
-    let x = to_bson(&foo).unwrap();
-    assert_eq!(
-        x.as_document().unwrap(),
-        &doc! {
-            "java_legacy": Bson::Binary(Binary{
-                subtype:BinarySubtype::UuidOld,
-                bytes: hex::decode("7766554433221100FFEEDDCCBBAA9988").unwrap(),
-            }),
-            "python_legacy": Bson::Binary(Binary{
-                subtype:BinarySubtype::UuidOld,
-                bytes: hex::decode("00112233445566778899AABBCCDDEEFF").unwrap(),
-            }),
-            "csharp_legacy": Bson::Binary(Binary{
-                subtype:BinarySubtype::UuidOld,
-                bytes: hex::decode("33221100554477668899AABBCCDDEEFF").unwrap(),
-            })
-        }
-    );
-
-    let foo: Foo = from_bson(x).unwrap();
-    assert_eq!(foo.java_legacy, uuid);
-    assert_eq!(foo.python_legacy, uuid);
-    assert_eq!(foo.csharp_legacy, uuid);
-}
-
 #[cfg(feature = "uuid-1")]
 #[test]
 fn test_serde_legacy_uuid_1() {
@@ -988,34 +940,6 @@ fn test_i64_as_bson_datetime() {
     assert_eq!(a.now, now.timestamp_millis());
 }
 
-#[test]
-#[cfg(feature = "uuid-0_8")]
-fn test_uuid_0_8_helpers() {
-    use serde_helpers::uuid_as_binary;
-    use uuid_0_8::Uuid;
-
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Serialize, Deserialize)]
-    struct A {
-        #[serde(with = "uuid_as_binary")]
-        uuid: Uuid,
-    }
-
-    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
-    let a = A { uuid };
-    let doc = to_document(&a).unwrap();
-    match doc.get("uuid").unwrap() {
-        Bson::Binary(bin) => {
-            assert_eq!(bin.subtype, BinarySubtype::Uuid);
-            assert_eq!(bin.bytes, uuid.as_bytes());
-        }
-        _ => panic!("expected Bson::Binary"),
-    }
-    let a: A = from_document(doc).unwrap();
-    assert_eq!(a.uuid, uuid);
-}
-
 #[test]
 #[cfg(feature = "uuid-1")]
 fn test_uuid_1_helpers() {
diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs
index cfb7120e..ca939050 100644
--- a/src/uuid/mod.rs
+++ b/src/uuid/mod.rs
@@ -71,9 +71,6 @@
 //! # };
 //! ```
 //!
-//! For backwards compatibility, a `uuid-0_8` feature flag can be enabled, which provides the same
-//! API for interoperation with version 0.8 of the `uuid` crate.
-//!
 //! ## The `serde_with-3` feature flag
 //!
 //! The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for
@@ -214,22 +211,6 @@ impl Default for Uuid {
     }
 }
 
-#[cfg(feature = "uuid-0_8")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))]
-impl Uuid {
-    /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
-    /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
-    pub fn from_uuid_0_8(uuid: uuid_0_8::Uuid) -> Self {
-        Self::from_external_uuid(uuid::Uuid::from_u128(uuid.as_u128()))
-    }
-
-    /// Convert this [`Uuid`] to a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
-    /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
-    pub fn to_uuid_0_8(self) -> uuid_0_8::Uuid {
-        uuid_0_8::Uuid::from_bytes(self.uuid.into_bytes())
-    }
-}
-
 #[cfg(feature = "uuid-1")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
 impl Uuid {
@@ -312,20 +293,6 @@ impl From<Uuid> for Bson {
     }
 }
 
-#[cfg(feature = "uuid-0_8")]
-impl From<uuid_0_8::Uuid> for Uuid {
-    fn from(u: uuid_0_8::Uuid) -> Self {
-        Self::from_uuid_0_8(u)
-    }
-}
-
-#[cfg(feature = "uuid-0_8")]
-impl From<Uuid> for uuid_0_8::Uuid {
-    fn from(s: Uuid) -> Self {
-        s.to_uuid_0_8()
-    }
-}
-
 #[cfg(feature = "uuid-1")]
 impl From<uuid::Uuid> for Uuid {
     fn from(u: uuid::Uuid) -> Self {
@@ -535,7 +502,6 @@ macro_rules! trait_impls {
         }
     };
 }
-trait_impls!(feature = "uuid-0_8", uuid_0_8::Uuid);
 trait_impls!(feature = "uuid-1", uuid::Uuid);
 
 /// Errors that can occur during [`Uuid`] construction and generation.
diff --git a/src/uuid/test.rs b/src/uuid/test.rs
index 5118270a..29c0048c 100644
--- a/src/uuid/test.rs
+++ b/src/uuid/test.rs
@@ -240,22 +240,6 @@ fn test_binary_to_uuid_python_legacy_rep() {
     );
 }
 
-#[cfg(feature = "uuid-0_8")]
-#[test]
-fn interop_0_8() {
-    let uuid = crate::Uuid::new();
-    let uuid_uuid = uuid.to_uuid_0_8();
-    assert_eq!(uuid.to_string(), uuid_uuid.to_string());
-    assert_eq!(&uuid.bytes(), uuid_uuid.as_bytes());
-
-    let back: crate::Uuid = uuid_uuid.into();
-    assert_eq!(back, uuid);
-
-    let d_bson = doc! { "uuid": uuid };
-    let d_uuid = doc! { "uuid": uuid_uuid };
-    assert_eq!(d_bson, d_uuid);
-}
-
 #[cfg(feature = "uuid-1")]
 #[test]
 fn interop_1() {

From ba7e703e1980af0e22abf3f18c9d0e66eeadb3fb Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 20 May 2025 16:24:43 -0400
Subject: [PATCH 105/156] RUST-2217: update version to 3.0 (#537)

---
 Cargo.lock | 2 +-
 Cargo.toml | 2 +-
 README.md  | 2 +-
 src/lib.rs | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8dd02413..49459e66 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -118,7 +118,7 @@ dependencies = [
 
 [[package]]
 name = "bson"
-version = "2.14.0"
+version = "3.0.0"
 dependencies = [
  "ahash",
  "assert_matches",
diff --git a/Cargo.toml b/Cargo.toml
index 052ec07b..04e21afc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bson"
-version = "2.14.0"
+version = "3.0.0"
 authors = [
     "Y. T. Chung <zonyitoo@gmail.com>",
     "Kevin Yeh <kevinyeah@utexas.edu>",
diff --git a/README.md b/README.md
index 43446159..b08e9399 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ This crate is available on [crates.io](https://crates.io/crates/bson). To use it
 
 ```toml
 [dependencies]
-bson = "2.14.0"
+bson = "3.0.0"
 ```
 
 Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your
diff --git a/src/lib.rs b/src/lib.rs
index 5be35f0e..18ac481d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,7 +51,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! bson = "2.14.0"
+//! bson = "3.0.0"
 //! ```
 //!
 //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in

From fe284454c2e55d65f64c3dc067c0ab196be643db Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 27 May 2025 12:01:37 -0400
Subject: [PATCH 106/156] minor: remove incorrect note about Decimal128 panic
 (#539)

---
 src/bson.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/bson.rs b/src/bson.rs
index f0133567..cf7aa3d3 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -461,8 +461,6 @@ impl From<Bson> for Value {
 
 impl Bson {
     /// Converts the Bson value into its [relaxed extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-    ///
-    /// Note: If this method is called on a case which contains a `Decimal128` value, it will panic.
     pub fn into_relaxed_extjson(self) -> Value {
         match self {
             Bson::Double(v) if v.is_nan() => {

From 8755bfb23776be7bcd3f81322821aa54eff481ff Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 28 May 2025 09:31:27 -0400
Subject: [PATCH 107/156] RUST-2215 Ergonomics for HumanReadable (#540)

---
 src/serde_helpers.rs | 60 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)

diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 04917f1c..a8877bdf 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -1,6 +1,11 @@
 //! Collection of helper functions for serializing to and deserializing from BSON using Serde
 
-use std::{convert::TryFrom, marker::PhantomData, result::Result};
+use std::{
+    convert::TryFrom,
+    marker::PhantomData,
+    ops::{Deref, DerefMut},
+    result::Result,
+};
 
 use serde::{de::Visitor, ser, Deserialize, Serialize, Serializer};
 
@@ -718,7 +723,8 @@ pub mod timestamp_as_u32 {
 /// Wrapping a type in `HumanReadable` signals to the BSON serde integration that it and all
 /// recursively contained types should be serialized to and deserialized from their human-readable
 /// formats.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
+#[repr(transparent)]
 pub struct HumanReadable<T>(pub T);
 
 pub(crate) const HUMAN_READABLE_NEWTYPE: &str = "$__bson_private_human_readable";
@@ -754,6 +760,56 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for HumanReadable<T> {
     }
 }
 
+impl<T: std::fmt::Display> std::fmt::Display for HumanReadable<T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl<T> From<T> for HumanReadable<T> {
+    fn from(value: T) -> Self {
+        Self(value)
+    }
+}
+
+impl<T> Deref for HumanReadable<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for HumanReadable<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T, R> AsRef<R> for HumanReadable<T>
+where
+    R: ?Sized,
+    <HumanReadable<T> as Deref>::Target: AsRef<R>,
+{
+    fn as_ref(&self) -> &R {
+        self.deref().as_ref()
+    }
+}
+
+impl<T, R: ?Sized> AsMut<R> for HumanReadable<T>
+where
+    <HumanReadable<T> as Deref>::Target: AsMut<R>,
+{
+    fn as_mut(&mut self) -> &mut R {
+        self.deref_mut().as_mut()
+    }
+}
+
+// One could imagine passthrough Borrow impls; however, it turns out that can't be made to work
+// because of the existing base library impl of Borrow<T> for T will conflict despite that not
+// actually being possible to construct (https://github.com/rust-lang/rust/issues/50237).  So,
+// sadly, Borrow impls for HumanReadable are deliberately omitted :(
+
 /// Wrapper type for deserializing BSON bytes with invalid UTF-8 sequences.
 ///
 /// Any invalid UTF-8 strings contained in the wrapped type will be replaced with the Unicode

From 07477063876650d6b695765118624ac8e05ed120 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Wed, 28 May 2025 15:55:41 -0400
Subject: [PATCH 108/156]  RUST-577 Bump dependencies with dependabot (#542)

---
 .github/dependabot.yml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 .github/dependabot.yml

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..990b6909
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,17 @@
+version: 2
+updates:
+  - package-ecosystem: cargo
+    directory: /
+    schedule:
+      interval: weekly
+    # Only bump to the latest version compatible with the dependency's version
+    # in Cargo.toml. This is the equivalent of running `cargo update`.
+    versioning-strategy: lockfile-only
+    # Update all dependencies in a single PR.
+    groups:
+      rust-dependencies:
+        patterns:
+          - "*"
+    # Include transitive dependencies.
+    allow:
+      - dependency-type: all

From 999583278eaa319fab6f365a670d1624306b9418 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 29 May 2025 11:24:36 -0400
Subject: [PATCH 109/156] Bump the rust-dependencies group with 8 updates
 (#543)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 49459e66..eb03dd13 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -159,9 +159,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.21"
+version = "1.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
+checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
 dependencies = [
  "shlex",
 ]
@@ -394,9 +394,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.11"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
 dependencies = [
  "libc",
  "windows-sys",
@@ -866,9 +866,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
 
 [[package]]
 name = "rusty-fork"
@@ -1059,9 +1059,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 
 [[package]]
 name = "tempfile"
-version = "3.19.1"
+version = "3.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
 dependencies = [
  "fastrand",
  "getrandom 0.3.2",
@@ -1140,9 +1140,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
 name = "uuid"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
 dependencies = [
  "getrandom 0.3.2",
  "js-sys",
@@ -1291,9 +1291,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-core"
-version = "0.61.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
 dependencies = [
  "windows-implement",
  "windows-interface",
@@ -1332,18 +1332,18 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
 dependencies = [
  "windows-link",
 ]

From 20da9b1bf84a33e287d847c9db1d92da551997ef Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 30 May 2025 13:42:29 -0400
Subject: [PATCH 110/156] RUST-2169 Clean up and future-proof features (#544)

---
 Cargo.lock                | 78 ++++-----------------------------------
 Cargo.toml                | 17 +++------
 README.md                 |  4 +-
 serde-tests/Cargo.lock    | 53 +++++++++++++++-----------
 serde-tests/Cargo.toml    |  4 +-
 src/bson.rs               |  5 +--
 src/datetime.rs           | 71 +++--------------------------------
 src/de/mod.rs             |  3 --
 src/document.rs           |  7 +---
 src/lib.rs                |  9 ++++-
 src/tests/modules/bson.rs |  1 -
 src/uuid/mod.rs           | 30 ++-------------
 12 files changed, 66 insertions(+), 216 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index eb03dd13..0bf7321a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -139,8 +139,7 @@ dependencies = [
  "serde_bytes",
  "serde_json",
  "serde_path_to_error",
- "serde_with 1.14.0",
- "serde_with 3.12.0",
+ "serde_with",
  "time",
  "uuid",
 ]
@@ -294,38 +293,14 @@ dependencies = [
  "syn 1.0.109",
 ]
 
-[[package]]
-name = "darling"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
-dependencies = [
- "darling_core 0.13.4",
- "darling_macro 0.13.4",
-]
-
 [[package]]
 name = "darling"
 version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
 dependencies = [
- "darling_core 0.20.11",
- "darling_macro 0.20.11",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim 0.10.0",
- "syn 1.0.109",
+ "darling_core",
+ "darling_macro",
 ]
 
 [[package]]
@@ -338,28 +313,17 @@ dependencies = [
  "ident_case",
  "proc-macro2",
  "quote",
- "strsim 0.11.1",
+ "strsim",
  "syn 2.0.101",
 ]
 
-[[package]]
-name = "darling_macro"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
-dependencies = [
- "darling_core 0.13.4",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "darling_macro"
 version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
 dependencies = [
- "darling_core 0.20.11",
+ "darling_core",
  "quote",
  "syn 2.0.101",
 ]
@@ -959,16 +923,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "serde_with"
-version = "1.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
-dependencies = [
- "serde",
- "serde_with_macros 1.5.2",
-]
-
 [[package]]
 name = "serde_with"
 version = "3.12.0"
@@ -983,29 +937,17 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "serde_with_macros 3.12.0",
+ "serde_with_macros",
  "time",
 ]
 
-[[package]]
-name = "serde_with_macros"
-version = "1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
-dependencies = [
- "darling 0.13.4",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "serde_with_macros"
 version = "3.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
 dependencies = [
- "darling 0.20.11",
+ "darling",
  "proc-macro2",
  "quote",
  "syn 2.0.101",
@@ -1017,12 +959,6 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
 [[package]]
 name = "strsim"
 version = "0.11.1"
diff --git a/Cargo.toml b/Cargo.toml
index 04e21afc..44c2eb37 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,24 +33,18 @@ exclude = [
 ]
 
 [features]
-default = []
+default = ["compat-3-0-0"]
+compat-3-0-0 = []
 # if enabled, include API for interfacing with chrono 0.4
-chrono-0_4 = ["chrono"]
+chrono-0_4 = ["dep:chrono"]
 # if enabled, include API for interfacing with uuid 1.x
 uuid-1 = []
 # if enabled, include API for interfacing with time 0.3
 time-0_3 = []
-# If enabled, implement Hash/Eq for Bson and Document
-hashable = []
-# If enabled, the maximum document size will be increased from the MongoDB cap
-# of 16 MB to the BSON spec maximum size of 2^31 - 1
-uncapped_max_size = []
 serde_path_to_error = ["dep:serde_path_to_error"]
 # if enabled, include serde_with interop.
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
-# it's commented out here because Cargo implicitly adds a feature flag for
-# all optional dependencies.
-# serde_with
+serde_with-3 = ["dep:serde_with"]
 
 [lib]
 name = "bson"
@@ -67,8 +61,7 @@ base64 = "0.22.1"
 once_cell = "1.5.1"
 uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
-serde_with = { version = "1.3.1", optional = true }
-serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true }
+serde_with = { version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
 serde_path_to_error = { version = "0.1.16", optional = true }
diff --git a/README.md b/README.md
index b08e9399..bbbd6c86 100644
--- a/README.md
+++ b/README.md
@@ -50,11 +50,9 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
 | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
 | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.                  | n/a                | no      |
-| `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | serde_path_to_error  | no |
-| `hashable`   | Implement `core::hash::Hash` and `std::cmp::Eq` on `Bson` and `Document`.                  | n/a                | no      |
-| `uncapped_max_size` | Increase the maximum document size from the MongoDB cap of 16 MB to the BSON spec maximum size of 2^31 - 1 bytes. | n/a | no |
+| `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
 
 ## Overview of the BSON Format
 
diff --git a/serde-tests/Cargo.lock b/serde-tests/Cargo.lock
index 3577fc13..13eba014 100644
--- a/serde-tests/Cargo.lock
+++ b/serde-tests/Cargo.lock
@@ -70,7 +70,7 @@ dependencies = [
 
 [[package]]
 name = "bson"
-version = "2.14.0"
+version = "3.0.0"
 dependencies = [
  "ahash",
  "base64 0.22.1",
@@ -125,6 +125,7 @@ dependencies = [
  "js-sys",
  "num-integer",
  "num-traits",
+ "serde",
  "time 0.1.45",
  "wasm-bindgen",
  "winapi",
@@ -202,9 +203,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.13.4"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -212,27 +213,27 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.13.4"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
  "strsim",
- "syn 1.0.104",
+ "syn 2.0.101",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.13.4"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
 dependencies = [
  "darling_core",
  "quote",
- "syn 1.0.104",
+ "syn 2.0.101",
 ]
 
 [[package]]
@@ -342,6 +343,7 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
 dependencies = [
  "autocfg",
  "hashbrown 0.12.3",
+ "serde",
 ]
 
 [[package]]
@@ -352,6 +354,7 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
 dependencies = [
  "equivalent",
  "hashbrown 0.14.3",
+ "serde",
 ]
 
 [[package]]
@@ -553,9 +556,9 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
 
 [[package]]
 name = "serde"
-version = "1.0.148"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
 dependencies = [
  "serde_derive",
 ]
@@ -587,13 +590,13 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.148"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.104",
+ "syn 2.0.101",
 ]
 
 [[package]]
@@ -610,31 +613,39 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "1.14.0"
+version = "3.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
+checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20"
 dependencies = [
+ "base64 0.22.1",
+ "chrono",
+ "hex",
+ "indexmap 1.9.2",
+ "indexmap 2.1.0",
  "serde",
+ "serde_derive",
+ "serde_json",
  "serde_with_macros",
+ "time 0.3.17",
 ]
 
 [[package]]
 name = "serde_with_macros"
-version = "1.5.2"
+version = "3.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
+checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2"
 dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 1.0.104",
+ "syn 2.0.101",
 ]
 
 [[package]]
 name = "strsim"
-version = "0.10.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
diff --git a/serde-tests/Cargo.toml b/serde-tests/Cargo.toml
index 61695e28..99236d60 100644
--- a/serde-tests/Cargo.toml
+++ b/serde-tests/Cargo.toml
@@ -8,11 +8,11 @@ edition = "2018"
 default = []
 
 [dependencies]
-bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde_with"] }
+bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde_with-3"] }
 serde = { version = "1.0", features = ["derive"] }
 pretty_assertions = "0.6.1"
 hex = "0.4.2"
-serde_with = "1"
+serde_with = "3"
 chrono = "0.4"
 uuid = "1"
 
diff --git a/src/bson.rs b/src/bson.rs
index cf7aa3d3..9b5f0ca4 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -90,7 +90,6 @@ pub enum Bson {
 /// Alias for `Vec<Bson>`.
 pub type Array = Vec<Bson>;
 
-#[cfg(feature = "hashable")]
 impl Hash for Bson {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         match self {
@@ -125,7 +124,6 @@ impl Hash for Bson {
     }
 }
 
-#[cfg(feature = "hashable")]
 impl Eq for Bson {}
 
 impl Display for Bson {
@@ -1154,8 +1152,7 @@ impl Display for Regex {
 }
 
 /// Represents a BSON code with scope value.
-#[derive(Debug, Clone, PartialEq)]
-#[cfg_attr(feature = "hashable", derive(Eq, Hash))]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct JavaScriptCodeWithScope {
     /// The JavaScript code.
     pub code: String,
diff --git a/src/datetime.rs b/src/datetime.rs
index f5c8e04e..c14c37ad 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -16,15 +16,10 @@ use time::format_description::well_known::Rfc3339;
 #[cfg(feature = "chrono-0_4")]
 use chrono::{LocalResult, TimeZone, Utc};
 #[cfg(all(
-    any(feature = "serde_with", feature = "serde_with-3"),
+    feature = "serde_with-3",
     any(feature = "chrono-0_4", feature = "time-0_3")
 ))]
 use serde::{Deserialize, Deserializer, Serialize};
-#[cfg(all(
-    feature = "serde_with",
-    any(feature = "chrono-0_4", feature = "time-0_3")
-))]
-use serde_with::{DeserializeAs, SerializeAs};
 
 /// Struct representing a BSON datetime.
 /// Note: BSON datetimes have millisecond precision.
@@ -158,7 +153,7 @@ use serde_with::{DeserializeAs, SerializeAs};
 /// use serde::{Deserialize, Serialize};
 /// use bson::doc;
 ///
-/// #[serde_with_3::serde_as]
+/// #[serde_with::serde_as]
 /// #[derive(Deserialize, Serialize, PartialEq, Debug)]
 /// struct Foo {
 ///   /// Serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization
@@ -479,39 +474,12 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
     }
 }
 
-#[cfg(all(feature = "chrono-0_4", feature = "serde_with"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "serde_with"))))]
-impl<'de> DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateTime {
-    fn deserialize_as<D>(deserializer: D) -> std::result::Result<chrono::DateTime<Utc>, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let dt = DateTime::deserialize(deserializer)?;
-        Ok(dt.to_chrono())
-    }
-}
-
-#[cfg(all(feature = "chrono-0_4", feature = "serde_with"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))]
-impl SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
-    fn serialize_as<S>(
-        source: &chrono::DateTime<Utc>,
-        serializer: S,
-    ) -> std::result::Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        let dt = DateTime::from_chrono(*source);
-        dt.serialize(serializer)
-    }
-}
-
 #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
 #[cfg_attr(
     docsrs,
     doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3")))
 )]
-impl<'de> serde_with_3::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateTime {
+impl<'de> serde_with::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateTime {
     fn deserialize_as<D>(deserializer: D) -> std::result::Result<chrono::DateTime<Utc>, D::Error>
     where
         D: Deserializer<'de>,
@@ -523,7 +491,7 @@ impl<'de> serde_with_3::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::Dat
 
 #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
 #[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))]
-impl serde_with_3::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
+impl serde_with::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
     fn serialize_as<S>(
         source: &chrono::DateTime<Utc>,
         serializer: S,
@@ -552,36 +520,9 @@ impl From<time::OffsetDateTime> for crate::DateTime {
     }
 }
 
-#[cfg(all(feature = "time-0_3", feature = "serde_with"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with"))))]
-impl<'de> DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime {
-    fn deserialize_as<D>(deserializer: D) -> std::result::Result<time::OffsetDateTime, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let dt = DateTime::deserialize(deserializer)?;
-        Ok(dt.to_time_0_3())
-    }
-}
-
-#[cfg(all(feature = "time-0_3", feature = "serde_with"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))]
-impl SerializeAs<time::OffsetDateTime> for crate::DateTime {
-    fn serialize_as<S>(
-        source: &time::OffsetDateTime,
-        serializer: S,
-    ) -> std::result::Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        let dt = DateTime::from_time_0_3(*source);
-        dt.serialize(serializer)
-    }
-}
-
 #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
 #[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with-3"))))]
-impl<'de> serde_with_3::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime {
+impl<'de> serde_with::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime {
     fn deserialize_as<D>(deserializer: D) -> std::result::Result<time::OffsetDateTime, D::Error>
     where
         D: Deserializer<'de>,
@@ -593,7 +534,7 @@ impl<'de> serde_with_3::DeserializeAs<'de, time::OffsetDateTime> for crate::Date
 
 #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
 #[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))]
-impl serde_with_3::SerializeAs<time::OffsetDateTime> for crate::DateTime {
+impl serde_with::SerializeAs<time::OffsetDateTime> for crate::DateTime {
     fn serialize_as<S>(
         source: &time::OffsetDateTime,
         serializer: S,
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 68d943de..09ea1f0d 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -48,9 +48,6 @@ pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor};
 
 pub(crate) use self::raw::Deserializer as RawDeserializer;
 
-#[cfg(not(feature = "uncapped_max_size"))]
-pub(crate) const MAX_BSON_SIZE: i32 = 16 * 1024 * 1024;
-#[cfg(feature = "uncapped_max_size")]
 pub(crate) const MAX_BSON_SIZE: i32 = i32::MAX;
 pub(crate) const MIN_BSON_DOCUMENT_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
 pub(crate) const MIN_BSON_STRING_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
diff --git a/src/document.rs b/src/document.rs
index ed8e8101..27779d2f 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -1,10 +1,9 @@
 //! A BSON document represented as an associative HashMap with insertion ordering.
 
-#[cfg(feature = "hashable")]
-use std::hash::Hash;
 use std::{
     error,
     fmt::{self, Debug, Display, Formatter},
+    hash::Hash,
     io::{Read, Write},
     iter::{Extend, FromIterator, IntoIterator},
     ops::Index,
@@ -58,8 +57,7 @@ impl Display for ValueAccessError {
 impl error::Error for ValueAccessError {}
 
 /// A BSON document represented as an associative HashMap with insertion ordering.
-#[derive(Clone, PartialEq)]
-#[cfg_attr(feature = "hashable", derive(Eq))]
+#[derive(Clone, PartialEq, Eq)]
 pub struct Document {
     inner: IndexMap<String, Bson, RandomState>,
 }
@@ -70,7 +68,6 @@ impl Default for Document {
     }
 }
 
-#[cfg(feature = "hashable")]
 impl Hash for Document {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         let mut entries = Vec::from_iter(&self.inner);
diff --git a/src/lib.rs b/src/lib.rs
index 18ac481d..93884fba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -62,12 +62,11 @@
 //! | Feature      | Description                                                                                          | Default |
 //! |:-------------|:-----------------------------------------------------------------------------------------------------|:--------|
 //! | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.       | no      |
-//! | `uuid-0_8`   | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API.           | no      |
 //! | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API.           | no      |
 //! | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.           | no      |
-//! | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for [`DateTime`] and [`Uuid`]. | no      |
 //! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for [`DateTime`] and [`Uuid`]. | no      |
 //! | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | no |
+//! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
 //!
 //! ## BSON values
 //!
@@ -330,3 +329,9 @@ pub mod uuid;
 
 #[cfg(test)]
 mod tests;
+
+#[cfg(not(feature = "compat-3-0-0"))]
+compile_error!(
+    "The feature 'compat-3-0-0' must be enabled to ensure forward compatibility with future \
+     versions of this crate."
+);
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 1e4f7b1d..c3ccabeb 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -488,7 +488,6 @@ fn debug_print() {
     assert_eq!(format!("{:#?}", doc), pretty_print);
 }
 
-#[cfg(feature = "hashable")]
 #[test]
 fn test_hashable() {
     let mut map = std::collections::HashMap::new();
diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs
index ca939050..c6bf3aef 100644
--- a/src/uuid/mod.rs
+++ b/src/uuid/mod.rs
@@ -85,7 +85,7 @@
 //! use serde::{Deserialize, Serialize};
 //! use bson::doc;
 //!
-//! #[serde_with_3::serde_as]
+//! #[serde_with::serde_as]
 //! #[derive(Deserialize, Serialize, PartialEq, Debug)]
 //! struct Foo {
 //!   /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization
@@ -453,33 +453,9 @@ macro_rules! trait_impls {
             }
         }
 
-        #[cfg(all($feat, feature = "serde_with"))]
-        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with"))))]
-        impl<'de> serde_with::DeserializeAs<'de, $u> for crate::Uuid {
-            fn deserialize_as<D>(deserializer: D) -> std::result::Result<$u, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                let uuid = Uuid::deserialize(deserializer)?;
-                Ok(uuid.into())
-            }
-        }
-
-        #[cfg(all($feat, feature = "serde_with"))]
-        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with"))))]
-        impl serde_with::SerializeAs<$u> for crate::Uuid {
-            fn serialize_as<S>(source: &$u, serializer: S) -> std::result::Result<S::Ok, S::Error>
-            where
-                S: serde::Serializer,
-            {
-                let uuid = Uuid::from(*source);
-                uuid.serialize(serializer)
-            }
-        }
-
         #[cfg(all($feat, feature = "serde_with-3"))]
         #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))]
-        impl<'de> serde_with_3::DeserializeAs<'de, $u> for crate::Uuid {
+        impl<'de> serde_with::DeserializeAs<'de, $u> for crate::Uuid {
             fn deserialize_as<D>(deserializer: D) -> std::result::Result<$u, D::Error>
             where
                 D: serde::Deserializer<'de>,
@@ -491,7 +467,7 @@ macro_rules! trait_impls {
 
         #[cfg(all($feat, feature = "serde_with-3"))]
         #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))]
-        impl serde_with_3::SerializeAs<$u> for crate::Uuid {
+        impl serde_with::SerializeAs<$u> for crate::Uuid {
             fn serialize_as<S>(source: &$u, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where
                 S: serde::Serializer,

From aa95676ea338d0a5c514becaf83917a3e54af7e8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Jun 2025 10:06:48 -0400
Subject: [PATCH 111/156] Bump cc from 1.2.24 to 1.2.25 in the
 rust-dependencies group (#545)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 0bf7321a..cf5216a3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -158,9 +158,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.24"
+version = "1.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
+checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
 dependencies = [
  "shlex",
 ]

From c038fb569472936d26fee3b27bf5257470c3cc45 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 2 Jun 2025 13:25:12 -0400
Subject: [PATCH 112/156] RUST-1887 Convince append to be more accepting (#541)

---
 src/raw/array_buf.rs    |  10 ++--
 src/raw/document_buf.rs | 100 ++++++++++++++++++++++++++++++++--------
 src/raw/mod.rs          |   2 +-
 3 files changed, 86 insertions(+), 26 deletions(-)

diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index 57dc6a5e..d9969d99 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -8,14 +8,14 @@ use serde::{Deserialize, Serialize};
 
 use crate::{RawArray, RawBsonRef, RawDocumentBuf};
 
-use super::{bson::RawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter};
+use super::{document_buf::BindRawBsonRef, 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
 /// [`RawDocumentBuf`] or as a field in a [`Deserialize`] struct.
 ///
-/// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`] value that borrows from
-/// the original document without making any additional allocations.
+/// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`](crate::raw::RawBson)
+/// value that borrows from the original document without making any additional allocations.
 /// ```
 /// # use bson::raw::Error;
 /// use bson::raw::RawArrayBuf;
@@ -92,7 +92,7 @@ impl RawArrayBuf {
     /// assert!(iter.next().is_none());
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn push(&mut self, value: impl Into<RawBson>) {
+    pub fn push(&mut self, value: impl BindRawBsonRef) {
         self.inner.append(self.len.to_string(), value);
         self.len += 1;
     }
@@ -148,7 +148,7 @@ impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> {
     }
 }
 
-impl<T: Into<RawBson>> FromIterator<T> for RawArrayBuf {
+impl<T: BindRawBsonRef> FromIterator<T> for RawArrayBuf {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
         let mut array_buf = RawArrayBuf::new();
         for item in iter {
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 6f7e73c3..7a3e0dca 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -189,43 +189,38 @@ impl RawDocumentBuf {
     ///
     /// If the provided key contains an interior null byte, this method will panic.
     ///
+    /// Values can be any type that can be converted to either borrowed or owned raw bson data; see
+    /// the documentation for [BindRawBsonRef] for more details.
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{doc, raw::RawDocumentBuf};
+    /// use bson::{doc, raw::{RawBsonRef, RawDocumentBuf}};
     ///
     /// let mut doc = RawDocumentBuf::new();
+    /// // `&str` and `i32` both convert to `RawBsonRef`
     /// doc.append("a string", "some string");
     /// doc.append("an integer", 12_i32);
     ///
     /// let mut subdoc = RawDocumentBuf::new();
     /// subdoc.append("a key", true);
-    /// doc.append("a document", subdoc);
+    /// doc.append("a borrowed document", &subdoc);
+    /// doc.append("an owned document", subdoc);
     ///
     /// let expected = doc! {
     ///     "a string": "some string",
     ///     "an integer": 12_i32,
-    ///     "a document": { "a key": true },
+    ///     "a borrowed document": { "a key": true },
+    ///     "an owned document": { "a key": true },
     /// };
     ///
     /// assert_eq!(doc.to_document()?, expected);
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn append(&mut self, key: impl AsRef<str>, value: impl Into<RawBson>) {
-        let value = value.into();
-        self.append_ref(key, value.as_raw_bson_ref())
-    }
-
-    /// 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.
-    pub fn append_ref<'a>(&mut self, key: impl AsRef<str>, value: impl Into<RawBsonRef<'a>>) {
-        raw_writer::RawWriter::new(&mut self.data)
-            .append(key.as_ref(), value.into())
-            .expect("key should not contain interior null byte")
+    pub fn append(&mut self, key: impl AsRef<str>, value: impl BindRawBsonRef) {
+        value.bind(|value_ref| {
+            raw_writer::RawWriter::new(&mut self.data)
+                .append(key.as_ref(), value_ref)
+                .expect("key should not contain interior null byte")
+        })
     }
 
     /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error
@@ -325,7 +320,7 @@ impl Borrow<RawDocument> for RawDocumentBuf {
     }
 }
 
-impl<S: AsRef<str>, T: Into<RawBson>> FromIterator<(S, T)> for RawDocumentBuf {
+impl<S: AsRef<str>, T: BindRawBsonRef> FromIterator<(S, T)> for RawDocumentBuf {
     fn from_iter<I: IntoIterator<Item = (S, T)>>(iter: I) -> Self {
         let mut buf = RawDocumentBuf::new();
         for (k, v) in iter {
@@ -334,3 +329,68 @@ impl<S: AsRef<str>, T: Into<RawBson>> FromIterator<(S, T)> for RawDocumentBuf {
         buf
     }
 }
+
+/// Types that can be consumed to produce raw bson references valid for a limited lifetime.
+/// Conceptually a union between `T: Into<RawBson>` and `T: Into<RawBsonRef>`; if your type
+/// implements `Into<RawBsonRef>` it will automatically implement this, but if it only
+/// implements `Into<RawBson>` it will need to manually define the trivial impl.
+pub trait BindRawBsonRef {
+    fn bind<F, R>(self, f: F) -> R
+    where
+        F: for<'a> FnOnce(RawBsonRef<'a>) -> R;
+}
+
+impl<'a, T: Into<RawBsonRef<'a>>> BindRawBsonRef for T {
+    fn bind<F, R>(self, f: F) -> R
+    where
+        F: for<'b> FnOnce(RawBsonRef<'b>) -> R,
+    {
+        f(self.into())
+    }
+}
+
+impl BindRawBsonRef for RawBson {
+    fn bind<F, R>(self, f: F) -> R
+    where
+        F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
+    {
+        f(self.as_raw_bson_ref())
+    }
+}
+
+impl BindRawBsonRef for &RawBson {
+    fn bind<F, R>(self, f: F) -> R
+    where
+        F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
+    {
+        f(self.as_raw_bson_ref())
+    }
+}
+
+macro_rules! raw_bson_from_impls {
+    ($($t:ty),+$(,)?) => {
+        $(
+            impl BindRawBsonRef for $t {
+                fn bind<F, R>(self, f: F) -> R
+                where
+                    F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
+                {
+                    let tmp: RawBson = self.into();
+                    f(tmp.as_raw_bson_ref())
+                }
+            }
+        )+
+    };
+}
+
+raw_bson_from_impls! {
+    &crate::binary::Vector,
+    crate::Binary,
+    crate::DbPointer,
+    super::RawArrayBuf,
+    RawDocumentBuf,
+    super::RawJavaScriptCodeWithScope,
+    crate::Regex,
+    String,
+    crate::binary::Vector,
+}
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index 175bca64..d6bcc2c9 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -140,7 +140,7 @@ pub use self::{
         RawRegexRef,
     },
     document::RawDocument,
-    document_buf::RawDocumentBuf,
+    document_buf::{BindRawBsonRef, RawDocumentBuf},
     error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
     iter::{RawElement, RawIter},
 };

From cc56d1ca318f92cb7f41dfb364c33a4c8138ff2e Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 3 Jun 2025 10:34:51 -0400
Subject: [PATCH 113/156] RUST-2213 Properly handle NaNs in fuzz testing (#547)

---
 fuzz/fuzz_targets/serialization.rs | 38 ++++++++++++++++++++----------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/fuzz/fuzz_targets/serialization.rs b/fuzz/fuzz_targets/serialization.rs
index e5ba621d..ea6b13e5 100644
--- a/fuzz/fuzz_targets/serialization.rs
+++ b/fuzz/fuzz_targets/serialization.rs
@@ -11,25 +11,37 @@ fn compare_docs(doc1: &Document, doc2: &Document) -> bool {
         return false;
     }
     for (key, value) in doc1 {
-        if !doc2.contains_key(key) {
+        if let Some(val2) = doc2.get(key) {
+            if !compare_values(value, val2) {
+                return false;
+            }
+        } else {
             return false;
         }
-        if let Some(val2) = doc2.get(key) {
-            match (value, val2) {
-                (Bson::Double(d1), Bson::Double(d2)) => {
-                    if (!d1.is_nan() || !d2.is_nan()) && d1 != d2 {
-                        return false;
-                    }
-                }
-                (v1, v2) => {
-                    if v1 != v2 {
-                        return false;
-                    }
+    }
+    true
+}
+
+fn compare_values(val1: &Bson, val2: &Bson) -> bool {
+    match (val1, val2) {
+        (Bson::Double(d1), Bson::Double(d2)) => (d1.is_nan() && d2.is_nan()) || d1 == d2,
+        (Bson::Document(doc1), Bson::Document(doc2)) => compare_docs(doc1, doc2),
+        (Bson::Array(arr1), Bson::Array(arr2)) => {
+            if arr1.len() != arr2.len() {
+                return false;
+            }
+            for (subval1, subval2) in std::iter::zip(arr1, arr2) {
+                if !compare_values(subval1, subval2) {
+                    return false;
                 }
             }
+            true
         }
+        (Bson::JavaScriptCodeWithScope(jsc1), Bson::JavaScriptCodeWithScope(jsc2)) => {
+            jsc1.code == jsc2.code && compare_docs(&jsc1.scope, &jsc2.scope)
+        }
+        (v1, v2) => v1 == v2,
     }
-    true
 }
 
 fuzz_target!(|input: &[u8]| {

From f2c07cd429e6c54fa4e9769358ae70c44868c42a Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 3 Jun 2025 14:35:10 -0400
Subject: [PATCH 114/156] RUST-1798 use simd to optimize utf8 validation (#548)

Co-authored-by: Liyixin95 <601947961@qq.com>
---
 Cargo.lock       | 7 +++++++
 Cargo.toml       | 1 +
 src/raw/error.rs | 6 ++----
 src/raw/mod.rs   | 2 +-
 4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index cf5216a3..4881faa0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -140,6 +140,7 @@ dependencies = [
  "serde_json",
  "serde_path_to_error",
  "serde_with",
+ "simdutf8",
  "time",
  "uuid",
 ]
@@ -959,6 +960,12 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
diff --git a/Cargo.toml b/Cargo.toml
index 44c2eb37..b2eaf819 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,6 +65,7 @@ serde_with = { version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
 bitvec = "1.0.1"
 serde_path_to_error = { version = "0.1.16", optional = true }
+simdutf8 = "0.1.5"
 
 [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
 js-sys = "0.3"
diff --git a/src/raw/error.rs b/src/raw/error.rs
index e6ab8fbc..a9912d90 100644
--- a/src/raw/error.rs
+++ b/src/raw/error.rs
@@ -1,5 +1,3 @@
-use std::str::Utf8Error;
-
 use crate::spec::ElementType;
 
 /// An error that occurs when attempting to parse raw BSON bytes.
@@ -44,7 +42,7 @@ pub enum ErrorKind {
     MalformedValue { message: String },
 
     /// Improper UTF-8 bytes were found when proper UTF-8 was expected.
-    Utf8EncodingError(Utf8Error),
+    Utf8EncodingError,
 }
 
 impl std::fmt::Display for Error {
@@ -60,7 +58,7 @@ impl std::fmt::Display for Error {
             ErrorKind::MalformedValue { message } => {
                 write!(f, "{}malformed value: {:?}", prefix, message)
             }
-            ErrorKind::Utf8EncodingError(e) => write!(f, "{}utf-8 encoding error: {}", prefix, e),
+            ErrorKind::Utf8EncodingError => write!(f, "{}utf-8 encoding error", prefix),
         }
     }
 }
diff --git a/src/raw/mod.rs b/src/raw/mod.rs
index d6bcc2c9..4e1dd0d6 100644
--- a/src/raw/mod.rs
+++ b/src/raw/mod.rs
@@ -271,7 +271,7 @@ fn read_lenencode(buf: &[u8]) -> Result<&str> {
 }
 
 fn try_to_str(data: &[u8]) -> Result<&str> {
-    std::str::from_utf8(data).map_err(|e| Error::new(ErrorKind::Utf8EncodingError(e)))
+    simdutf8::basic::from_utf8(data).map_err(|_| Error::new(ErrorKind::Utf8EncodingError))
 }
 
 fn usize_try_from_i32(i: i32) -> Result<usize> {

From 84e43af32148b5a605915b0653e8386431969aae Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Tue, 3 Jun 2025 14:40:49 -0400
Subject: [PATCH 115/156] RUST-1960 Make large-dates time feature optional
 (#546)

---
 Cargo.toml               | 4 +++-
 README.md                | 3 ++-
 src/datetime.rs          | 8 ++++++++
 src/lib.rs               | 1 +
 src/tests/datetime.rs    | 1 +
 src/tests/spec/corpus.rs | 5 +++++
 6 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index b2eaf819..cc7ada60 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,6 +37,8 @@ default = ["compat-3-0-0"]
 compat-3-0-0 = []
 # if enabled, include API for interfacing with chrono 0.4
 chrono-0_4 = ["dep:chrono"]
+# enable the large-dates feature for the time crate
+large_dates = ["time/large-dates"]
 # if enabled, include API for interfacing with uuid 1.x
 uuid-1 = []
 # if enabled, include API for interfacing with time 0.3
@@ -62,7 +64,7 @@ once_cell = "1.5.1"
 uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
 serde_with = { version = "3.1.0", optional = true }
-time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] }
+time = { version = "0.3.9", features = ["formatting", "parsing", "macros"] }
 bitvec = "1.0.1"
 serde_path_to_error = { version = "0.1.16", optional = true }
 simdutf8 = "0.1.5"
diff --git a/README.md b/README.md
index bbbd6c86..fffa70bf 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,8 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.                  | n/a                | no      |
 | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
 | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | serde_path_to_error  | no |
-| `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
+| `compat-3-0-0` | Required for future compatibility if default features are disabled. | n/a | no |
+| `large_dates` | Increase the supported year range for some `bson::DateTime` utilities from +/-9,999 (inclusive) to +/-999,999 (inclusive). Note that enabling this feature can impact performance and introduce parsing ambiguities. | n/a | no |
 
 ## Overview of the BSON Format
 
diff --git a/src/datetime.rs b/src/datetime.rs
index c14c37ad..eca1522b 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -174,6 +174,14 @@ use serde::{Deserialize, Deserializer, Serialize};
 /// # }
 /// # Ok::<(), Box<dyn std::error::Error>>(())
 /// ```
+///
+/// ## Large Dates
+/// The range of dates supported by `DateTime` is defined by [`DateTime::MIN`] and
+/// [`DateTime::MAX`]. However, some utilities for constructing and converting `DateTimes`, such as
+/// interop with the [`time::OffsetDateTime`] type and with RFC 3339 strings, are bounded by the
+/// [`time`] crate's supported date range. The `large_dates` feature can be enabled to expand this
+/// range, which enables the
+/// [`large-dates` feature for `time`](https://docs.rs/time/latest/time/#feature-flags).
 #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
 pub struct DateTime(i64);
 
diff --git a/src/lib.rs b/src/lib.rs
index 93884fba..7906e58e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -67,6 +67,7 @@
 //! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for [`DateTime`] and [`Uuid`]. | no      |
 //! | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | no |
 //! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
+//! | `large_dates` | Increase the supported year range for some `bson::DateTime` utilities from +/-9,999 (inclusive) to +/-999,999 (inclusive). Note that enabling this feature can impact performance and introduce parsing ambiguities. | no |
 //!
 //! ## BSON values
 //!
diff --git a/src/tests/datetime.rs b/src/tests/datetime.rs
index 56bba311..e69c24c8 100644
--- a/src/tests/datetime.rs
+++ b/src/tests/datetime.rs
@@ -37,6 +37,7 @@ fn datetime_to_rfc3339() {
 }
 
 #[test]
+#[cfg(feature = "large_dates")]
 fn invalid_datetime_to_rfc3339() {
     assert!(crate::DateTime::MAX.try_to_rfc3339_string().is_err());
 }
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 796d1a70..93bc3220 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -100,6 +100,11 @@ where
 fn run_test(test: TestFile) {
     let _guard = LOCK.run_concurrently();
     for valid in test.valid {
+        #[cfg(not(feature = "large_dates"))]
+        if valid.description == "Y10K" {
+            continue;
+        }
+
         let description = format!("{}: {}", test.description, valid.description);
 
         let canonical_bson = hex::decode(&valid.canonical_bson).expect(&description);

From 9844287767d33ccdefee24d01d9620b6e8cd51ee Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Tue, 3 Jun 2025 16:17:17 -0400
Subject: [PATCH 116/156] Rename `mod.rs` files (#549)

---
 src/{de/mod.rs => de.rs}                 | 0
 src/{extjson/mod.rs => extjson.rs}       | 0
 src/{raw/mod.rs => raw.rs}               | 0
 src/raw/{test/mod.rs => test.rs}         | 0
 src/{ser/mod.rs => ser.rs}               | 0
 src/ser/{raw/mod.rs => raw.rs}           | 0
 src/{tests/mod.rs => tests.rs}           | 0
 src/tests/{modules/mod.rs => modules.rs} | 0
 src/tests/{spec/mod.rs => spec.rs}       | 0
 src/{uuid/mod.rs => uuid.rs}             | 0
 10 files changed, 0 insertions(+), 0 deletions(-)
 rename src/{de/mod.rs => de.rs} (100%)
 rename src/{extjson/mod.rs => extjson.rs} (100%)
 rename src/{raw/mod.rs => raw.rs} (100%)
 rename src/raw/{test/mod.rs => test.rs} (100%)
 rename src/{ser/mod.rs => ser.rs} (100%)
 rename src/ser/{raw/mod.rs => raw.rs} (100%)
 rename src/{tests/mod.rs => tests.rs} (100%)
 rename src/tests/{modules/mod.rs => modules.rs} (100%)
 rename src/tests/{spec/mod.rs => spec.rs} (100%)
 rename src/{uuid/mod.rs => uuid.rs} (100%)

diff --git a/src/de/mod.rs b/src/de.rs
similarity index 100%
rename from src/de/mod.rs
rename to src/de.rs
diff --git a/src/extjson/mod.rs b/src/extjson.rs
similarity index 100%
rename from src/extjson/mod.rs
rename to src/extjson.rs
diff --git a/src/raw/mod.rs b/src/raw.rs
similarity index 100%
rename from src/raw/mod.rs
rename to src/raw.rs
diff --git a/src/raw/test/mod.rs b/src/raw/test.rs
similarity index 100%
rename from src/raw/test/mod.rs
rename to src/raw/test.rs
diff --git a/src/ser/mod.rs b/src/ser.rs
similarity index 100%
rename from src/ser/mod.rs
rename to src/ser.rs
diff --git a/src/ser/raw/mod.rs b/src/ser/raw.rs
similarity index 100%
rename from src/ser/raw/mod.rs
rename to src/ser/raw.rs
diff --git a/src/tests/mod.rs b/src/tests.rs
similarity index 100%
rename from src/tests/mod.rs
rename to src/tests.rs
diff --git a/src/tests/modules/mod.rs b/src/tests/modules.rs
similarity index 100%
rename from src/tests/modules/mod.rs
rename to src/tests/modules.rs
diff --git a/src/tests/spec/mod.rs b/src/tests/spec.rs
similarity index 100%
rename from src/tests/spec/mod.rs
rename to src/tests/spec.rs
diff --git a/src/uuid/mod.rs b/src/uuid.rs
similarity index 100%
rename from src/uuid/mod.rs
rename to src/uuid.rs

From d1aaa8ec06fc6412d5ad705b05ddc0258c812d68 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 5 Jun 2025 11:48:01 -0400
Subject: [PATCH 117/156] RUST-1406 Add crate-wide error types, convert value
 access errors (#551)

---
 Cargo.lock                    |  21 ++
 Cargo.toml                    |   1 +
 serde-tests/Cargo.lock        |  28 +++
 src/document.rs               | 449 ++++++++++++++++++++--------------
 src/error.rs                  | 110 +++++++++
 src/lib.rs                    |   1 +
 src/raw.rs                    |   2 +-
 src/raw/array.rs              |  67 +++--
 src/raw/document.rs           | 148 ++++++-----
 src/raw/error.rs              |  64 -----
 src/raw/test.rs               |  10 +-
 src/tests/modules/document.rs |  95 +++----
 12 files changed, 567 insertions(+), 429 deletions(-)
 create mode 100644 src/error.rs

diff --git a/Cargo.lock b/Cargo.lock
index 4881faa0..2c7968d7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -141,6 +141,7 @@ dependencies = [
  "serde_path_to_error",
  "serde_with",
  "simdutf8",
+ "thiserror",
  "time",
  "uuid",
 ]
@@ -1022,6 +1023,26 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
 [[package]]
 name = "time"
 version = "0.3.41"
diff --git a/Cargo.toml b/Cargo.toml
index cc7ada60..c772468c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,6 +65,7 @@ uuid = { version = "1.1.2", features = ["serde", "v4"] }
 serde_bytes = "0.11.5"
 serde_with = { version = "3.1.0", optional = true }
 time = { version = "0.3.9", features = ["formatting", "parsing", "macros"] }
+thiserror = "2"
 bitvec = "1.0.1"
 serde_path_to_error = { version = "0.1.16", optional = true }
 simdutf8 = "0.1.5"
diff --git a/serde-tests/Cargo.lock b/serde-tests/Cargo.lock
index 13eba014..ea41fa86 100644
--- a/serde-tests/Cargo.lock
+++ b/serde-tests/Cargo.lock
@@ -87,6 +87,8 @@ dependencies = [
  "serde_bytes",
  "serde_json",
  "serde_with",
+ "simdutf8",
+ "thiserror",
  "time 0.3.17",
  "uuid",
 ]
@@ -641,6 +643,12 @@ dependencies = [
  "syn 2.0.101",
 ]
 
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
@@ -684,6 +692,26 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
 [[package]]
 name = "time"
 version = "0.1.45"
diff --git a/src/document.rs b/src/document.rs
index 27779d2f..c4911e4a 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -1,7 +1,6 @@
 //! A BSON document represented as an associative HashMap with insertion ordering.
 
 use std::{
-    error,
     fmt::{self, Debug, Display, Formatter},
     hash::Hash,
     io::{Read, Write},
@@ -14,48 +13,13 @@ use indexmap::IndexMap;
 
 use crate::{
     bson::{Array, Bson, Timestamp},
+    error::{Error, Result},
     oid::ObjectId,
-    spec::BinarySubtype,
+    spec::{BinarySubtype, ElementType},
     Binary,
     Decimal128,
 };
 
-/// Error to indicate that either a value was empty or it contained an unexpected
-/// type, for use with the direct getters.
-#[derive(PartialEq, Clone)]
-#[non_exhaustive]
-pub enum ValueAccessError {
-    /// Cannot find the expected field with the specified key
-    NotPresent,
-    /// Found a Bson value with the specified key, but not with the expected type
-    UnexpectedType,
-}
-
-/// Result of accessing Bson value
-pub type ValueAccessResult<T> = Result<T, ValueAccessError>;
-
-impl Debug for ValueAccessError {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
-        match *self {
-            ValueAccessError::NotPresent => write!(f, "ValueAccessError: field is not present"),
-            ValueAccessError::UnexpectedType => {
-                write!(f, "ValueAccessError: field does not have the expected type")
-            }
-        }
-    }
-}
-
-impl Display for ValueAccessError {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
-        match *self {
-            ValueAccessError::NotPresent => write!(f, "field is not present"),
-            ValueAccessError::UnexpectedType => write!(f, "field does not have the expected type"),
-        }
-    }
-}
-
-impl error::Error for ValueAccessError {}
-
 /// A BSON document represented as an associative HashMap with insertion ordering.
 #[derive(Clone, PartialEq, Eq)]
 pub struct Document {
@@ -246,300 +210,432 @@ impl<'a> Iterator for IterMut<'a> {
 }
 
 impl Document {
-    /// Creates a new empty Document.
+    /// Returns a new empty document.
     pub fn new() -> Document {
         Document {
             inner: IndexMap::default(),
         }
     }
 
-    /// Gets an iterator over the entries of the map.
+    /// Returns an iterator over the contents of the document.
     pub fn iter(&self) -> Iter {
         self.into_iter()
     }
 
-    /// Gets an iterator over pairs of keys and mutable values.
+    /// Returns an iterator over mutable references to the contents of the document.
     pub fn iter_mut(&mut self) -> IterMut {
         IterMut {
             inner: self.inner.iter_mut(),
         }
     }
 
-    /// Clears the document, removing all values.
+    /// Removes all values from the document.
     pub fn clear(&mut self) {
         self.inner.clear();
     }
 
-    /// Returns a reference to the Bson corresponding to the key.
+    /// Returns a reference to the [`Bson`] value that corresponds to the given key, if present.
     pub fn get(&self, key: impl AsRef<str>) -> Option<&Bson> {
         self.inner.get(key.as_ref())
     }
 
-    /// Gets a mutable reference to the Bson corresponding to the key
+    /// Returns a mutable reference to the [`Bson`] value that corresponds to the given key, if
+    /// present.
     pub fn get_mut(&mut self, key: impl AsRef<str>) -> Option<&mut Bson> {
         self.inner.get_mut(key.as_ref())
     }
 
-    /// Get a floating point value for this key if it exists and has
-    /// the correct type.
-    pub fn get_f64(&self, key: impl AsRef<str>) -> ValueAccessResult<f64> {
+    /// Returns the value for the given key if one is present and is of type
+    /// [`ElementType::Double`].
+    pub fn get_f64(&self, key: impl AsRef<str>) -> Result<f64> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::Double(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Double,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to a floating point value for this key if it exists and has
-    /// the correct type.
-    pub fn get_f64_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut f64> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Double`].
+    pub fn get_f64_mut(&mut self, key: impl AsRef<str>) -> Result<&mut f64> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Double(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Double,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a reference to a Decimal128 value for key, if it exists.
-    pub fn get_decimal128(&self, key: impl AsRef<str>) -> ValueAccessResult<&Decimal128> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Decimal128`].
+    pub fn get_decimal128(&self, key: impl AsRef<str>) -> Result<&Decimal128> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(Bson::Decimal128(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Decimal128,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to a Decimal128 value for key, if it exists.
-    pub fn get_decimal128_mut(
-        &mut self,
-        key: impl AsRef<str>,
-    ) -> ValueAccessResult<&mut Decimal128> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Decimal128`].
+    pub fn get_decimal128_mut(&mut self, key: impl AsRef<str>) -> Result<&mut Decimal128> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Decimal128(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Decimal128,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a string slice this key if it exists and has the correct type.
-    pub fn get_str(&self, key: impl AsRef<str>) -> ValueAccessResult<&str> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::String`].
+    pub fn get_str(&self, key: impl AsRef<str>) -> Result<&str> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(Bson::String(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::String,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable string slice this key if it exists and has the correct type.
-    pub fn get_str_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut str> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::String`].
+    pub fn get_str_mut(&mut self, key: impl AsRef<str>) -> Result<&mut str> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::String(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::String,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a reference to an array for this key if it exists and has
-    /// the correct type.
-    pub fn get_array(&self, key: impl AsRef<str>) -> ValueAccessResult<&Array> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Array`].
+    pub fn get_array(&self, key: impl AsRef<str>) -> Result<&Array> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(Bson::Array(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Array,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to an array for this key if it exists and has
-    /// the correct type.
-    pub fn get_array_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut Array> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Array`].
+    pub fn get_array_mut(&mut self, key: impl AsRef<str>) -> Result<&mut Array> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Array(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Array,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a reference to a document for this key if it exists and has
-    /// the correct type.
-    pub fn get_document(&self, key: impl AsRef<str>) -> ValueAccessResult<&Document> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::EmbeddedDocument`].
+    pub fn get_document(&self, key: impl AsRef<str>) -> Result<&Document> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(Bson::Document(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::EmbeddedDocument,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to a document for this key if it exists and has
-    /// the correct type.
-    pub fn get_document_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut Document> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::EmbeddedDocument`].
+    pub fn get_document_mut(&mut self, key: impl AsRef<str>) -> Result<&mut Document> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Document(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::EmbeddedDocument,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a bool value for this key if it exists and has the correct type.
-    pub fn get_bool(&self, key: impl AsRef<str>) -> ValueAccessResult<bool> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Boolean`].
+    pub fn get_bool(&self, key: impl AsRef<str>) -> Result<bool> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::Boolean(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Boolean,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to a bool value for this key if it exists and has the correct type.
-    pub fn get_bool_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut bool> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Boolean`].
+    pub fn get_bool_mut(&mut self, key: impl AsRef<str>) -> Result<&mut bool> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Boolean(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Boolean,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Returns wether this key has a null value
-    pub fn is_null(&self, key: impl AsRef<str>) -> bool {
-        self.get(key) == Some(&Bson::Null)
+    /// Returns [`Bson::Null`] if the given key corresponds to a [`Bson::Null`] value.
+    pub fn get_null(&self, key: impl AsRef<str>) -> Result<Bson> {
+        let key = key.as_ref();
+        match self.get(key) {
+            Some(&Bson::Null) => Ok(Bson::Null),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Null,
+            )),
+            None => Err(Error::value_access_not_present(key)),
+        }
     }
 
-    /// Get an i32 value for this key if it exists and has the correct type.
-    pub fn get_i32(&self, key: impl AsRef<str>) -> ValueAccessResult<i32> {
+    /// Returns the value for the given key if one is present and is of type [`ElementType::Int32`].
+    pub fn get_i32(&self, key: impl AsRef<str>) -> Result<i32> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::Int32(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Int32,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to an i32 value for this key if it exists and has the correct type.
-    pub fn get_i32_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut i32> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Int32`].
+    pub fn get_i32_mut(&mut self, key: impl AsRef<str>) -> Result<&mut i32> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Int32(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Int32,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get an i64 value for this key if it exists and has the correct type.
-    pub fn get_i64(&self, key: impl AsRef<str>) -> ValueAccessResult<i64> {
+    /// Returns the value for the given key if one is present and is of type [`ElementType::Int64`].
+    pub fn get_i64(&self, key: impl AsRef<str>) -> Result<i64> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::Int64(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Int64,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to an i64 value for this key if it exists and has the correct type.
-    pub fn get_i64_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut i64> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Int64`].
+    pub fn get_i64_mut(&mut self, key: impl AsRef<str>) -> Result<&mut i64> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Int64(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Int64,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a time stamp value for this key if it exists and has the correct type.
-    pub fn get_timestamp(&self, key: impl AsRef<str>) -> ValueAccessResult<Timestamp> {
+    /// Returns the value for the given key if one is present and is of type
+    /// [`ElementType::Timestamp`].
+    pub fn get_timestamp(&self, key: impl AsRef<str>) -> Result<Timestamp> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::Timestamp(timestamp)) => Ok(timestamp),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Timestamp,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to a time stamp value for this key if it exists and has the correct
-    /// type.
-    pub fn get_timestamp_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut Timestamp> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Timestamp`].
+    pub fn get_timestamp_mut(&mut self, key: impl AsRef<str>) -> Result<&mut Timestamp> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Timestamp(ref mut timestamp)) => Ok(timestamp),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Timestamp,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a reference to a generic binary value for this key if it exists and has the correct
-    /// type.
-    pub fn get_binary_generic(&self, key: impl AsRef<str>) -> ValueAccessResult<&Vec<u8>> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Binary`] with binary subtype [`BinarySubtype::Generic`].
+    pub fn get_binary_generic(&self, key: impl AsRef<str>) -> Result<&Vec<u8>> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::Binary(Binary {
                 subtype: BinarySubtype::Generic,
                 ref bytes,
             })) => Ok(bytes),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Binary,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference generic binary value for this key if it exists and has the correct
-    /// type.
-    pub fn get_binary_generic_mut(
-        &mut self,
-        key: impl AsRef<str>,
-    ) -> ValueAccessResult<&mut Vec<u8>> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::Binary`] with binary subtype [`BinarySubtype::Generic`].
+    pub fn get_binary_generic_mut(&mut self, key: impl AsRef<str>) -> Result<&mut Vec<u8>> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::Binary(Binary {
                 subtype: BinarySubtype::Generic,
                 ref mut bytes,
             })) => Ok(bytes),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::Binary,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get an object id value for this key if it exists and has the correct type.
-    pub fn get_object_id(&self, key: impl AsRef<str>) -> ValueAccessResult<ObjectId> {
+    /// Returns the value for the given key if one is present and is of type
+    /// [`ElementType::ObjectId`].
+    pub fn get_object_id(&self, key: impl AsRef<str>) -> Result<ObjectId> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(&Bson::ObjectId(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::ObjectId,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to an object id value for this key if it exists and has the correct
-    /// type.
-    pub fn get_object_id_mut(&mut self, key: impl AsRef<str>) -> ValueAccessResult<&mut ObjectId> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::ObjectId`].
+    pub fn get_object_id_mut(&mut self, key: impl AsRef<str>) -> Result<&mut ObjectId> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::ObjectId(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::ObjectId,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a reference to a UTC datetime value for this key if it exists and has the correct type.
-    pub fn get_datetime(&self, key: impl AsRef<str>) -> ValueAccessResult<&crate::DateTime> {
+    /// Returns a reference to the value for the given key if one is present and is of type
+    /// [`ElementType::DateTime`].
+    pub fn get_datetime(&self, key: impl AsRef<str>) -> Result<&crate::DateTime> {
+        let key = key.as_ref();
         match self.get(key) {
             Some(Bson::DateTime(v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::DateTime,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Get a mutable reference to a UTC datetime value for this key if it exists and has the
-    /// correct type.
-    pub fn get_datetime_mut(
-        &mut self,
-        key: impl AsRef<str>,
-    ) -> ValueAccessResult<&mut crate::DateTime> {
+    /// Returns a mutable reference to the value for the given key if one is present and is of type
+    /// [`ElementType::DateTime`].
+    pub fn get_datetime_mut(&mut self, key: impl AsRef<str>) -> Result<&mut crate::DateTime> {
+        let key = key.as_ref();
         match self.get_mut(key) {
             Some(&mut Bson::DateTime(ref mut v)) => Ok(v),
-            Some(_) => Err(ValueAccessError::UnexpectedType),
-            None => Err(ValueAccessError::NotPresent),
+            Some(bson) => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                ElementType::DateTime,
+            )),
+            None => Err(Error::value_access_not_present(key)),
         }
     }
 
-    /// Returns true if the map contains a value for the specified key.
+    /// Returns whether the map contains a value for the specified key.
     pub fn contains_key(&self, key: impl AsRef<str>) -> bool {
         self.inner.contains_key(key.as_ref())
     }
 
-    /// Gets a collection of all keys in the document.
+    /// Returns an iterator over the keys in the document.
     pub fn keys(&self) -> Keys {
         Keys {
             inner: self.inner.keys(),
         }
     }
 
-    /// Gets a collection of all values in the document.
+    /// Returns an iterator over the values in the document.
     pub fn values(&self) -> Values {
         Values {
             inner: self.inner.values(),
@@ -551,26 +647,27 @@ impl Document {
         self.inner.len()
     }
 
-    /// Returns true if the document contains no elements
+    /// Returns whether the document is empty.
     pub fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
 
-    /// Sets the value of the entry with the OccupiedEntry's key,
-    /// and returns the entry's old value. Accepts any type that
-    /// can be converted into Bson.
+    /// Inserts the provided key-value pair into the document. Any type that implements `Into<Bson>`
+    /// can be specified as a value. If a value is already present for the given key, it will be
+    /// overridden and returned.
     pub fn insert<KT: Into<String>, BT: Into<Bson>>(&mut self, key: KT, val: BT) -> Option<Bson> {
         self.inner.insert(key.into(), val.into())
     }
 
-    /// Takes the value of the entry out of the document, and returns it.
-    /// Computes in **O(n)** time (average).
+    /// Removes and returns the value that corresponds to the given key if present. Computes in
+    /// **O(n)** time (average).
     pub fn remove(&mut self, key: impl AsRef<str>) -> Option<Bson> {
         self.inner.shift_remove(key.as_ref())
     }
 
-    pub fn entry(&mut self, k: String) -> Entry {
-        match self.inner.entry(k) {
+    /// Returns an [`Entry`] for the given key.
+    pub fn entry(&mut self, k: impl Into<String>) -> Entry {
+        match self.inner.entry(k.into()) {
             indexmap::map::Entry::Occupied(o) => Entry::Occupied(OccupiedEntry { inner: o }),
             indexmap::map::Entry::Vacant(v) => Entry::Vacant(VacantEntry { inner: v }),
         }
@@ -647,9 +744,7 @@ impl Document {
     }
 }
 
-/// A view into a single entry in a map, which may either be vacant or occupied.
-///
-/// This enum is constructed from the entry method on HashMap.
+/// A view into a single entry in a document, which may either be vacant or occupied.
 pub enum Entry<'a> {
     /// An occupied entry.
     Occupied(OccupiedEntry<'a>),
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 00000000..5fefad1c
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,110 @@
+use thiserror::Error;
+
+use crate::spec::ElementType;
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// An error that can occur in the `bson` crate.
+#[derive(Debug, Error)]
+#[error("Kind: {kind}")]
+#[non_exhaustive]
+pub struct Error {
+    /// The kind of error that occurred.
+    pub kind: ErrorKind,
+}
+
+/// The types of errors that can occur in the `bson` crate.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum ErrorKind {
+    /// An error occurred when attempting to access a value in a document.
+    #[error("An error occurred when attempting to access a document value for key {key}: {kind}")]
+    #[non_exhaustive]
+    ValueAccess {
+        /// The key of the value.
+        key: String,
+
+        /// The kind of error that occurred.
+        kind: ValueAccessErrorKind,
+    },
+}
+
+/// The types of errors that can occur when attempting to access a value in a document.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum ValueAccessErrorKind {
+    /// No value for the specified key was present in the document.
+    #[error("The key was not present in the document")]
+    NotPresent,
+
+    /// The type of the value in the document did not match the requested type.
+    #[error("Expected type {expected:?}, got type {actual:?}")]
+    #[non_exhaustive]
+    UnexpectedType {
+        /// The actual type of the value.
+        actual: ElementType,
+
+        /// The expected type of the value.
+        expected: ElementType,
+    },
+
+    /// An error occurred when attempting to parse the document's BSON bytes.
+    #[error("{message}")]
+    #[non_exhaustive]
+    InvalidBson { message: String },
+}
+
+impl Error {
+    pub(crate) fn value_access_not_present(key: impl Into<String>) -> Self {
+        Self {
+            kind: ErrorKind::ValueAccess {
+                key: key.into(),
+                kind: ValueAccessErrorKind::NotPresent,
+            },
+        }
+    }
+
+    pub(crate) fn value_access_unexpected_type(
+        key: impl Into<String>,
+        actual: ElementType,
+        expected: ElementType,
+    ) -> Self {
+        Self {
+            kind: ErrorKind::ValueAccess {
+                key: key.into(),
+                kind: ValueAccessErrorKind::UnexpectedType { actual, expected },
+            },
+        }
+    }
+
+    pub(crate) fn value_access_invalid_bson(key: impl Into<String>, message: String) -> Self {
+        Self {
+            kind: ErrorKind::ValueAccess {
+                key: key.into(),
+                kind: ValueAccessErrorKind::InvalidBson { message },
+            },
+        }
+    }
+
+    #[cfg(test)]
+    pub(crate) fn is_value_access_not_present(&self) -> bool {
+        matches!(
+            self.kind,
+            ErrorKind::ValueAccess {
+                kind: ValueAccessErrorKind::NotPresent,
+                ..
+            }
+        )
+    }
+
+    #[cfg(test)]
+    pub(crate) fn is_value_access_unexpected_type(&self) -> bool {
+        matches!(
+            self.kind,
+            ErrorKind::ValueAccess {
+                kind: ValueAccessErrorKind::UnexpectedType { .. },
+                ..
+            }
+        )
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 7906e58e..d06f4601 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -320,6 +320,7 @@ pub mod datetime;
 pub mod de;
 pub mod decimal128;
 pub mod document;
+pub mod error;
 pub mod extjson;
 pub mod oid;
 pub mod raw;
diff --git a/src/raw.rs b/src/raw.rs
index 4e1dd0d6..364e45d5 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -141,7 +141,7 @@ pub use self::{
     },
     document::RawDocument,
     document_buf::{BindRawBsonRef, RawDocumentBuf},
-    error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
+    error::{Error, ErrorKind, Result},
     iter::{RawElement, RawIter},
 };
 
diff --git a/src/raw/array.rs b/src/raw/array.rs
index f6ed11ea..ce2232eb 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -3,17 +3,17 @@ use std::{borrow::Cow, convert::TryFrom};
 use serde::{ser::SerializeSeq, Deserialize, Serialize};
 
 use super::{
-    error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
     serde::OwnedOrBorrowedRawArray,
-    Error,
+    Error as RawError,
     RawBinaryRef,
     RawBsonRef,
     RawDocument,
     RawIter,
     RawRegexRef,
-    Result,
+    Result as RawResult,
 };
 use crate::{
+    error::{Error, Result},
     oid::ObjectId,
     raw::RAW_ARRAY_NEWTYPE,
     spec::ElementType,
@@ -58,7 +58,6 @@ use crate::{
 /// requires iterating through the array from the beginning to find the requested index.
 ///
 /// ```
-/// # use bson::raw::{ValueAccessError};
 /// use bson::{doc, raw::RawDocument};
 ///
 /// let doc = doc! {
@@ -104,7 +103,7 @@ impl RawArray {
     }
 
     /// Gets a reference to the value at the given index.
-    pub fn get(&self, index: usize) -> Result<Option<RawBsonRef<'_>>> {
+    pub fn get(&self, index: usize) -> RawResult<Option<RawBsonRef<'_>>> {
         self.into_iter().nth(index).transpose()
     }
 
@@ -113,44 +112,36 @@ impl RawArray {
         index: usize,
         expected_type: ElementType,
         f: impl FnOnce(RawBsonRef<'a>) -> Option<T>,
-    ) -> ValueAccessResult<T> {
+    ) -> Result<T> {
         let bson = self
             .get(index)
-            .map_err(|e| ValueAccessError {
-                key: index.to_string(),
-                kind: ValueAccessErrorKind::InvalidBson(e),
-            })?
-            .ok_or(ValueAccessError {
-                key: index.to_string(),
-                kind: ValueAccessErrorKind::NotPresent,
-            })?;
+            .map_err(|e| Error::value_access_invalid_bson(index.to_string(), format!("{:?}", e)))?
+            .ok_or_else(|| Error::value_access_not_present(index.to_string()))?;
         match f(bson) {
             Some(t) => Ok(t),
-            None => Err(ValueAccessError {
-                key: index.to_string(),
-                kind: ValueAccessErrorKind::UnexpectedType {
-                    expected: expected_type,
-                    actual: bson.element_type(),
-                },
-            }),
+            None => Err(Error::value_access_unexpected_type(
+                index.to_string(),
+                bson.element_type(),
+                expected_type,
+            )),
         }
     }
 
     /// 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<f64> {
+    pub fn get_f64(&self, index: usize) -> Result<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> {
+    pub fn get_str(&self, index: usize) -> Result<&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> {
+    pub fn get_document(&self, index: usize) -> Result<&RawDocument> {
         self.get_with(
             index,
             ElementType::EmbeddedDocument,
@@ -160,55 +151,55 @@ impl RawArray {
 
     /// 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> {
+    pub fn get_array(&self, index: usize) -> Result<&RawArray> {
         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<RawBinaryRef<'_>> {
+    pub fn get_binary(&self, index: usize) -> Result<RawBinaryRef<'_>> {
         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<ObjectId> {
+    pub fn get_object_id(&self, index: usize) -> Result<ObjectId> {
         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<bool> {
+    pub fn get_bool(&self, index: usize) -> Result<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<DateTime> {
+    pub fn get_datetime(&self, index: usize) -> Result<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<RawRegexRef<'_>> {
+    pub fn get_regex(&self, index: usize) -> Result<RawRegexRef<'_>> {
         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<Timestamp> {
+    pub fn get_timestamp(&self, index: usize) -> Result<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<i32> {
+    pub fn get_i32(&self, index: usize) -> Result<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<i64> {
+    pub fn get_i64(&self, index: usize) -> Result<i64> {
         self.get_with(index, ElementType::Int64, RawBsonRef::as_i64)
     }
 
@@ -232,9 +223,9 @@ impl std::fmt::Debug for RawArray {
 }
 
 impl TryFrom<&RawArray> for Vec<Bson> {
-    type Error = Error;
+    type Error = RawError;
 
-    fn try_from(arr: &RawArray) -> Result<Vec<Bson>> {
+    fn try_from(arr: &RawArray) -> RawResult<Vec<Bson>> {
         arr.into_iter()
             .map(|result| {
                 let rawbson = result?;
@@ -260,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<RawBsonRef<'a>>;
+    type Item = RawResult<RawBsonRef<'a>>;
 
     fn into_iter(self) -> RawArrayIter<'a> {
         RawArrayIter {
@@ -275,9 +266,9 @@ pub struct RawArrayIter<'a> {
 }
 
 impl<'a> Iterator for RawArrayIter<'a> {
-    type Item = Result<RawBsonRef<'a>>;
+    type Item = RawResult<RawBsonRef<'a>>;
 
-    fn next(&mut self) -> Option<Result<RawBsonRef<'a>>> {
+    fn next(&mut self) -> Option<RawResult<RawBsonRef<'a>>> {
         match self.inner.next() {
             Some(Ok(elem)) => match elem.value() {
                 Ok(value) => Some(Ok(value)),
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 8f725a0a..c39276f3 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -7,24 +7,24 @@ use serde::{ser::SerializeMap, Deserialize, Serialize};
 
 use crate::{
     de::MIN_BSON_DOCUMENT_SIZE,
+    error::{Error, Result},
     raw::{error::ErrorKind, serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE},
     DateTime,
     Timestamp,
 };
 
 use super::{
-    error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
     i32_from_slice,
     iter::Iter,
     try_to_str,
-    Error,
+    Error as RawError,
     RawArray,
     RawBinaryRef,
     RawBsonRef,
     RawDocumentBuf,
     RawIter,
     RawRegexRef,
-    Result,
+    Result as RawResult,
 };
 use crate::{oid::ObjectId, spec::ElementType, Document};
 
@@ -91,11 +91,11 @@ impl RawDocument {
     /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?;
     /// # Ok::<(), bson::raw::Error>(())
     /// ```
-    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> Result<&RawDocument> {
+    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
         let data = data.as_ref();
 
         if data.len() < 5 {
-            return Err(Error {
+            return Err(RawError {
                 key: None,
                 kind: ErrorKind::MalformedValue {
                     message: "document too short".into(),
@@ -106,7 +106,7 @@ impl RawDocument {
         let length = i32_from_slice(data)?;
 
         if data.len() as i32 != length {
-            return Err(Error {
+            return Err(RawError {
                 key: None,
                 kind: ErrorKind::MalformedValue {
                     message: "document length incorrect".into(),
@@ -115,7 +115,7 @@ impl RawDocument {
         }
 
         if data[data.len() - 1] != 0 {
-            return Err(Error {
+            return Err(RawError {
                 key: None,
                 kind: ErrorKind::MalformedValue {
                     message: "document not null-terminated".into(),
@@ -171,7 +171,7 @@ impl RawDocument {
     /// assert!(doc.get("unknown")?.is_none());
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn get(&self, key: impl AsRef<str>) -> Result<Option<RawBsonRef<'_>>> {
+    pub fn get(&self, key: impl AsRef<str>) -> RawResult<Option<RawBsonRef<'_>>> {
         for elem in RawIter::new(self) {
             let elem = elem?;
             if key.as_ref() == elem.key() {
@@ -206,28 +206,20 @@ impl RawDocument {
         key: impl AsRef<str>,
         expected_type: ElementType,
         f: impl FnOnce(RawBsonRef<'a>) -> Option<T>,
-    ) -> ValueAccessResult<T> {
+    ) -> Result<T> {
         let key = key.as_ref();
 
         let bson = self
             .get(key)
-            .map_err(|e| ValueAccessError {
-                key: key.to_string(),
-                kind: ValueAccessErrorKind::InvalidBson(e),
-            })?
-            .ok_or(ValueAccessError {
-                key: key.to_string(),
-                kind: ValueAccessErrorKind::NotPresent,
-            })?;
+            .map_err(|e| Error::value_access_invalid_bson(key, format!("{:?}", e)))?
+            .ok_or_else(|| Error::value_access_not_present(key))?;
         match f(bson) {
             Some(t) => Ok(t),
-            None => Err(ValueAccessError {
-                key: key.to_string(),
-                kind: ValueAccessErrorKind::UnexpectedType {
-                    expected: expected_type,
-                    actual: bson.element_type(),
-                },
-            }),
+            None => Err(Error::value_access_unexpected_type(
+                key,
+                bson.element_type(),
+                expected_type,
+            )),
         }
     }
 
@@ -236,7 +228,6 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::raw::ValueAccessErrorKind;
     /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
@@ -245,11 +236,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(doc.get_f64("f64")?, 2.5);
-    /// assert!(matches!(doc.get_f64("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_f64("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_f64("bool").is_err());
+    /// assert!(doc.get_f64("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_f64(&self, key: impl AsRef<str>) -> ValueAccessResult<f64> {
+    pub fn get_f64(&self, key: impl AsRef<str>) -> Result<f64> {
         self.get_with(key, ElementType::Double, RawBsonRef::as_f64)
     }
 
@@ -257,7 +248,7 @@ impl RawDocument {
     /// key corresponds to a value which isn't a string.
     ///
     /// ```
-    /// use bson::{rawdoc, raw::ValueAccessErrorKind};
+    /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
     ///     "string": "hello",
@@ -265,11 +256,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(doc.get_str("string")?, "hello");
-    /// assert!(matches!(doc.get_str("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_str("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_str("bool").is_err());
+    /// assert!(doc.get_str("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_str(&self, key: impl AsRef<str>) -> ValueAccessResult<&'_ str> {
+    pub fn get_str(&self, key: impl AsRef<str>) -> Result<&'_ str> {
         self.get_with(key, ElementType::String, RawBsonRef::as_str)
     }
 
@@ -278,7 +269,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, raw::ValueAccessErrorKind};
+    /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
     ///     "doc": { "key": "value"},
@@ -286,11 +277,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(doc.get_document("doc")?.get_str("key")?, "value");
-    /// assert!(matches!(doc.get_document("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_document("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_document("bool").is_err());
+    /// assert!(doc.get_document("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_document(&self, key: impl AsRef<str>) -> ValueAccessResult<&'_ RawDocument> {
+    pub fn get_document(&self, key: impl AsRef<str>) -> Result<&'_ RawDocument> {
         self.get_with(key, ElementType::EmbeddedDocument, RawBsonRef::as_document)
     }
 
@@ -298,7 +289,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't an array.
     ///
     /// ```
-    /// use bson::{rawdoc, raw::ValueAccessErrorKind};
+    /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
     ///     "array": [true, 3],
@@ -311,10 +302,10 @@ impl RawDocument {
     ///
     /// assert!(arr_iter.next().is_none());
     /// assert!(doc.get_array("bool").is_err());
-    /// assert!(matches!(doc.get_array("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_array("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_array(&self, key: impl AsRef<str>) -> ValueAccessResult<&'_ RawArray> {
+    pub fn get_array(&self, key: impl AsRef<str>) -> Result<&'_ RawArray> {
         self.get_with(key, ElementType::Array, RawBsonRef::as_array)
     }
 
@@ -324,7 +315,6 @@ impl RawDocument {
     /// ```
     /// use bson::{
     ///     rawdoc,
-    ///     raw::ValueAccessErrorKind,
     ///     spec::BinarySubtype,
     ///     Binary,
     /// };
@@ -335,11 +325,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(&doc.get_binary("binary")?.bytes, &[1, 2, 3]);
-    /// assert!(matches!(doc.get_binary("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_binary("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_binary("bool").is_err());
+    /// assert!(doc.get_binary("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_binary(&self, key: impl AsRef<str>) -> ValueAccessResult<RawBinaryRef<'_>> {
+    pub fn get_binary(&self, key: impl AsRef<str>) -> Result<RawBinaryRef<'_>> {
         self.get_with(key, ElementType::Binary, RawBsonRef::as_binary)
     }
 
@@ -348,7 +338,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, oid::ObjectId, raw::ValueAccessErrorKind};
+    /// use bson::{rawdoc, oid::ObjectId};
     ///
     /// let doc = rawdoc! {
     ///     "_id": ObjectId::new(),
@@ -356,11 +346,11 @@ impl RawDocument {
     /// };
     ///
     /// let oid = doc.get_object_id("_id")?;
-    /// assert!(matches!(doc.get_object_id("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_object_id("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_object_id("bool").is_err());
+    /// assert!(doc.get_object_id("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_object_id(&self, key: impl AsRef<str>) -> ValueAccessResult<ObjectId> {
+    pub fn get_object_id(&self, key: impl AsRef<str>) -> Result<ObjectId> {
         self.get_with(key, ElementType::ObjectId, RawBsonRef::as_object_id)
     }
 
@@ -369,7 +359,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, oid::ObjectId, raw::ValueAccessErrorKind};
+    /// use bson::{rawdoc, oid::ObjectId};
     ///
     /// let doc = rawdoc! {
     ///     "_id": ObjectId::new(),
@@ -377,11 +367,11 @@ impl RawDocument {
     /// };
     ///
     /// assert!(doc.get_bool("bool")?);
-    /// assert!(matches!(doc.get_bool("_id").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_bool("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_bool("_id").is_err());
+    /// assert!(doc.get_bool("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_bool(&self, key: impl AsRef<str>) -> ValueAccessResult<bool> {
+    pub fn get_bool(&self, key: impl AsRef<str>) -> Result<bool> {
         self.get_with(key, ElementType::Boolean, RawBsonRef::as_bool)
     }
 
@@ -390,7 +380,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, raw::ValueAccessErrorKind, DateTime};
+    /// use bson::{rawdoc, DateTime};
     ///
     /// let dt = DateTime::now();
     /// let doc = rawdoc! {
@@ -399,11 +389,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(doc.get_datetime("created_at")?, dt);
-    /// assert!(matches!(doc.get_datetime("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_datetime("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_datetime("bool").is_err());
+    /// assert!(doc.get_datetime("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_datetime(&self, key: impl AsRef<str>) -> ValueAccessResult<DateTime> {
+    pub fn get_datetime(&self, key: impl AsRef<str>) -> Result<DateTime> {
         self.get_with(key, ElementType::DateTime, RawBsonRef::as_datetime)
     }
 
@@ -411,7 +401,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't a regex.
     ///
     /// ```
-    /// use bson::{rawdoc, Regex, raw::ValueAccessErrorKind};
+    /// use bson::{rawdoc, Regex};
     ///
     /// let doc = rawdoc! {
     ///     "regex": Regex {
@@ -423,11 +413,11 @@ impl RawDocument {
     ///
     /// 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));
+    /// assert!(doc.get_regex("bool").is_err());
+    /// assert!(doc.get_regex("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_regex(&self, key: impl AsRef<str>) -> ValueAccessResult<RawRegexRef<'_>> {
+    pub fn get_regex(&self, key: impl AsRef<str>) -> Result<RawRegexRef<'_>> {
         self.get_with(key, ElementType::RegularExpression, RawBsonRef::as_regex)
     }
 
@@ -436,7 +426,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, Timestamp, raw::ValueAccessErrorKind};
+    /// use bson::{rawdoc, Timestamp};
     ///
     /// let doc = rawdoc! {
     ///     "bool": true,
@@ -447,11 +437,11 @@ impl RawDocument {
     ///
     /// assert_eq!(timestamp.time, 649876543);
     /// assert_eq!(timestamp.increment, 9);
-    /// assert!(matches!(doc.get_timestamp("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_timestamp("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_timestamp("bool").is_err());
+    /// assert!(doc.get_timestamp("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_timestamp(&self, key: impl AsRef<str>) -> ValueAccessResult<Timestamp> {
+    pub fn get_timestamp(&self, key: impl AsRef<str>) -> Result<Timestamp> {
         self.get_with(key, ElementType::Timestamp, RawBsonRef::as_timestamp)
     }
 
@@ -460,7 +450,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, raw::ValueAccessErrorKind};
+    /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
     ///     "bool": true,
@@ -468,11 +458,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(doc.get_i32("i32")?, 1_000_000);
-    /// assert!(matches!(doc.get_i32("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { ..}));
-    /// assert!(matches!(doc.get_i32("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_i32("bool").is_err());
+    /// assert!(doc.get_i32("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_i32(&self, key: impl AsRef<str>) -> ValueAccessResult<i32> {
+    pub fn get_i32(&self, key: impl AsRef<str>) -> Result<i32> {
         self.get_with(key, ElementType::Int32, RawBsonRef::as_i32)
     }
 
@@ -481,7 +471,7 @@ impl RawDocument {
     ///
     /// ```
     /// # use bson::raw::Error;
-    /// use bson::{rawdoc, raw::ValueAccessErrorKind};
+    /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
     ///     "bool": true,
@@ -489,11 +479,11 @@ impl RawDocument {
     /// };
     ///
     /// assert_eq!(doc.get_i64("i64")?, 9223372036854775807);
-    /// assert!(matches!(doc.get_i64("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. }));
-    /// assert!(matches!(doc.get_i64("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent));
+    /// assert!(doc.get_i64("bool").is_err());
+    /// assert!(doc.get_i64("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
     /// ```
-    pub fn get_i64(&self, key: impl AsRef<str>) -> ValueAccessResult<i64> {
+    pub fn get_i64(&self, key: impl AsRef<str>) -> Result<i64> {
         self.get_with(key, ElementType::Int64, RawBsonRef::as_i64)
     }
 
@@ -515,19 +505,21 @@ impl RawDocument {
         self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize
     }
 
-    pub(crate) fn cstring_bytes_at(&self, start_at: usize) -> Result<&[u8]> {
+    pub(crate) fn cstring_bytes_at(&self, start_at: usize) -> RawResult<&[u8]> {
         let buf = &self.as_bytes()[start_at..];
 
         let mut splits = buf.splitn(2, |x| *x == 0);
-        let value = splits.next().ok_or_else(|| Error::malformed("no value"))?;
+        let value = splits
+            .next()
+            .ok_or_else(|| RawError::malformed("no value"))?;
         if splits.next().is_some() {
             Ok(value)
         } else {
-            Err(Error::malformed("expected null terminator"))
+            Err(RawError::malformed("expected null terminator"))
         }
     }
 
-    pub(crate) fn read_cstring_at(&self, start_at: usize) -> Result<&str> {
+    pub(crate) fn read_cstring_at(&self, start_at: usize) -> RawResult<&str> {
         let bytes = self.cstring_bytes_at(start_at)?;
         try_to_str(bytes)
     }
@@ -605,9 +597,9 @@ impl<'a> From<&'a RawDocument> for Cow<'a, RawDocument> {
 }
 
 impl TryFrom<&RawDocument> for crate::Document {
-    type Error = Error;
+    type Error = RawError;
 
-    fn try_from(rawdoc: &RawDocument) -> Result<Document> {
+    fn try_from(rawdoc: &RawDocument) -> RawResult<Document> {
         rawdoc
             .into_iter()
             .map(|res| res.and_then(|(k, v)| Ok((k.to_owned(), v.try_into()?))))
@@ -617,7 +609,7 @@ impl TryFrom<&RawDocument> for crate::Document {
 
 impl<'a> IntoIterator for &'a RawDocument {
     type IntoIter = Iter<'a>;
-    type Item = Result<(&'a str, RawBsonRef<'a>)>;
+    type Item = RawResult<(&'a str, RawBsonRef<'a>)>;
 
     fn into_iter(self) -> Iter<'a> {
         self.iter()
diff --git a/src/raw/error.rs b/src/raw/error.rs
index a9912d90..10f3a8f6 100644
--- a/src/raw/error.rs
+++ b/src/raw/error.rs
@@ -1,5 +1,3 @@
-use crate::spec::ElementType;
-
 /// An error that occurs when attempting to parse raw BSON bytes.
 #[derive(Debug, PartialEq, Clone)]
 #[non_exhaustive]
@@ -72,65 +70,3 @@ pub type Result<T> = std::result::Result<T, Error>;
 pub(crate) fn try_with_key<G, F: FnOnce() -> Result<G>>(key: impl Into<String>, f: F) -> Result<G> {
     f().map_err(|e| e.with_key(key))
 }
-
-pub type ValueAccessResult<T> = std::result::Result<T, ValueAccessError>;
-
-/// Error to indicate that either a value was empty or it contained an unexpected
-/// type, for use with the direct getters (e.g. [`crate::RawDocument::get_str`]).
-#[derive(Debug, PartialEq, Clone)]
-#[non_exhaustive]
-pub struct ValueAccessError {
-    /// The type of error that was encountered.
-    pub kind: ValueAccessErrorKind,
-
-    /// The key at which the error was encountered.
-    pub(crate) key: String,
-}
-
-impl ValueAccessError {
-    /// The key at which the error was encountered.
-    pub fn key(&self) -> &str {
-        self.key.as_str()
-    }
-}
-
-/// The type of error encountered when using a direct getter (e.g. [`crate::RawDocument::get_str`]).
-#[derive(Debug, PartialEq, Clone)]
-#[non_exhaustive]
-pub enum ValueAccessErrorKind {
-    /// Cannot find the expected field with the specified key
-    NotPresent,
-
-    /// Found a Bson value with the specified key, but not with the expected type
-    #[non_exhaustive]
-    UnexpectedType {
-        /// The type that was expected.
-        expected: ElementType,
-
-        /// The actual type that was encountered.
-        actual: ElementType,
-    },
-
-    /// An error was encountered attempting to decode the document.
-    InvalidBson(super::Error),
-}
-
-impl std::fmt::Display for ValueAccessError {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        let prefix = format!("error at key: \"{}\": ", self.key);
-
-        match &self.kind {
-            ValueAccessErrorKind::UnexpectedType { actual, expected } => write!(
-                f,
-                "{} unexpected element type: {:?}, expected: {:?}",
-                prefix, actual, expected
-            ),
-            ValueAccessErrorKind::InvalidBson(error) => {
-                write!(f, "{}: {}", prefix, error)
-            }
-            ValueAccessErrorKind::NotPresent => write!(f, "{}value not present", prefix),
-        }
-    }
-}
-
-impl std::error::Error for ValueAccessError {}
diff --git a/src/raw/test.rs b/src/raw/test.rs
index 11f6bcd3..caf1fc99 100644
--- a/src/raw/test.rs
+++ b/src/raw/test.rs
@@ -5,7 +5,6 @@ use super::*;
 use crate::{
     doc,
     oid::ObjectId,
-    raw::error::ValueAccessErrorKind,
     spec::BinarySubtype,
     Binary,
     Bson,
@@ -183,12 +182,9 @@ fn array() {
         .expect("no key array")
         .as_array()
         .expect("result was not an array");
-    assert_eq!(array.get_str(0), Ok("binary"));
-    assert_eq!(array.get_str(3), Ok("notation"));
-    assert_eq!(
-        array.get_str(4).unwrap_err().kind,
-        ValueAccessErrorKind::NotPresent
-    );
+    assert_eq!(array.get_str(0).unwrap(), "binary");
+    assert_eq!(array.get_str(3).unwrap(), "notation");
+    assert!(array.get_str(4).unwrap_err().is_value_access_not_present());
 }
 
 #[test]
diff --git a/src/tests/modules/document.rs b/src/tests/modules/document.rs
index c6f5390e..365138f5 100644
--- a/src/tests/modules/document.rs
+++ b/src/tests/modules/document.rs
@@ -1,6 +1,5 @@
 use crate::{
     doc,
-    document::ValueAccessError,
     oid::ObjectId,
     spec::BinarySubtype,
     tests::LOCK,
@@ -66,42 +65,45 @@ fn test_getters() {
     };
 
     assert_eq!(None, doc.get("nonsense"));
-    assert_eq!(Err(ValueAccessError::NotPresent), doc.get_str("nonsense"));
-    assert_eq!(
-        Err(ValueAccessError::UnexpectedType),
-        doc.get_str("floating_point")
-    );
+    assert!(doc
+        .get_str("nonsense")
+        .unwrap_err()
+        .is_value_access_not_present());
+    assert!(doc
+        .get_str("floating_point")
+        .unwrap_err()
+        .is_value_access_unexpected_type());
 
     assert_eq!(Some(&Bson::Double(10.0)), doc.get("floating_point"));
-    assert_eq!(Ok(10.0), doc.get_f64("floating_point"));
+    assert_eq!(10.0, doc.get_f64("floating_point").unwrap());
 
     assert_eq!(
         Some(&Bson::String("a value".to_string())),
         doc.get("string")
     );
-    assert_eq!(Ok("a value"), doc.get_str("string"));
+    assert_eq!("a value", doc.get_str("string").unwrap());
 
     let array = vec![Bson::Int32(10), Bson::Int32(20), Bson::Int32(30)];
     assert_eq!(Some(&Bson::Array(array.clone())), doc.get("array"));
-    assert_eq!(Ok(&array), doc.get_array("array"));
+    assert_eq!(&array, doc.get_array("array").unwrap());
 
     let embedded = doc! { "key": 1 };
     assert_eq!(Some(&Bson::Document(embedded.clone())), doc.get("doc"));
-    assert_eq!(Ok(&embedded), doc.get_document("doc"));
+    assert_eq!(&embedded, doc.get_document("doc").unwrap());
 
     assert_eq!(Some(&Bson::Boolean(true)), doc.get("bool"));
-    assert_eq!(Ok(true), doc.get_bool("bool"));
+    assert!(doc.get_bool("bool").unwrap());
 
     doc.insert("null".to_string(), Bson::Null);
     assert_eq!(Some(&Bson::Null), doc.get("null"));
-    assert!(doc.is_null("null"));
-    assert!(!doc.is_null("array"));
+    assert_eq!(doc.get_null("null").unwrap(), Bson::Null);
+    assert!(doc.get_null("array").is_err());
 
     assert_eq!(Some(&Bson::Int32(1)), doc.get("i32"));
-    assert_eq!(Ok(1i32), doc.get_i32("i32"));
+    assert_eq!(1i32, doc.get_i32("i32").unwrap());
 
     assert_eq!(Some(&Bson::Int64(1)), doc.get("i64"));
-    assert_eq!(Ok(1i64), doc.get_i64("i64"));
+    assert_eq!(1i64, doc.get_i64("i64").unwrap());
 
     doc.insert(
         "timestamp".to_string(),
@@ -118,21 +120,21 @@ fn test_getters() {
         doc.get("timestamp")
     );
     assert_eq!(
-        Ok(Timestamp {
+        Timestamp {
             time: 0,
             increment: 100,
-        }),
-        doc.get_timestamp("timestamp")
+        },
+        doc.get_timestamp("timestamp").unwrap()
     );
 
     let dt = crate::DateTime::from_time_0_3(datetime);
     assert_eq!(Some(&Bson::DateTime(dt)), doc.get("datetime"));
-    assert_eq!(Ok(&dt), doc.get_datetime("datetime"));
+    assert_eq!(&dt, doc.get_datetime("datetime").unwrap());
 
     let object_id = ObjectId::new();
     doc.insert("_id".to_string(), Bson::ObjectId(object_id));
     assert_eq!(Some(&Bson::ObjectId(object_id)), doc.get("_id"));
-    assert_eq!(Ok(object_id), doc.get_object_id("_id"));
+    assert_eq!(object_id, doc.get_object_id("_id").unwrap());
 
     assert_eq!(
         Some(&Bson::Binary(Binary {
@@ -141,7 +143,7 @@ fn test_getters() {
         })),
         doc.get("binary")
     );
-    assert_eq!(Ok(&binary), doc.get_binary_generic("binary"));
+    assert_eq!(&binary, doc.get_binary_generic("binary").unwrap());
 }
 
 #[test]
@@ -301,13 +303,7 @@ fn test_display_doc_with_array() {
     let doc_display_expectation = "{ \"hello\": [1, 2, 3] }";
     assert_eq!(doc_display_expectation, format!("{doc}"));
 
-    let doc_display_pretty_expectation = r#"{
-  "hello": [
-    1, 
-    2, 
-    3
-  ]
-}"#;
+    let doc_display_pretty_expectation = "{\n  \"hello\": [\n    1, \n    2, \n    3\n  ]\n}";
     let formatted = format!("{doc:#}");
     assert_eq!(doc_display_pretty_expectation, formatted);
 
@@ -315,15 +311,7 @@ fn test_display_doc_with_array() {
         "a": [1, [1, 2]]
     };
 
-    let expectation = r#"{
-  "a": [
-    1, 
-    [
-      1, 
-      2
-    ]
-  ]
-}"#;
+    let expectation = "{\n  \"a\": [\n    1, \n    [\n      1, \n      2\n    ]\n  ]\n}";
     assert_eq!(expectation, format!("{nested_array_doc:#}"));
 }
 
@@ -338,37 +326,16 @@ fn test_pretty_printing() {
     );
 
     let d = doc! { "hello": "world!", "nested": { "key": "val", "double": { "a": "thing" } } };
-    let expected = r#"{
-  "hello": "world!",
-  "nested": {
-    "key": "val",
-    "double": {
-      "a": "thing"
-    }
-  }
-}"#;
+    #[rustfmt::skip]
+    let expected =  "{\n  \"hello\": \"world!\",\n  \"nested\": {\n    \"key\": \"val\",\n    \"double\": {\n      \"a\": \"thing\"\n    }\n  }\n}";
     let formatted = format!("{d:#}");
-    assert_eq!(
-        expected, formatted,
-        "expected:\n{expected}\ngot:\n{formatted}"
-    );
+    assert_eq!(formatted, expected);
 
     let d =
         doc! { "hello": "world!", "nested": { "key": "val", "double": { "a": [1, 2], "c": "d"} } };
-    let expected = r#"{
-  "hello": "world!",
-  "nested": {
-    "key": "val",
-    "double": {
-      "a": [
-        1, 
-        2
-      ],
-      "c": "d"
-    }
-  }
-}"#;
-    assert_eq!(expected, format!("{d:#}"));
+    #[rustfmt::skip]
+    let expected = "{\n  \"hello\": \"world!\",\n  \"nested\": {\n    \"key\": \"val\",\n    \"double\": {\n      \"a\": [\n        1, \n        2\n      ],\n      \"c\": \"d\"\n    }\n  }\n}";
+    assert_eq!(format!("{d:#}"), expected);
 }
 
 #[test]

From b40735733f1a4aefdc53a990442fcc54c970e6b2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 9 Jun 2025 08:04:11 -0400
Subject: [PATCH 118/156] Bump the rust-dependencies group with 6 updates
 (#553)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 60 ++++++++++++++----------------------------------------
 1 file changed, 15 insertions(+), 45 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 2c7968d7..b157ab2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -134,7 +134,7 @@ dependencies = [
  "once_cell",
  "pretty_assertions",
  "proptest",
- "rand 0.9.1",
+ "rand",
  "serde",
  "serde_bytes",
  "serde_json",
@@ -148,9 +148,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
 
 [[package]]
 name = "cast"
@@ -160,9 +160,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.25"
+version = "1.2.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
+checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
 dependencies = [
  "shlex",
 ]
@@ -655,17 +655,17 @@ dependencies = [
 
 [[package]]
 name = "proptest"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50"
+checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f"
 dependencies = [
  "bit-set",
  "bit-vec",
  "bitflags 2.9.0",
  "lazy_static",
  "num-traits",
- "rand 0.8.5",
- "rand_chacha 0.3.1",
+ "rand",
+ "rand_chacha",
  "rand_xorshift",
  "regex-syntax",
  "rusty-fork",
@@ -700,35 +700,14 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
 
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
 [[package]]
 name = "rand"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
 dependencies = [
- "rand_chacha 0.9.0",
- "rand_core 0.9.3",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.6.4",
+ "rand_chacha",
+ "rand_core",
 ]
 
 [[package]]
@@ -738,16 +717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.9.3",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom 0.2.16",
+ "rand_core",
 ]
 
 [[package]]
@@ -761,11 +731,11 @@ dependencies = [
 
 [[package]]
 name = "rand_xorshift"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
+checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]

From 328d540df28d01afa71da55d485e4b83e61913c7 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 9 Jun 2025 11:13:48 -0400
Subject: [PATCH 119/156] RUST-1406 Convert raw errors to standard error type
 (#552)

---
 src/de/error.rs         |   6 +-
 src/document.rs         | 104 +++++++++++++++++------------------
 src/error.rs            |  94 ++++++++++++++++++++++---------
 src/raw.rs              |  37 +++++++------
 src/raw/array.rs        |  14 ++---
 src/raw/array_buf.rs    |   4 +-
 src/raw/document.rs     |  69 +++++++++--------------
 src/raw/document_buf.rs |  25 +++------
 src/raw/error.rs        |  72 ------------------------
 src/raw/iter.rs         | 119 ++++++++++++++++++++--------------------
 10 files changed, 244 insertions(+), 300 deletions(-)
 delete mode 100644 src/raw/error.rs

diff --git a/src/de/error.rs b/src/de/error.rs
index 8b3c7920..1d6eed0d 100644
--- a/src/de/error.rs
+++ b/src/de/error.rs
@@ -76,9 +76,9 @@ impl From<string::FromUtf8Error> for Error {
     }
 }
 
-impl From<crate::raw::Error> for Error {
-    fn from(value: crate::raw::Error) -> Self {
-        Self::deserialization(value)
+impl From<crate::error::Error> for Error {
+    fn from(error: crate::error::Error) -> Self {
+        Self::deserialization(error.to_string())
     }
 }
 
diff --git a/src/document.rs b/src/document.rs
index c4911e4a..30e49283 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -252,12 +252,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::Double(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Double,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -267,12 +267,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Double(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Double,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -282,12 +282,12 @@ impl Document {
         match self.get(key) {
             Some(Bson::Decimal128(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Decimal128,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -297,12 +297,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Decimal128(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Decimal128,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -310,14 +310,14 @@ impl Document {
     pub fn get_str(&self, key: impl AsRef<str>) -> Result<&str> {
         let key = key.as_ref();
         match self.get(key) {
-            Some(Bson::String(v)) => Ok(v),
+            Some(Bson::String(v)) => Ok(v.as_str()),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::String,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -325,14 +325,14 @@ impl Document {
     pub fn get_str_mut(&mut self, key: impl AsRef<str>) -> Result<&mut str> {
         let key = key.as_ref();
         match self.get_mut(key) {
-            Some(&mut Bson::String(ref mut v)) => Ok(v),
+            Some(&mut Bson::String(ref mut v)) => Ok(v.as_mut_str()),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::String,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -342,12 +342,12 @@ impl Document {
         match self.get(key) {
             Some(Bson::Array(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Array,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -357,12 +357,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Array(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Array,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -372,12 +372,12 @@ impl Document {
         match self.get(key) {
             Some(Bson::Document(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::EmbeddedDocument,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -387,12 +387,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Document(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::EmbeddedDocument,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -402,12 +402,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::Boolean(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Boolean,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -417,12 +417,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Boolean(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Boolean,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns [`Bson::Null`] if the given key corresponds to a [`Bson::Null`] value.
@@ -431,12 +431,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::Null) => Ok(Bson::Null),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Null,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns the value for the given key if one is present and is of type [`ElementType::Int32`].
@@ -445,12 +445,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::Int32(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Int32,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -460,12 +460,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Int32(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Int32,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns the value for the given key if one is present and is of type [`ElementType::Int64`].
@@ -474,12 +474,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::Int64(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Int64,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -489,12 +489,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Int64(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Int64,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns the value for the given key if one is present and is of type
@@ -504,12 +504,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::Timestamp(timestamp)) => Ok(timestamp),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Timestamp,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -519,12 +519,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::Timestamp(ref mut timestamp)) => Ok(timestamp),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Timestamp,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -537,12 +537,12 @@ impl Document {
                 ref bytes,
             })) => Ok(bytes),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Binary,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -555,12 +555,12 @@ impl Document {
                 ref mut bytes,
             })) => Ok(bytes),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::Binary,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns the value for the given key if one is present and is of type
@@ -570,12 +570,12 @@ impl Document {
         match self.get(key) {
             Some(&Bson::ObjectId(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::ObjectId,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -585,12 +585,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::ObjectId(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::ObjectId,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a reference to the value for the given key if one is present and is of type
@@ -600,12 +600,12 @@ impl Document {
         match self.get(key) {
             Some(Bson::DateTime(v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::DateTime,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns a mutable reference to the value for the given key if one is present and is of type
@@ -615,12 +615,12 @@ impl Document {
         match self.get_mut(key) {
             Some(&mut Bson::DateTime(ref mut v)) => Ok(v),
             Some(bson) => Err(Error::value_access_unexpected_type(
-                key,
                 bson.element_type(),
                 ElementType::DateTime,
             )),
-            None => Err(Error::value_access_not_present(key)),
+            None => Err(Error::value_access_not_present()),
         }
+        .map_err(|e| e.with_key(key))
     }
 
     /// Returns whether the map contains a value for the specified key.
diff --git a/src/error.rs b/src/error.rs
index 5fefad1c..58f3e000 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -6,29 +6,62 @@ pub type Result<T> = std::result::Result<T, Error>;
 
 /// An error that can occur in the `bson` crate.
 #[derive(Debug, Error)]
-#[error("Kind: {kind}")]
 #[non_exhaustive]
 pub struct Error {
     /// The kind of error that occurred.
     pub kind: ErrorKind,
+
+    /// The document key associated with the error, if any.
+    pub key: Option<String>,
+
+    /// The array index associated with the error, if any.
+    pub index: Option<usize>,
+}
+
+impl std::fmt::Display for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if let Some(key) = self.key.as_deref() {
+            write!(f, "Error at key \"{key}\": ")?;
+        } else if let Some(index) = self.index {
+            write!(f, "Error at array index {index}: ")?;
+        }
+
+        write!(f, "{}", self.kind)
+    }
 }
 
 /// The types of errors that can occur in the `bson` crate.
 #[derive(Debug, Error)]
 #[non_exhaustive]
 pub enum ErrorKind {
+    /// Malformed BSON bytes were encountered.
+    #[error("Malformed BSON: {message}")]
+    #[non_exhaustive]
+    MalformedValue { message: String },
+
+    /// Invalid UTF-8 bytes were encountered.
+    #[error("Invalid UTF-8")]
+    Utf8Encoding,
+
     /// An error occurred when attempting to access a value in a document.
-    #[error("An error occurred when attempting to access a document value for key {key}: {kind}")]
+    #[error("An error occurred when attempting to access a document value: {kind}")]
     #[non_exhaustive]
     ValueAccess {
-        /// The key of the value.
-        key: String,
-
         /// The kind of error that occurred.
         kind: ValueAccessErrorKind,
     },
 }
 
+impl From<ErrorKind> for Error {
+    fn from(kind: ErrorKind) -> Self {
+        Self {
+            kind,
+            key: None,
+            index: None,
+        }
+    }
+}
+
 /// The types of errors that can occur when attempting to access a value in a document.
 #[derive(Debug, Error)]
 #[non_exhaustive]
@@ -55,35 +88,42 @@ pub enum ValueAccessErrorKind {
 }
 
 impl Error {
-    pub(crate) fn value_access_not_present(key: impl Into<String>) -> Self {
-        Self {
-            kind: ErrorKind::ValueAccess {
-                key: key.into(),
-                kind: ValueAccessErrorKind::NotPresent,
-            },
+    pub(crate) fn with_key(mut self, key: impl Into<String>) -> Self {
+        self.key = Some(key.into());
+        self
+    }
+
+    pub(crate) fn with_index(mut self, index: usize) -> Self {
+        self.index = Some(index);
+        self
+    }
+
+    pub(crate) fn value_access_not_present() -> Self {
+        ErrorKind::ValueAccess {
+            kind: ValueAccessErrorKind::NotPresent,
         }
+        .into()
     }
 
-    pub(crate) fn value_access_unexpected_type(
-        key: impl Into<String>,
-        actual: ElementType,
-        expected: ElementType,
-    ) -> Self {
-        Self {
-            kind: ErrorKind::ValueAccess {
-                key: key.into(),
-                kind: ValueAccessErrorKind::UnexpectedType { actual, expected },
-            },
+    pub(crate) fn value_access_unexpected_type(actual: ElementType, expected: ElementType) -> Self {
+        ErrorKind::ValueAccess {
+            kind: ValueAccessErrorKind::UnexpectedType { actual, expected },
         }
+        .into()
     }
 
-    pub(crate) fn value_access_invalid_bson(key: impl Into<String>, message: String) -> Self {
-        Self {
-            kind: ErrorKind::ValueAccess {
-                key: key.into(),
-                kind: ValueAccessErrorKind::InvalidBson { message },
-            },
+    pub(crate) fn value_access_invalid_bson(message: String) -> Self {
+        ErrorKind::ValueAccess {
+            kind: ValueAccessErrorKind::InvalidBson { message },
+        }
+        .into()
+    }
+
+    pub(crate) fn malformed_value(message: impl ToString) -> Self {
+        ErrorKind::MalformedValue {
+            message: message.to_string(),
         }
+        .into()
     }
 
     #[cfg(test)]
diff --git a/src/raw.rs b/src/raw.rs
index 364e45d5..252832c2 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -30,7 +30,7 @@
 //!   elem.as_str(),
 //!   Some("y'all"),
 //! );
-//! # Ok::<(), bson::raw::Error>(())
+//! # Ok::<(), bson::error::Error>(())
 //! ```
 //!
 //! ### [`crate::Document`] interop
@@ -109,7 +109,7 @@
 //! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?;
 //! assert_eq!(key, "year");
 //! assert_eq!(value.as_str(), Some("2021"));
-//! # Ok::<(), bson::raw::Error>(())
+//! # Ok::<(), bson::error::Error>(())
 //! ```
 
 mod array;
@@ -118,7 +118,6 @@ mod bson;
 mod bson_ref;
 mod document;
 mod document_buf;
-mod error;
 mod iter;
 pub(crate) mod serde;
 #[cfg(test)]
@@ -126,7 +125,10 @@ mod test;
 
 use std::convert::{TryFrom, TryInto};
 
-use crate::de::MIN_BSON_STRING_SIZE;
+use crate::{
+    de::MIN_BSON_STRING_SIZE,
+    error::{Error, ErrorKind, Result},
+};
 
 pub use self::{
     array::{RawArray, RawArrayIter},
@@ -141,7 +143,6 @@ pub use self::{
     },
     document::RawDocument,
     document_buf::{BindRawBsonRef, RawDocumentBuf},
-    error::{Error, ErrorKind, Result},
     iter::{RawElement, RawIter},
 };
 
@@ -163,7 +164,7 @@ fn f64_from_slice(val: &[u8]) -> Result<f64> {
         .get(0..8)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed(format!(
+            Error::malformed_value(format!(
                 "expected 8 bytes to read double, instead got {}",
                 val.len()
             ))
@@ -178,7 +179,7 @@ fn i32_from_slice(val: &[u8]) -> Result<i32> {
         .get(0..4)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed(format!(
+            Error::malformed_value(format!(
                 "expected 4 bytes to read i32, instead got {}",
                 val.len()
             ))
@@ -193,7 +194,7 @@ fn i64_from_slice(val: &[u8]) -> Result<i64> {
         .get(0..8)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed(format!(
+            Error::malformed_value(format!(
                 "expected 8 bytes to read i64, instead got {}",
                 val.len()
             ))
@@ -206,7 +207,7 @@ fn u8_from_slice(val: &[u8]) -> Result<u8> {
         .get(0..1)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed(format!(
+            Error::malformed_value(format!(
                 "expected 1 byte to read u8, instead got {}",
                 val.len()
             ))
@@ -217,7 +218,7 @@ fn u8_from_slice(val: &[u8]) -> Result<u8> {
 pub(crate) fn bool_from_slice(val: &[u8]) -> Result<bool> {
     let val = u8_from_slice(val)?;
     if val > 1 {
-        return Err(Error::malformed(format!(
+        return Err(Error::malformed_value(format!(
             "boolean must be stored as 0 or 1, got {}",
             val
         )));
@@ -228,7 +229,7 @@ pub(crate) fn bool_from_slice(val: &[u8]) -> Result<bool> {
 
 fn read_len(buf: &[u8]) -> Result<usize> {
     if buf.len() < 4 {
-        return Err(Error::malformed(format!(
+        return Err(Error::malformed_value(format!(
             "expected buffer with string to contain at least 4 bytes, but it only has {}",
             buf.len()
         )));
@@ -238,14 +239,14 @@ fn read_len(buf: &[u8]) -> Result<usize> {
     let end = checked_add(usize_try_from_i32(length)?, 4)?;
 
     if end < MIN_BSON_STRING_SIZE as usize {
-        return Err(Error::malformed(format!(
+        return Err(Error::malformed_value(format!(
             "BSON length encoded string needs to be at least {} bytes, instead got {}",
             MIN_BSON_STRING_SIZE, end
         )));
     }
 
     if buf.len() < end {
-        return Err(Error::malformed(format!(
+        return Err(Error::malformed_value(format!(
             "expected buffer to contain at least {} bytes, but it only has {}",
             end,
             buf.len()
@@ -253,7 +254,9 @@ fn read_len(buf: &[u8]) -> Result<usize> {
     }
 
     if buf[end - 1] != 0 {
-        return Err(Error::malformed("expected string to be null-terminated"));
+        return Err(Error::malformed_value(
+            "expected string to be null-terminated",
+        ));
     }
 
     Ok(length as usize + 4)
@@ -271,14 +274,14 @@ fn read_lenencode(buf: &[u8]) -> Result<&str> {
 }
 
 fn try_to_str(data: &[u8]) -> Result<&str> {
-    simdutf8::basic::from_utf8(data).map_err(|_| Error::new(ErrorKind::Utf8EncodingError))
+    simdutf8::basic::from_utf8(data).map_err(|_| ErrorKind::Utf8Encoding.into())
 }
 
 fn usize_try_from_i32(i: i32) -> Result<usize> {
-    usize::try_from(i).map_err(Error::malformed)
+    usize::try_from(i).map_err(Error::malformed_value)
 }
 
 fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
     lhs.checked_add(rhs)
-        .ok_or_else(|| Error::malformed("attempted to add with overflow"))
+        .ok_or_else(|| Error::malformed_value("attempted to add with overflow"))
 }
diff --git a/src/raw/array.rs b/src/raw/array.rs
index ce2232eb..4f2f47ba 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -115,15 +115,15 @@ impl RawArray {
     ) -> Result<T> {
         let bson = self
             .get(index)
-            .map_err(|e| Error::value_access_invalid_bson(index.to_string(), format!("{:?}", e)))?
-            .ok_or_else(|| Error::value_access_not_present(index.to_string()))?;
+            .map_err(|e| Error::value_access_invalid_bson(format!("{:?}", e)))?
+            .ok_or_else(Error::value_access_not_present)
+            .map_err(|e| e.with_index(index))?;
         match f(bson) {
             Some(t) => Ok(t),
-            None => Err(Error::value_access_unexpected_type(
-                index.to_string(),
-                bson.element_type(),
-                expected_type,
-            )),
+            None => Err(
+                Error::value_access_unexpected_type(bson.element_type(), expected_type)
+                    .with_index(index),
+            ),
         }
     }
 
diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index d9969d99..b8ac1f06 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -17,7 +17,7 @@ use super::{document_buf::BindRawBsonRef, serde::OwnedOrBorrowedRawArray, RawArr
 /// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`](crate::raw::RawBson)
 /// value that borrows from the original document without making any additional allocations.
 /// ```
-/// # use bson::raw::Error;
+/// # use bson::error::Error;
 /// use bson::raw::RawArrayBuf;
 ///
 /// let mut array = RawArrayBuf::new();
@@ -67,7 +67,7 @@ impl RawArrayBuf {
     /// Append a value to the end of the array.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::raw::{RawArrayBuf, RawDocumentBuf};
     ///
     /// let mut array = RawArrayBuf::new();
diff --git a/src/raw/document.rs b/src/raw/document.rs
index c39276f3..468a3da0 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -8,7 +8,7 @@ use serde::{ser::SerializeMap, Deserialize, Serialize};
 use crate::{
     de::MIN_BSON_DOCUMENT_SIZE,
     error::{Error, Result},
-    raw::{error::ErrorKind, serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE},
+    raw::{serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE},
     DateTime,
     Timestamp,
 };
@@ -42,7 +42,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document};
 /// Iterating over a [`RawDocument`] 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::error::Error;
 /// use bson::raw::RawDocument;
 ///
 /// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?;
@@ -89,38 +89,23 @@ impl RawDocument {
     /// use bson::raw::RawDocument;
     ///
     /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?;
-    /// # Ok::<(), bson::raw::Error>(())
+    /// # Ok::<(), bson::error::Error>(())
     /// ```
     pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
         let data = data.as_ref();
 
         if data.len() < 5 {
-            return Err(RawError {
-                key: None,
-                kind: ErrorKind::MalformedValue {
-                    message: "document too short".into(),
-                },
-            });
+            return Err(Error::malformed_value("document too short"));
         }
 
         let length = i32_from_slice(data)?;
 
         if data.len() as i32 != length {
-            return Err(RawError {
-                key: None,
-                kind: ErrorKind::MalformedValue {
-                    message: "document length incorrect".into(),
-                },
-            });
+            return Err(Error::malformed_value("document length incorrect"));
         }
 
         if data[data.len() - 1] != 0 {
-            return Err(RawError {
-                key: None,
-                kind: ErrorKind::MalformedValue {
-                    message: "document not null-terminated".into(),
-                },
-            });
+            return Err(Error::malformed_value("document not null-terminated"));
         }
 
         Ok(RawDocument::new_unchecked(data))
@@ -143,12 +128,12 @@ impl RawDocument {
     /// Creates a new [`RawDocumentBuf`] with an owned copy of the BSON bytes.
     ///
     /// ```
-    /// use bson::raw::{RawDocument, RawDocumentBuf, Error};
+    /// use bson::raw::{RawDocument, RawDocumentBuf};
     ///
     /// let data = b"\x05\0\0\0\0";
     /// let doc_ref = RawDocument::from_bytes(data)?;
     /// let doc: RawDocumentBuf = doc_ref.to_raw_document_buf();
-    /// # Ok::<(), Error>(())
+    /// # Ok::<(), bson::error::Error>(())
     pub fn to_raw_document_buf(&self) -> RawDocumentBuf {
         // unwrap is ok here because we already verified the bytes in `RawDocumentRef::new`
         RawDocumentBuf::from_bytes(self.data.to_owned()).unwrap()
@@ -158,7 +143,7 @@ impl RawDocument {
     /// found.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::{rawdoc, oid::ObjectId};
     ///
     /// let doc = rawdoc! {
@@ -211,15 +196,15 @@ impl RawDocument {
 
         let bson = self
             .get(key)
-            .map_err(|e| Error::value_access_invalid_bson(key, format!("{:?}", e)))?
-            .ok_or_else(|| Error::value_access_not_present(key))?;
+            .map_err(|e| Error::value_access_invalid_bson(format!("{:?}", e)))?
+            .ok_or_else(Error::value_access_not_present)
+            .map_err(|e| e.with_key(key))?;
         match f(bson) {
             Some(t) => Ok(t),
-            None => Err(Error::value_access_unexpected_type(
-                key,
-                bson.element_type(),
-                expected_type,
-            )),
+            None => Err(
+                Error::value_access_unexpected_type(bson.element_type(), expected_type)
+                    .with_key(key),
+            ),
         }
     }
 
@@ -227,7 +212,7 @@ impl RawDocument {
     /// if the key corresponds to a value which isn't a double.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
@@ -268,7 +253,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't a document.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
@@ -337,7 +322,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't an ObjectId.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::{rawdoc, oid::ObjectId};
     ///
     /// let doc = rawdoc! {
@@ -358,7 +343,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't a boolean.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::{rawdoc, oid::ObjectId};
     ///
     /// let doc = rawdoc! {
@@ -379,7 +364,7 @@ impl RawDocument {
     /// error if the key corresponds to a value which isn't a DateTime.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::{rawdoc, DateTime};
     ///
     /// let dt = DateTime::now();
@@ -425,7 +410,7 @@ impl RawDocument {
     /// error if the key corresponds to a value which isn't a timestamp.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::{rawdoc, Timestamp};
     ///
     /// let doc = rawdoc! {
@@ -449,7 +434,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't a 32-bit integer.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
@@ -470,7 +455,7 @@ impl RawDocument {
     /// the key corresponds to a value which isn't a 64-bit integer.
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::rawdoc;
     ///
     /// let doc = rawdoc! {
@@ -490,7 +475,7 @@ impl RawDocument {
     /// Return a reference to the contained data as a `&[u8]`
     ///
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::rawdoc;
     /// let docbuf = rawdoc! {};
     /// assert_eq!(docbuf.as_bytes(), b"\x05\x00\x00\x00\x00");
@@ -511,11 +496,11 @@ impl RawDocument {
         let mut splits = buf.splitn(2, |x| *x == 0);
         let value = splits
             .next()
-            .ok_or_else(|| RawError::malformed("no value"))?;
+            .ok_or_else(|| RawError::malformed_value("no value"))?;
         if splits.next().is_some() {
             Ok(value)
         } else {
-            Err(RawError::malformed("expected null terminator"))
+            Err(RawError::malformed_value("expected null terminator"))
         }
     }
 
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 7a3e0dca..07b0fdae 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -14,7 +14,6 @@ use super::{
     iter::Iter,
     serde::OwnedOrBorrowedRawDocument,
     Error,
-    ErrorKind,
     RawBsonRef,
     RawDocument,
     RawIter,
@@ -34,7 +33,7 @@ mod raw_writer;
 /// the original document without making any additional allocations.
 ///
 /// ```
-/// # use bson::raw::Error;
+/// # use bson::error::Error;
 /// use bson::raw::RawDocumentBuf;
 ///
 /// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?;
@@ -86,9 +85,9 @@ impl RawDocumentBuf {
     /// the RawDocument will return Errors where appropriate.
     ///
     /// ```
-    /// # use bson::raw::{RawDocumentBuf, Error};
+    /// # use bson::raw::RawDocumentBuf;
     /// let doc = RawDocumentBuf::from_bytes(b"\x05\0\0\0\0".to_vec())?;
-    /// # Ok::<(), Error>(())
+    /// # Ok::<(), bson::error::Error>(())
     /// ```
     pub fn from_bytes(data: Vec<u8>) -> Result<RawDocumentBuf> {
         let _ = RawDocument::from_bytes(data.as_slice())?;
@@ -98,7 +97,6 @@ impl RawDocumentBuf {
     /// Create a [`RawDocumentBuf`] from a [`Document`].
     ///
     /// ```
-    /// # use bson::raw::Error;
     /// use bson::{doc, oid::ObjectId, raw::RawDocumentBuf};
     ///
     /// let document = doc! {
@@ -107,16 +105,11 @@ impl RawDocumentBuf {
     ///     "title": "Moby-Dick",
     /// };
     /// let doc = RawDocumentBuf::from_document(&document)?;
-    /// # Ok::<(), Error>(())
+    /// # Ok::<(), bson::error::Error>(())
     /// ```
     pub fn from_document(doc: &Document) -> Result<RawDocumentBuf> {
         let mut data = Vec::new();
-        doc.to_writer(&mut data).map_err(|e| Error {
-            key: None,
-            kind: ErrorKind::MalformedValue {
-                message: e.to_string(),
-            },
-        })?;
+        doc.to_writer(&mut data).map_err(Error::malformed_value)?;
 
         Ok(Self { data })
     }
@@ -125,7 +118,6 @@ impl RawDocumentBuf {
     /// `Result<(&str, RawBson<'_>)>`.
     ///
     /// ```
-    /// # use bson::raw::Error;
     /// use bson::{doc, raw::RawDocumentBuf};
     ///
     /// let doc = RawDocumentBuf::from_document(&doc! { "ferris": true })?;
@@ -135,7 +127,7 @@ impl RawDocumentBuf {
     ///     assert_eq!(key, "ferris");
     ///     assert_eq!(value.as_bool(), Some(true));
     /// }
-    /// # Ok::<(), Error>(())
+    /// # Ok::<(), bson::error::Error>(())
     /// ```
     ///
     /// # Note:
@@ -170,12 +162,11 @@ impl RawDocumentBuf {
     /// Return the contained data as a `Vec<u8>`
     ///
     /// ```
-    /// # use bson::raw::Error;
     /// use bson::{doc, raw::RawDocumentBuf};
     ///
     /// let doc = RawDocumentBuf::from_document(&doc!{})?;
     /// assert_eq!(doc.into_bytes(), b"\x05\x00\x00\x00\x00".to_vec());
-    /// # Ok::<(), Error>(())
+    /// # Ok::<(), bson::error::Error>(())
     /// ```
     pub fn into_bytes(self) -> Vec<u8> {
         self.data
@@ -192,7 +183,7 @@ impl RawDocumentBuf {
     /// Values can be any type that can be converted to either borrowed or owned raw bson data; see
     /// the documentation for [BindRawBsonRef] for more details.
     /// ```
-    /// # use bson::raw::Error;
+    /// # use bson::error::Error;
     /// use bson::{doc, raw::{RawBsonRef, RawDocumentBuf}};
     ///
     /// let mut doc = RawDocumentBuf::new();
diff --git a/src/raw/error.rs b/src/raw/error.rs
deleted file mode 100644
index 10f3a8f6..00000000
--- a/src/raw/error.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-/// An error that occurs when attempting to parse raw BSON bytes.
-#[derive(Debug, PartialEq, Clone)]
-#[non_exhaustive]
-pub struct Error {
-    /// The type of error that was encountered.
-    pub kind: ErrorKind,
-
-    /// They key associated with the error, if any.
-    pub(crate) key: Option<String>,
-}
-
-impl Error {
-    pub(crate) fn new(kind: ErrorKind) -> Self {
-        Self { key: None, kind }
-    }
-
-    pub(crate) fn malformed(e: impl ToString) -> Self {
-        Self::new(ErrorKind::MalformedValue {
-            message: e.to_string(),
-        })
-    }
-
-    pub(crate) fn with_key(mut self, key: impl Into<String>) -> Self {
-        self.key = Some(key.into());
-        self
-    }
-
-    /// The key at which the error was encountered, if any.
-    pub fn key(&self) -> Option<&str> {
-        self.key.as_deref()
-    }
-}
-
-/// The different categories of errors that can be returned when reading from raw BSON.
-#[derive(Clone, Debug, PartialEq)]
-#[non_exhaustive]
-pub enum ErrorKind {
-    /// A BSON value did not fit the proper format.
-    #[non_exhaustive]
-    MalformedValue { message: String },
-
-    /// Improper UTF-8 bytes were found when proper UTF-8 was expected.
-    Utf8EncodingError,
-}
-
-impl std::fmt::Display for Error {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        let p = self
-            .key
-            .as_ref()
-            .map(|k| format!("error at key \"{}\": ", k));
-
-        let prefix = p.as_ref().map_or("", |p| p.as_str());
-
-        match &self.kind {
-            ErrorKind::MalformedValue { message } => {
-                write!(f, "{}malformed value: {:?}", prefix, message)
-            }
-            ErrorKind::Utf8EncodingError => write!(f, "{}utf-8 encoding error", prefix),
-        }
-    }
-}
-
-impl std::error::Error for Error {}
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-/// Execute the provided closure, mapping the key of the returned error (if any) to the provided
-/// key.
-pub(crate) fn try_with_key<G, F: FnOnce() -> Result<G>>(key: impl Into<String>, f: F) -> Result<G> {
-    f().map_err(|e| e.with_key(key))
-}
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 9082dada..9a4150dc 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -20,7 +20,6 @@ use crate::{
 use super::{
     bool_from_slice,
     checked_add,
-    error::try_with_key,
     f64_from_slice,
     i32_from_slice,
     i64_from_slice,
@@ -82,7 +81,7 @@ impl<'a> RawIter<'a> {
     fn verify_enough_bytes(&self, start: usize, num_bytes: usize) -> Result<()> {
         let end = checked_add(start, num_bytes)?;
         if self.doc.as_bytes().get(start..end).is_none() {
-            return Err(Error::malformed(format!(
+            return Err(Error::malformed_value(format!(
                 "length exceeds remaining length of buffer: {} vs {}",
                 num_bytes,
                 self.doc.as_bytes().len() - start
@@ -96,7 +95,7 @@ impl<'a> RawIter<'a> {
         let size = i32_from_slice(&self.doc.as_bytes()[starting_at..])? as usize;
 
         if size < MIN_BSON_DOCUMENT_SIZE as usize {
-            return Err(Error::malformed(format!(
+            return Err(Error::malformed_value(format!(
                 "document too small: {} bytes",
                 size
             )));
@@ -105,7 +104,7 @@ impl<'a> RawIter<'a> {
         self.verify_enough_bytes(starting_at, size)?;
 
         if self.doc.as_bytes()[starting_at + size - 1] != 0 {
-            return Err(Error::malformed("not null terminated"));
+            return Err(Error::malformed_value("not null terminated"));
         }
         Ok(size)
     }
@@ -308,7 +307,7 @@ impl<'a> RawElement<'a> {
     }
 
     fn malformed_error(&self, e: impl ToString) -> Error {
-        Error::malformed(e).with_key(self.key)
+        Error::malformed_value(e).with_key(self.key)
     }
 
     pub(crate) fn slice(&self) -> &'a [u8] {
@@ -335,7 +334,7 @@ impl<'a> RawElement<'a> {
         Ok(ObjectId::from_bytes(
             self.doc.as_bytes()[start_at..(start_at + 12)]
                 .try_into()
-                .map_err(|e| Error::malformed(e).with_key(self.key))?,
+                .map_err(|e| Error::malformed_value(e).with_key(self.key))?,
         ))
     }
 }
@@ -344,11 +343,56 @@ impl RawIter<'_> {
     fn get_next_length_at(&self, start_at: usize) -> Result<usize> {
         let len = i32_from_slice(&self.doc.as_bytes()[start_at..])?;
         if len < 0 {
-            Err(Error::malformed("lengths can't be negative"))
+            Err(Error::malformed_value("lengths can't be negative"))
         } else {
             Ok(len as usize)
         }
     }
+
+    fn get_next_kvp(&mut self, offset: usize) -> Result<(ElementType, usize)> {
+        let element_type = match ElementType::from(self.doc.as_bytes()[self.offset]) {
+            Some(et) => et,
+            None => {
+                return Err(Error::malformed_value(format!(
+                    "invalid tag: {}",
+                    self.doc.as_bytes()[self.offset]
+                )));
+            }
+        };
+
+        let element_size = match element_type {
+            ElementType::Boolean => 1,
+            ElementType::Int32 => 4,
+            ElementType::Int64 => 8,
+            ElementType::Double => 8,
+            ElementType::DateTime => 8,
+            ElementType::Timestamp => 8,
+            ElementType::ObjectId => 12,
+            ElementType::Decimal128 => 16,
+            ElementType::Null => 0,
+            ElementType::Undefined => 0,
+            ElementType::MinKey => 0,
+            ElementType::MaxKey => 0,
+            ElementType::String => read_len(&self.doc.as_bytes()[offset..])?,
+            ElementType::EmbeddedDocument => self.next_document_len(offset)?,
+            ElementType::Array => self.next_document_len(offset)?,
+            ElementType::Binary => self.get_next_length_at(offset)? + 4 + 1,
+            ElementType::RegularExpression => {
+                let pattern = self.doc.read_cstring_at(offset)?;
+                let options = self.doc.read_cstring_at(offset + pattern.len() + 1)?;
+                pattern.len() + 1 + options.len() + 1
+            }
+            ElementType::DbPointer => read_len(&self.doc.as_bytes()[offset..])? + 12,
+            ElementType::Symbol => read_len(&self.doc.as_bytes()[offset..])?,
+            ElementType::JavaScriptCode => read_len(&self.doc.as_bytes()[offset..])?,
+            ElementType::JavaScriptCodeWithScope => self.get_next_length_at(offset)?,
+        };
+
+        self.verify_enough_bytes(offset, element_size)?;
+        self.offset = offset + element_size;
+
+        Ok((element_type, element_size))
+    }
 }
 
 impl<'a> Iterator for RawIter<'a> {
@@ -363,11 +407,11 @@ impl<'a> Iterator for RawIter<'a> {
                 return None;
             } else {
                 self.valid = false;
-                return Some(Err(Error::malformed("document not null terminated")));
+                return Some(Err(Error::malformed_value("document not null terminated")));
             }
         } else if self.offset >= self.doc.as_bytes().len() {
             self.valid = false;
-            return Some(Err(Error::malformed("iteration overflowed document")));
+            return Some(Err(Error::malformed_value("iteration overflowed document")));
         }
 
         let key = match self.doc.read_cstring_at(self.offset + 1) {
@@ -377,59 +421,9 @@ impl<'a> Iterator for RawIter<'a> {
                 return Some(Err(e));
             }
         };
-
         let offset = self.offset + 1 + key.len() + 1; // type specifier + key + \0
-        let kvp_result = try_with_key(key, || {
-            let element_type = match ElementType::from(self.doc.as_bytes()[self.offset]) {
-                Some(et) => et,
-                None => {
-                    return Err(Error::malformed(format!(
-                        "invalid tag: {}",
-                        self.doc.as_bytes()[self.offset]
-                    ))
-                    .with_key(key))
-                }
-            };
-
-            let element_size = match element_type {
-                ElementType::Boolean => 1,
-                ElementType::Int32 => 4,
-                ElementType::Int64 => 8,
-                ElementType::Double => 8,
-                ElementType::DateTime => 8,
-                ElementType::Timestamp => 8,
-                ElementType::ObjectId => 12,
-                ElementType::Decimal128 => 16,
-                ElementType::Null => 0,
-                ElementType::Undefined => 0,
-                ElementType::MinKey => 0,
-                ElementType::MaxKey => 0,
-                ElementType::String => read_len(&self.doc.as_bytes()[offset..])?,
-                ElementType::EmbeddedDocument => self.next_document_len(offset)?,
-                ElementType::Array => self.next_document_len(offset)?,
-                ElementType::Binary => self.get_next_length_at(offset)? + 4 + 1,
-                ElementType::RegularExpression => {
-                    let pattern = self.doc.read_cstring_at(offset)?;
-                    let options = self.doc.read_cstring_at(offset + pattern.len() + 1)?;
-                    pattern.len() + 1 + options.len() + 1
-                }
-                ElementType::DbPointer => read_len(&self.doc.as_bytes()[offset..])? + 12,
-                ElementType::Symbol => read_len(&self.doc.as_bytes()[offset..])?,
-                ElementType::JavaScriptCode => read_len(&self.doc.as_bytes()[offset..])?,
-                ElementType::JavaScriptCodeWithScope => self.get_next_length_at(offset)?,
-            };
-
-            self.verify_enough_bytes(offset, element_size)?;
-            self.offset = offset + element_size;
-
-            Ok((element_type, element_size))
-        });
 
-        if kvp_result.is_err() {
-            self.valid = false;
-        }
-
-        Some(match kvp_result {
+        Some(match self.get_next_kvp(offset) {
             Ok((kind, size)) => Ok(RawElement {
                 key,
                 kind,
@@ -437,7 +431,10 @@ impl<'a> Iterator for RawIter<'a> {
                 start_at: offset,
                 size,
             }),
-            Err(e) => Err(e),
+            Err(error) => {
+                self.valid = false;
+                Err(error.with_key(key))
+            }
         })
     }
 }

From 8389d37175a6e9018ac82dacd62b20415e9c4469 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 9 Jun 2025 12:55:20 -0400
Subject: [PATCH 120/156] RUST-1998 Remove lossy utf8 as a decoder option
 (#550)

---
 src/datetime.rs                              |  7 ---
 src/de.rs                                    | 30 +----------
 src/de/raw.rs                                |  8 +--
 src/document.rs                              | 17 ++-----
 src/error.rs                                 | 15 ++++++
 src/lib.rs                                   |  3 --
 src/raw/array.rs                             | 14 ++++++
 src/raw/document.rs                          | 53 ++++++++++++++++++++
 src/raw/document_buf.rs                      | 17 +++----
 src/raw/iter.rs                              | 28 ++++++++++-
 src/serde_helpers.rs                         | 48 +++++++++++++++++-
 src/tests/modules/serializer_deserializer.rs | 11 ++--
 src/tests/spec/corpus.rs                     | 22 ++++----
 13 files changed, 191 insertions(+), 82 deletions(-)

diff --git a/src/datetime.rs b/src/datetime.rs
index eca1522b..b1394c32 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -386,13 +386,6 @@ impl crate::DateTime {
         }
     }
 
-    #[deprecated(since = "2.3.0", note = "Use try_to_rfc3339_string instead.")]
-    /// Convert this [`DateTime`] to an RFC 3339 formatted string.  Panics if it could not be
-    /// represented in that format.
-    pub fn to_rfc3339_string(self) -> String {
-        self.try_to_rfc3339_string().unwrap()
-    }
-
     /// Convert this [`DateTime`] to an RFC 3339 formatted string.
     pub fn try_to_rfc3339_string(self) -> Result<String> {
         self.to_time_0_3()
diff --git a/src/de.rs b/src/de.rs
index 09ea1f0d..c1e1312a 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -137,40 +137,12 @@ where
     from_slice(bytes.as_slice())
 }
 
-/// Deserialize an instance of type `T` from an I/O stream of BSON, replacing any invalid UTF-8
-/// sequences with the Unicode replacement character.
-///
-/// This is mainly useful when reading raw BSON returned from a MongoDB server, which
-/// in rare cases can contain invalidly truncated strings (<https://jira.mongodb.org/browse/SERVER-24007>).
-/// For most use cases, [`crate::from_reader`] can be used instead.
-pub fn from_reader_utf8_lossy<R, T>(reader: R) -> Result<T>
-where
-    T: DeserializeOwned,
-    R: Read,
-{
-    let bytes = reader_to_vec(reader)?;
-    from_slice_utf8_lossy(bytes.as_slice())
-}
-
 /// Deserialize an instance of type `T` from a slice of BSON bytes.
 pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    from_raw(raw::Deserializer::new(bytes, false)?)
-}
-
-/// Deserialize an instance of type `T` from a slice of BSON bytes, replacing any invalid UTF-8
-/// sequences with the Unicode replacement character.
-///
-/// This is mainly useful when reading raw BSON returned from a MongoDB server, which
-/// in rare cases can contain invalidly truncated strings (<https://jira.mongodb.org/browse/SERVER-24007>).
-/// For most use cases, [`crate::from_slice`] can be used instead.
-pub fn from_slice_utf8_lossy<'de, T>(bytes: &'de [u8]) -> Result<T>
-where
-    T: Deserialize<'de>,
-{
-    from_raw(raw::Deserializer::new(bytes, true)?)
+    from_raw(raw::Deserializer::new(bytes)?)
 }
 
 pub(crate) fn from_raw<'de, T: Deserialize<'de>>(
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 6ec3e437..4f809df1 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -50,11 +50,11 @@ struct DeserializerOptions {
 }
 
 impl<'de> Deserializer<'de> {
-    pub(crate) fn new(buf: &'de [u8], utf8_lossy: bool) -> Result<Self> {
+    pub(crate) fn new(buf: &'de [u8]) -> Result<Self> {
         Ok(Self {
             element: RawElement::toplevel(buf)?,
             options: DeserializerOptions {
-                utf8_lossy,
+                utf8_lossy: false,
                 human_readable: false,
             },
         })
@@ -71,7 +71,7 @@ impl<'de> Deserializer<'de> {
         V: serde::de::Visitor<'de>,
     {
         if self.options.utf8_lossy {
-            if let Some(lossy) = self.element.value_utf8_lossy()? {
+            if let Some(lossy) = self.element.value_utf8_lossy_inner()? {
                 return match lossy {
                     Utf8LossyBson::String(s) => visitor.visit_string(s),
                     Utf8LossyBson::RegularExpression(re) => {
@@ -178,7 +178,7 @@ impl<'de> Deserializer<'de> {
 
     fn get_string(&self) -> Result<Cow<'de, str>> {
         if self.options.utf8_lossy {
-            let value = self.element.value_utf8_lossy()?;
+            let value = self.element.value_utf8_lossy_inner()?;
             let s = match value {
                 Some(Utf8LossyBson::String(s)) => s,
                 _ => {
diff --git a/src/document.rs b/src/document.rs
index 30e49283..eed8213c 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -695,9 +695,9 @@ impl Document {
         Ok(())
     }
 
-    fn decode<R: Read + ?Sized>(reader: &mut R, utf_lossy: bool) -> crate::de::Result<Document> {
+    fn decode<R: Read + ?Sized>(reader: &mut R) -> crate::de::Result<Document> {
         let buf = crate::de::reader_to_vec(reader)?;
-        crate::de::from_raw(crate::de::RawDeserializer::new(&buf, utf_lossy)?)
+        crate::de::from_raw(crate::de::RawDeserializer::new(&buf)?)
     }
 
     /// Attempts to deserialize a [`Document`] from a byte stream.
@@ -729,18 +729,7 @@ impl Document {
     /// # }
     /// ```
     pub fn from_reader<R: Read>(mut reader: R) -> crate::de::Result<Document> {
-        Self::decode(&mut reader, false)
-    }
-
-    /// Attempt to deserialize a [`Document`] that may contain invalid UTF-8 strings from a byte
-    /// stream.
-    ///
-    /// This is mainly useful when reading raw BSON returned from a MongoDB server, which
-    /// in rare cases can contain invalidly truncated strings (<https://jira.mongodb.org/browse/SERVER-24007>).
-    /// For most use cases, `Document::from_reader` can be used instead.
-    #[deprecated = "use bson::serde_helpers::Utf8LossyDeserialization"]
-    pub fn from_reader_utf8_lossy<R: Read>(mut reader: R) -> crate::de::Result<Document> {
-        Self::decode(&mut reader, true)
+        Self::decode(&mut reader)
     }
 }
 
diff --git a/src/error.rs b/src/error.rs
index 58f3e000..d1497760 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -50,6 +50,11 @@ pub enum ErrorKind {
         /// The kind of error that occurred.
         kind: ValueAccessErrorKind,
     },
+
+    /// A wrapped deserialization error.
+    /// TODO RUST-1406: collapse this
+    #[error("Deserialization error")]
+    DeError(crate::de::Error),
 }
 
 impl From<ErrorKind> for Error {
@@ -62,6 +67,16 @@ impl From<ErrorKind> for Error {
     }
 }
 
+impl From<crate::de::Error> for Error {
+    fn from(value: crate::de::Error) -> Self {
+        Self {
+            kind: ErrorKind::DeError(value),
+            key: None,
+            index: None,
+        }
+    }
+}
+
 /// The types of errors that can occur when attempting to access a value in a document.
 #[derive(Debug, Error)]
 #[non_exhaustive]
diff --git a/src/lib.rs b/src/lib.rs
index d06f4601..3780be14 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -308,9 +308,6 @@ pub use self::{
     uuid::{Uuid, UuidRepresentation},
 };
 
-#[allow(deprecated)]
-pub use self::de::{from_reader_utf8_lossy, from_slice_utf8_lossy};
-
 #[macro_use]
 mod macros;
 mod base64;
diff --git a/src/raw/array.rs b/src/raw/array.rs
index 4f2f47ba..a55daa03 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -212,6 +212,20 @@ impl RawArray {
     pub fn is_empty(&self) -> bool {
         self.doc.is_empty()
     }
+
+    /// Gets an iterator over the elements in the [`RawArray`],
+    /// which yields `Result<RawElement<'_>>` values. These hold a
+    /// reference to the underlying array but do not explicitly
+    /// resolve the values.
+    ///
+    /// This iterator, which underpins the implementation of the
+    /// default iterator, produces `RawElement` objects that hold a
+    /// view onto the array but do not parse out or construct
+    /// values until the `.value()` or `.try_into()` methods are
+    /// called.
+    pub fn iter_elements(&self) -> RawIter {
+        RawIter::new(&self.doc)
+    }
 }
 
 impl std::fmt::Debug for RawArray {
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 468a3da0..e62eb62e 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -9,7 +9,11 @@ use crate::{
     de::MIN_BSON_DOCUMENT_SIZE,
     error::{Error, Result},
     raw::{serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE},
+    Bson,
     DateTime,
+    JavaScriptCodeWithScope,
+    RawBson,
+    RawJavaScriptCodeWithScope,
     Timestamp,
 };
 
@@ -508,6 +512,55 @@ impl RawDocument {
         let bytes = self.cstring_bytes_at(start_at)?;
         try_to_str(bytes)
     }
+
+    /// Copy this into a [`Document`], returning an error if invalid BSON is encountered.
+    pub fn to_document(&self) -> RawResult<Document> {
+        self.try_into()
+    }
+
+    /// Copy this into a [`Document`], returning an error if invalid BSON is encountered.  Any
+    /// invalid UTF-8 sequences will be replaced with the Unicode replacement character.
+    pub fn to_document_utf8_lossy(&self) -> RawResult<Document> {
+        let mut out = Document::new();
+        for elem in self.iter_elements() {
+            let elem = elem?;
+            let value = deep_utf8_lossy(elem.value_utf8_lossy()?)?;
+            out.insert(elem.key(), value);
+        }
+        Ok(out)
+    }
+}
+
+fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
+    match src {
+        RawBson::Array(arr) => {
+            let mut tmp = vec![];
+            for elem in arr.iter_elements() {
+                tmp.push(deep_utf8_lossy(elem?.value_utf8_lossy()?)?);
+            }
+            Ok(Bson::Array(tmp))
+        }
+        RawBson::Document(doc) => {
+            let mut tmp = doc! {};
+            for elem in doc.iter_elements() {
+                let elem = elem?;
+                tmp.insert(elem.key(), deep_utf8_lossy(elem.value_utf8_lossy()?)?);
+            }
+            Ok(Bson::Document(tmp))
+        }
+        RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code, scope }) => {
+            let mut tmp = doc! {};
+            for elem in scope.iter_elements() {
+                let elem = elem?;
+                tmp.insert(elem.key(), deep_utf8_lossy(elem.value_utf8_lossy()?)?);
+            }
+            Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
+                code,
+                scope: tmp,
+            }))
+        }
+        v => v.try_into(),
+    }
 }
 
 impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 07b0fdae..e89ef704 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -1,6 +1,6 @@
 use std::{
     borrow::{Borrow, Cow},
-    convert::{TryFrom, TryInto},
+    convert::TryFrom,
     iter::FromIterator,
     ops::Deref,
 };
@@ -65,7 +65,7 @@ pub struct RawDocumentBuf {
 
 impl RawDocumentBuf {
     /// Creates a new, empty [`RawDocumentBuf`].
-    pub fn new() -> RawDocumentBuf {
+    pub fn new() -> Self {
         let mut data = Vec::new();
         data.extend(MIN_BSON_DOCUMENT_SIZE.to_le_bytes());
         data.push(0);
@@ -89,11 +89,16 @@ impl RawDocumentBuf {
     /// let doc = RawDocumentBuf::from_bytes(b"\x05\0\0\0\0".to_vec())?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn from_bytes(data: Vec<u8>) -> Result<RawDocumentBuf> {
+    pub fn from_bytes(data: Vec<u8>) -> Result<Self> {
         let _ = RawDocument::from_bytes(data.as_slice())?;
         Ok(Self { data })
     }
 
+    pub fn from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
+        let buf = crate::de::reader_to_vec(reader)?;
+        Self::from_bytes(buf)
+    }
+
     /// Create a [`RawDocumentBuf`] from a [`Document`].
     ///
     /// ```
@@ -213,12 +218,6 @@ impl RawDocumentBuf {
                 .expect("key should not contain interior null byte")
         })
     }
-
-    /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error
-    /// if invalid BSON is encountered.
-    pub fn to_document(&self) -> Result<Document> {
-        self.as_ref().try_into()
-    }
 }
 
 impl Default for RawDocumentBuf {
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 9a4150dc..62fdc8e6 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -265,7 +265,14 @@ impl<'a> RawElement<'a> {
         })
     }
 
-    pub(crate) fn value_utf8_lossy(&self) -> Result<Option<Utf8LossyBson<'a>>> {
+    pub fn value_utf8_lossy(&self) -> Result<RawBson> {
+        match self.value_utf8_lossy_inner()? {
+            Some(v) => Ok(v.into()),
+            None => Ok(self.value()?.to_raw_bson()),
+        }
+    }
+
+    pub(crate) fn value_utf8_lossy_inner(&self) -> Result<Option<Utf8LossyBson<'a>>> {
         Ok(Some(match self.kind {
             ElementType::String => Utf8LossyBson::String(self.read_utf8_lossy()),
             ElementType::JavaScriptCode => Utf8LossyBson::JavaScriptCode(self.read_utf8_lossy()),
@@ -452,3 +459,22 @@ pub(crate) struct Utf8LossyJavaScriptCodeWithScope<'a> {
     pub(crate) code: String,
     pub(crate) scope: &'a RawDocument,
 }
+
+impl<'a> From<Utf8LossyBson<'a>> for RawBson {
+    fn from(value: Utf8LossyBson<'a>) -> Self {
+        match value {
+            Utf8LossyBson::String(s) => RawBson::String(s),
+            Utf8LossyBson::JavaScriptCode(s) => RawBson::JavaScriptCode(s),
+            Utf8LossyBson::JavaScriptCodeWithScope(Utf8LossyJavaScriptCodeWithScope {
+                code,
+                scope,
+            }) => RawBson::JavaScriptCodeWithScope(super::RawJavaScriptCodeWithScope {
+                code,
+                scope: scope.to_raw_document_buf(),
+            }),
+            Utf8LossyBson::Symbol(s) => RawBson::Symbol(s),
+            Utf8LossyBson::DbPointer(p) => RawBson::DbPointer(p),
+            Utf8LossyBson::RegularExpression(r) => RawBson::RegularExpression(r),
+        }
+    }
+}
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index a8877bdf..6cd1bb25 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -817,7 +817,8 @@ where
 ///
 /// This wrapper type has no impact on serialization. Serializing a `Utf8LossyDeserialization<T>`
 /// will call the `serialize` method for the wrapped `T`.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
+#[repr(transparent)]
 pub struct Utf8LossyDeserialization<T>(pub T);
 
 pub(crate) const UTF8_LOSSY_NEWTYPE: &str = "$__bson_private_utf8_lossy";
@@ -852,3 +853,48 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Utf8LossyDeserialization<T>
         deserializer.deserialize_newtype_struct(UTF8_LOSSY_NEWTYPE, V(PhantomData))
     }
 }
+
+impl<T: std::fmt::Display> std::fmt::Display for Utf8LossyDeserialization<T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl<T> From<T> for Utf8LossyDeserialization<T> {
+    fn from(value: T) -> Self {
+        Self(value)
+    }
+}
+
+impl<T> Deref for Utf8LossyDeserialization<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for Utf8LossyDeserialization<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T, R> AsRef<R> for Utf8LossyDeserialization<T>
+where
+    R: ?Sized,
+    <Utf8LossyDeserialization<T> as Deref>::Target: AsRef<R>,
+{
+    fn as_ref(&self) -> &R {
+        self.deref().as_ref()
+    }
+}
+
+impl<T, R: ?Sized> AsMut<R> for Utf8LossyDeserialization<T>
+where
+    <Utf8LossyDeserialization<T> as Deref>::Target: AsMut<R>,
+{
+    fn as_mut(&mut self) -> &mut R {
+        self.deref_mut().as_mut()
+    }
+}
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 1083e985..63182cde 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -18,6 +18,7 @@ use crate::{
     Decimal128,
     Document,
     JavaScriptCodeWithScope,
+    RawDocumentBuf,
     Regex,
     Timestamp,
 };
@@ -67,14 +68,16 @@ fn test_encode_decode_utf8_string_invalid() {
     let bytes = b"\x80\xae".to_vec();
     let src = unsafe { String::from_utf8_unchecked(bytes) };
 
-    let doc = doc! { "key": src };
+    let doc = doc! { "key": &src, "subdoc": { "subkey": &src } };
 
     let mut buf = Vec::new();
     doc.to_writer(&mut buf).unwrap();
 
-    let expected = doc! { "key": "��" };
-    #[allow(deprecated)]
-    let decoded = Document::from_reader_utf8_lossy(&mut Cursor::new(buf)).unwrap();
+    let expected = doc! { "key": "��", "subdoc": { "subkey": "��" } };
+    let decoded = RawDocumentBuf::from_reader(&mut Cursor::new(buf))
+        .unwrap()
+        .to_document_utf8_lossy()
+        .unwrap();
     assert_eq!(decoded, expected);
 }
 
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 93bc3220..1ef1893e 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -182,7 +182,7 @@ fn run_test(test: TestFile) {
             if !description.contains("$regex query operator") {
                 // deserialize the field from raw Bytes into a RawBson
                 let deserializer_raw =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false).unwrap();
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
                 let raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBsonRef>))
                     .expect(&description);
@@ -194,7 +194,7 @@ fn run_test(test: TestFile) {
 
                 // deserialize the field from raw Bytes into an OwnedRawBson
                 let deserializer_raw =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false).unwrap();
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
                 let owned_raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
                     .expect(&description);
@@ -203,7 +203,7 @@ fn run_test(test: TestFile) {
 
                 // deserialize the field from raw Bytes into a Bson
                 let deserializer_value =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false).unwrap();
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
                 let bson_field = deserializer_value
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<Bson>))
                     .expect(&description);
@@ -555,13 +555,15 @@ fn run_test(test: TestFile) {
         crate::from_reader::<_, Document>(bson.as_slice()).expect_err(description.as_str());
 
         if decode_error.description.contains("invalid UTF-8") {
-            #[allow(deprecated)]
-            crate::from_reader_utf8_lossy::<_, Document>(bson.as_slice()).unwrap_or_else(|err| {
-                panic!(
-                    "{}: utf8_lossy should not fail (failed with {:?})",
-                    description, err
-                )
-            });
+            RawDocumentBuf::from_reader(bson.as_slice())
+                .expect(&description)
+                .to_document_utf8_lossy()
+                .unwrap_or_else(|err| {
+                    panic!(
+                        "{}: utf8_lossy should not fail (failed with {:?})",
+                        description, err
+                    )
+                });
             crate::from_slice::<Utf8LossyDeserialization<Document>>(bson.as_slice())
                 .expect(&description);
         }

From 2b693609261b6bbc3560d5abf8f62bd8e278c9e5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 16 Jun 2025 09:55:46 -0400
Subject: [PATCH 121/156] Bump the rust-dependencies group with 8 updates
 (#556)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 73 +++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 56 insertions(+), 17 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index b157ab2b..64fbbcaa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -160,18 +160,18 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.26"
+version = "1.2.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
+checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
 dependencies = [
  "shlex",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
 
 [[package]]
 name = "chrono"
@@ -346,6 +346,12 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 
+[[package]]
+name = "dyn-clone"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
+
 [[package]]
 name = "either"
 version = "1.15.0"
@@ -395,7 +401,7 @@ dependencies = [
  "cfg-if",
  "js-sys",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi 0.11.1+wasi-snapshot-preview1",
  "wasm-bindgen",
 ]
 
@@ -531,9 +537,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.172"
+version = "0.2.173"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb"
 
 [[package]]
 name = "linux-raw-sys"
@@ -549,9 +555,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
 
 [[package]]
 name = "num-conv"
@@ -758,6 +764,26 @@ dependencies = [
  "crossbeam-utils",
 ]
 
+[[package]]
+name = "ref-cast"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
 [[package]]
 name = "regex"
 version = "1.11.1"
@@ -833,6 +859,18 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "schemars"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "serde"
 version = "1.0.219"
@@ -897,15 +935,16 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.12.0"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
+checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42"
 dependencies = [
  "base64",
  "chrono",
  "hex",
  "indexmap 1.9.3",
  "indexmap 2.9.0",
+ "schemars",
  "serde",
  "serde_derive",
  "serde_json",
@@ -915,9 +954,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.12.0"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
+checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -1111,9 +1150,9 @@ dependencies = [
 
 [[package]]
 name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
 
 [[package]]
 name = "wasi"
@@ -1260,9 +1299,9 @@ dependencies = [
 
 [[package]]
 name = "windows-link"
-version = "0.1.1"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
 
 [[package]]
 name = "windows-result"

From 5f54ac51f748d56ca7e8ee7dca4a75b133024e85 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Tue, 17 Jun 2025 11:35:19 -0400
Subject: [PATCH 122/156] RUST-1869 Rename `RawElement::len` to
 `RawElement::size` (#557)

---
 src/raw/iter.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 62fdc8e6..8dddbf5b 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -143,7 +143,6 @@ impl TryInto<Bson> for RawElement<'_> {
     }
 }
 
-#[allow(clippy::len_without_is_empty)]
 impl<'a> RawElement<'a> {
     pub(crate) fn toplevel(bytes: &'a [u8]) -> Result<Self> {
         let doc = RawDocument::from_bytes(bytes)?;
@@ -155,7 +154,8 @@ impl<'a> RawElement<'a> {
             size: doc.as_bytes().len(),
         })
     }
-    pub fn len(&self) -> usize {
+
+    pub fn size(&self) -> usize {
         self.size
     }
 

From 1669bc07652999f15e15d73ba658e63c0dace815 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 17 Jun 2025 15:38:30 -0400
Subject: [PATCH 123/156] RUST-1992 Make serde an optional feature (#554)

Co-authored-by: Isabel Atkinson <isabelatkinson@gmail.com>
---
 .evergreen/run-fuzzer.sh                      |   5 +-
 .evergreen/run-tests.sh                       |   4 +-
 Cargo.toml                                    |   3 +-
 examples/deserialize.rs                       |  11 -
 examples/serialize.rs                         |  26 ---
 examples/test.bson                            | Bin 316 -> 0 bytes
 fuzz/.gitignore                               |   1 +
 fuzz/Cargo.toml                               |   9 +-
 .../{deserialize.rs => decode.rs}             |   4 +-
 .../{serialization.rs => encoding.rs}         |  15 +-
 fuzz/fuzz_targets/iterate.rs                  |   2 +-
 fuzz/fuzz_targets/raw_deserialize.rs          |   5 +-
 .../raw_deserialize_utf8_lossy.rs             |  10 +-
 fuzz/fuzz_targets/string_handling.rs          |   2 +-
 fuzz/fuzz_targets/type_markers.rs             |   2 +-
 fuzz/generate_corpus.rs                       |  24 ++-
 serde-tests/Cargo.toml                        |   2 +-
 serde-tests/json.rs                           |  16 +-
 serde-tests/test.rs                           | 102 +++++-----
 src/binary.rs                                 |   6 +-
 src/binary/vector.rs                          |  12 +-
 src/bson.rs                                   |  18 +-
 src/datetime.rs                               |   8 +-
 src/de.rs                                     |  65 ++----
 src/decimal128.rs                             |   1 +
 src/document.rs                               |  33 +--
 src/error.rs                                  |  25 ++-
 src/lib.rs                                    |  31 ++-
 src/macros.rs                                 |   8 +-
 src/oid.rs                                    |   4 +-
 src/raw.rs                                    |  57 +++++-
 src/raw/array.rs                              |  25 +--
 src/raw/array_buf.rs                          |  64 ++++--
 src/raw/bson.rs                               |  43 ++--
 src/raw/bson_ref.rs                           |  69 ++++---
 src/raw/document.rs                           |  45 ++--
 src/raw/document_buf.rs                       | 107 +++++-----
 src/raw/document_buf/raw_writer.rs            |   4 +-
 src/raw/iter.rs                               |  27 +--
 src/raw/serde.rs                              |  12 +-
 src/raw/serde/bson_visitor.rs                 |   4 +-
 src/raw/serde/seeded_visitor.rs               |   6 +-
 src/raw/test.rs                               |  30 ++-
 src/raw/test/append.rs                        | 192 +++++++++---------
 src/ser.rs                                    |  43 ++--
 src/ser/error.rs                              |  16 +-
 src/ser/raw.rs                                |   4 +-
 src/ser/raw/document_serializer.rs            |   9 +-
 src/ser/raw/value_serializer.rs               |   6 +-
 src/ser/serde.rs                              |   3 +-
 src/tests.rs                                  |   3 +
 src/tests/modules.rs                          |   2 +
 src/tests/modules/bson.rs                     |  27 ++-
 src/tests/modules/macros.rs                   |  91 +++++----
 src/tests/modules/ser.rs                      |  89 ++++----
 src/tests/modules/serializer_deserializer.rs  | 118 +++++------
 src/tests/serde.rs                            | 156 +++++++-------
 src/tests/serde_helpers.rs                    |  29 +--
 src/tests/spec/corpus.rs                      |  92 +++++----
 src/tests/spec/vector.rs                      |  19 +-
 src/uuid.rs                                   |  23 ++-
 src/uuid/test.rs                              |  52 ++---
 62 files changed, 1016 insertions(+), 905 deletions(-)
 delete mode 100644 examples/deserialize.rs
 delete mode 100644 examples/serialize.rs
 delete mode 100644 examples/test.bson
 rename fuzz/fuzz_targets/{deserialize.rs => decode.rs} (61%)
 rename fuzz/fuzz_targets/{serialization.rs => encoding.rs} (75%)

diff --git a/.evergreen/run-fuzzer.sh b/.evergreen/run-fuzzer.sh
index 559913d2..9a3e8c27 100755
--- a/.evergreen/run-fuzzer.sh
+++ b/.evergreen/run-fuzzer.sh
@@ -30,11 +30,12 @@ run_fuzzer() {
 }
 
 # Run existing targets
-run_fuzzer "deserialize"
+run_fuzzer "decode"
 run_fuzzer "raw_deserialize"
+run_fuzzer "raw_deserialize_utf8_lossy"
 run_fuzzer "iterate"
 
 # Run new security-focused targets
 run_fuzzer "type_markers"
 run_fuzzer "string_handling"
-run_fuzzer "serialization"
+run_fuzzer "encoding"
diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh
index 56c57f23..5b01e50f 100755
--- a/.evergreen/run-tests.sh
+++ b/.evergreen/run-tests.sh
@@ -4,7 +4,9 @@ set -o errexit
 
 . ~/.cargo/env
 
-RUST_BACKTRACE=1 cargo test
+# Test with default features and excluding doctests (some of which require the 'serde' feature)
+RUST_BACKTRACE=1 cargo test --all-targets
+# Test with all features and including doctests
 RUST_BACKTRACE=1 cargo test --all-features
 
 cd serde-tests
diff --git a/Cargo.toml b/Cargo.toml
index c772468c..abff6263 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -47,6 +47,7 @@ serde_path_to_error = ["dep:serde_path_to_error"]
 # if enabled, include serde_with interop.
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
 serde_with-3 = ["dep:serde_with"]
+serde = ["dep:serde"]
 
 [lib]
 name = "bson"
@@ -55,7 +56,7 @@ name = "bson"
 ahash = "0.8.0"
 chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
 rand = "0.9"
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0", features = ["derive"], optional = true }
 serde_json = { version = "1.0", features = ["preserve_order"] }
 indexmap = "2.1.0"
 hex = "0.4.2"
diff --git a/examples/deserialize.rs b/examples/deserialize.rs
deleted file mode 100644
index cfb911d2..00000000
--- a/examples/deserialize.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use std::fs::File;
-
-use bson::Document;
-
-fn main() {
-    let mut f = File::open("examples/test.bson").unwrap();
-
-    while let Ok(deserialized) = Document::from_reader(&mut f) {
-        println!("{:?}", deserialized);
-    }
-}
diff --git a/examples/serialize.rs b/examples/serialize.rs
deleted file mode 100644
index 9dbba5a1..00000000
--- a/examples/serialize.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use std::io::Cursor;
-
-use bson::{oid, Bson, DateTime, Document};
-
-fn main() {
-    let mut doc = Document::new();
-    doc.insert("foo".to_string(), Bson::String("bar".to_string()));
-
-    let arr = vec![
-        Bson::String("blah".to_string()),
-        Bson::DateTime(DateTime::now()),
-        Bson::ObjectId(oid::ObjectId::from_bytes([
-            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
-        ])),
-    ];
-
-    doc.insert("array".to_string(), Bson::Array(arr));
-
-    let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
-
-    println!("Serialized: {:?}", buf);
-
-    let doc = Document::from_reader(&mut Cursor::new(&buf[..])).unwrap();
-    println!("Deserialized: {:?}", doc);
-}
diff --git a/examples/test.bson b/examples/test.bson
deleted file mode 100644
index 7b61956312e043583d613522daa098bf14d0ed0c..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/fuzz/.gitignore b/fuzz/.gitignore
index 572e03bd..bf9c8cb7 100644
--- a/fuzz/.gitignore
+++ b/fuzz/.gitignore
@@ -2,3 +2,4 @@
 target
 corpus
 artifacts
+Cargo.lock
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index abd24a57..27a01ff3 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -10,6 +10,7 @@ cargo-fuzz = true
 
 [dependencies.bson]
 path = ".."
+features = ["serde"]
 
 [dependencies.libfuzzer-sys]
 version = "0.4.0"
@@ -24,8 +25,8 @@ version = "1.0"
 members = ["."]
 
 [[bin]]
-name = "deserialize"
-path = "fuzz_targets/deserialize.rs"
+name = "decode"
+path = "fuzz_targets/decode.rs"
 
 [[bin]]
 name = "iterate"
@@ -48,8 +49,8 @@ name = "string_handling"
 path = "fuzz_targets/string_handling.rs"
 
 [[bin]]
-name = "serialization"
-path = "fuzz_targets/serialization.rs"
+name = "encoding"
+path = "fuzz_targets/encoding.rs"
 
 [[bin]]
 name = "generate_corpus"
diff --git a/fuzz/fuzz_targets/deserialize.rs b/fuzz/fuzz_targets/decode.rs
similarity index 61%
rename from fuzz/fuzz_targets/deserialize.rs
rename to fuzz/fuzz_targets/decode.rs
index 4995394d..ef71f959 100644
--- a/fuzz/fuzz_targets/deserialize.rs
+++ b/fuzz/fuzz_targets/decode.rs
@@ -7,8 +7,8 @@ use bson::Document;
 use std::io::Cursor;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = Document::from_reader(&mut Cursor::new(&buf[..])) {
+    if let Ok(doc) = Document::decode_from_reader(&mut Cursor::new(&buf[..])) {
         let mut vec = Vec::with_capacity(buf.len());
-        let _ = doc.to_writer(&mut vec);
+        let _ = doc.encode_to_writer(&mut vec);
     }
 });
diff --git a/fuzz/fuzz_targets/serialization.rs b/fuzz/fuzz_targets/encoding.rs
similarity index 75%
rename from fuzz/fuzz_targets/serialization.rs
rename to fuzz/fuzz_targets/encoding.rs
index ea6b13e5..99e66cda 100644
--- a/fuzz/fuzz_targets/serialization.rs
+++ b/fuzz/fuzz_targets/encoding.rs
@@ -45,20 +45,19 @@ fn compare_values(val1: &Bson, val2: &Bson) -> bool {
 }
 
 fuzz_target!(|input: &[u8]| {
-    if let Ok(rawdoc) = RawDocument::from_bytes(&input) {
+    if let Ok(rawdoc) = RawDocument::decode_from_bytes(&input) {
         if let Ok(doc) = Document::try_from(rawdoc) {
             let out = RawDocumentBuf::try_from(&doc).unwrap();
             let out_bytes = out.as_bytes();
             if input != out_bytes {
-                let reserialized = RawDocument::from_bytes(&out_bytes).unwrap();
-                let reserialized_doc = Document::try_from(reserialized).unwrap();
-                // Ensure that the reserialized document is the same as the original document, the
+                let reencoded = RawDocument::decode_from_bytes(&out_bytes).unwrap();
+                let reencoded_doc = Document::try_from(reencoded).unwrap();
+                // Ensure that the re-encoded document is the same as the original document, the
                 // bytes can differ while still resulting in the same Document.
-                if !compare_docs(&doc, &reserialized_doc) {
+                if !compare_docs(&doc, &reencoded_doc) {
                     panic!(
-                        "Reserialized document is not the same as the original document: {:?} != \
-                         {:?}",
-                        doc, reserialized_doc
+                        "Reencoded document is not the same as the original document: {:?} != {:?}",
+                        doc, reencoded_doc
                     );
                 }
             }
diff --git a/fuzz/fuzz_targets/iterate.rs b/fuzz/fuzz_targets/iterate.rs
index 7dece7ca..8dc9404a 100644
--- a/fuzz/fuzz_targets/iterate.rs
+++ b/fuzz/fuzz_targets/iterate.rs
@@ -5,7 +5,7 @@ extern crate bson;
 use bson::RawDocument;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = RawDocument::from_bytes(buf) {
+    if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
         for _ in doc {}
     }
 });
diff --git a/fuzz/fuzz_targets/raw_deserialize.rs b/fuzz/fuzz_targets/raw_deserialize.rs
index 4fb91b09..3e7e8e18 100644
--- a/fuzz/fuzz_targets/raw_deserialize.rs
+++ b/fuzz/fuzz_targets/raw_deserialize.rs
@@ -5,8 +5,7 @@ extern crate bson;
 use bson::Document;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = bson::from_slice::<Document>(buf) {
-        let mut vec = Vec::with_capacity(buf.len());
-        let _ = doc.to_writer(&mut vec);
+    if let Ok(doc) = bson::deserialize_from_slice::<Document>(buf) {
+        let _ = bson::serialize_to_vec(&doc);
     }
 });
diff --git a/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs b/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
index fb5343b4..cf872965 100644
--- a/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
+++ b/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
@@ -1,11 +1,11 @@
 #![no_main]
-#[macro_use] extern crate libfuzzer_sys;
+#[macro_use]
+extern crate libfuzzer_sys;
 extern crate bson;
-use bson::Document;
+use bson::{serde_helpers::Utf8LossyDeserialization, Document};
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = bson::from_slice_utf8_lossy::<Document>(buf) {
-        let mut vec = Vec::with_capacity(buf.len());
-        let _ = doc.to_writer(&mut vec);
+    if let Ok(doc) = bson::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(buf) {
+        let _ = bson::serialize_to_vec(&doc.0);
     }
 });
diff --git a/fuzz/fuzz_targets/string_handling.rs b/fuzz/fuzz_targets/string_handling.rs
index 090d132f..3b403bd0 100644
--- a/fuzz/fuzz_targets/string_handling.rs
+++ b/fuzz/fuzz_targets/string_handling.rs
@@ -6,7 +6,7 @@ use bson::{RawBsonRef, RawDocument};
 use std::convert::TryInto;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = RawDocument::from_bytes(buf) {
+    if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
         for elem in doc.iter_elements().flatten() {
             // Convert to RawBsonRef and check string-related types
             if let Ok(bson) = elem.try_into() {
diff --git a/fuzz/fuzz_targets/type_markers.rs b/fuzz/fuzz_targets/type_markers.rs
index 3506b96e..f6dd7aa7 100644
--- a/fuzz/fuzz_targets/type_markers.rs
+++ b/fuzz/fuzz_targets/type_markers.rs
@@ -6,7 +6,7 @@ use bson::{RawBsonRef, RawDocument};
 use std::convert::TryInto;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = RawDocument::from_bytes(buf) {
+    if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
         for elem in doc.iter_elements().flatten() {
             let _: Result<RawBsonRef, _> = elem.try_into();
         }
diff --git a/fuzz/generate_corpus.rs b/fuzz/generate_corpus.rs
index c67c4cfc..06b16f02 100644
--- a/fuzz/generate_corpus.rs
+++ b/fuzz/generate_corpus.rs
@@ -29,14 +29,18 @@ fn generate_length_edge_cases(dir: &Path) -> std::io::Result<()> {
     let min_doc = doc! {};
     fs::write(
         target_dir.join("min_doc"),
-        bson::to_vec(&min_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+        min_doc
+            .encode_to_vec()
+            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
     // Document with length near i32::MAX
     let large_doc = doc! { "a": "b".repeat(i32::MAX as usize / 2) };
     fs::write(
         target_dir.join("large_doc"),
-        bson::to_vec(&large_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+        large_doc
+            .encode_to_vec()
+            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
     Ok(())
@@ -73,7 +77,9 @@ fn generate_type_marker_cases(dir: &Path) -> std::io::Result<()> {
     };
     fs::write(
         target_dir.join("all_types"),
-        bson::to_vec(&all_types).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+        all_types
+            .encode_to_vec()
+            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
     Ok(())
@@ -100,7 +106,9 @@ fn generate_string_edge_cases(dir: &Path) -> std::io::Result<()> {
     };
     fs::write(
         target_dir.join("utf8_cases"),
-        bson::to_vec(&utf8_cases).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+        utf8_cases
+            .encode_to_vec()
+            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
     Ok(())
@@ -124,7 +132,9 @@ fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
     }
     fs::write(
         target_dir.join("nested_doc"),
-        bson::to_vec(&nested_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+        nested_doc
+            .encode_to_vec()
+            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
     // Document with large binary data
@@ -136,7 +146,9 @@ fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
     };
     fs::write(
         target_dir.join("large_binary"),
-        bson::to_vec(&large_binary).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
+        large_binary
+            .encode_to_vec()
+            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
     Ok(())
diff --git a/serde-tests/Cargo.toml b/serde-tests/Cargo.toml
index 99236d60..12a09e8c 100644
--- a/serde-tests/Cargo.toml
+++ b/serde-tests/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2018"
 default = []
 
 [dependencies]
-bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde_with-3"] }
+bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3"] }
 serde = { version = "1.0", features = ["derive"] }
 pretty_assertions = "0.6.1"
 hex = "0.4.2"
diff --git a/serde-tests/json.rs b/serde-tests/json.rs
index 417ea6c9..7d6d3b2d 100644
--- a/serde-tests/json.rs
+++ b/serde-tests/json.rs
@@ -99,18 +99,18 @@ fn owned_raw_bson() {
     });
 
     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", RawBson::Null);
+    doc_buf.append("a", "key").unwrap();
+    doc_buf.append("number", 12).unwrap();
+    doc_buf.append("bool", false).unwrap();
+    doc_buf.append("nu", RawBson::Null).unwrap();
 
     let mut array_buf = RawArrayBuf::new();
-    array_buf.push(1);
-    array_buf.push("string");
+    array_buf.push(1).unwrap();
+    array_buf.push("string").unwrap();
 
     let mut bson_doc = RawDocumentBuf::new();
-    bson_doc.append("first", true);
-    bson_doc.append("second", "string");
+    bson_doc.append("first", true).unwrap();
+    bson_doc.append("second", "string").unwrap();
 
     let expected = Foo {
         doc_buf,
diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index 719f63c6..9fbafdc4 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -52,44 +52,42 @@ use bson::{
 ///     - serializing `expected_value` to BSON bytes matches the raw BSON bytes of `expected_doc`
 ///     - deserializing a `T` from the serialized bytes produces `expected_value`
 ///     - deserializing a `Document` from the serialized bytes produces `expected_doc`
-///   - `bson::to_writer` and `Document::to_writer` produce the same result given the same input
+///   - `bson::to_vec` and `Document::to_vec` produce the same result given the same input
 fn run_test<T>(expected_value: &T, expected_doc: &Document, description: &str)
 where
     T: Serialize + DeserializeOwned + PartialEq + std::fmt::Debug,
 {
-    let mut expected_bytes = Vec::new();
-    expected_doc
-        .to_writer(&mut expected_bytes)
-        .expect(description);
+    let expected_bytes = expected_doc.encode_to_vec().expect(description);
 
-    let expected_bytes_serde = bson::to_vec(&expected_value).expect(description);
+    let expected_bytes_serde = bson::serialize_to_vec(&expected_value).expect(description);
 
     assert_eq!(expected_bytes_serde, expected_bytes, "{}", description);
 
-    let expected_bytes_from_doc_serde = bson::to_vec(&expected_doc).expect(description);
+    let expected_bytes_from_doc_serde = bson::serialize_to_vec(&expected_doc).expect(description);
     assert_eq!(
         expected_bytes_from_doc_serde, expected_bytes,
         "{}",
         description
     );
 
-    let serialized_doc = bson::to_document(&expected_value).expect(description);
+    let serialized_doc = bson::serialize_to_document(&expected_value).expect(description);
     assert_eq!(&serialized_doc, expected_doc, "{}", description);
     assert_eq!(
         expected_value,
-        &bson::from_document::<T>(serialized_doc).expect(description),
+        &bson::deserialize_from_document::<T>(serialized_doc).expect(description),
         "{}",
         description
     );
 
     assert_eq!(
-        &bson::from_reader::<_, T>(expected_bytes.as_slice()).expect(description),
+        &bson::deserialize_from_reader::<_, T>(expected_bytes.as_slice()).expect(description),
         expected_value,
         "{}",
         description
     );
     assert_eq!(
-        &bson::from_reader::<_, Document>(expected_bytes.as_slice()).expect(description),
+        &bson::deserialize_from_reader::<_, Document>(expected_bytes.as_slice())
+            .expect(description),
         expected_doc,
         "{}",
         description
@@ -104,25 +102,23 @@ fn run_deserialize_test<T>(expected_value: &T, expected_doc: &Document, descript
 where
     T: DeserializeOwned + PartialEq + std::fmt::Debug,
 {
-    let mut expected_bytes = Vec::new();
-    expected_doc
-        .to_writer(&mut expected_bytes)
-        .expect(description);
+    let expected_bytes = expected_doc.encode_to_vec().expect(description);
 
     assert_eq!(
-        &bson::from_document::<T>(expected_doc.clone()).expect(description),
+        &bson::deserialize_from_document::<T>(expected_doc.clone()).expect(description),
         expected_value,
         "{}",
         description
     );
     assert_eq!(
-        &bson::from_reader::<_, T>(expected_bytes.as_slice()).expect(description),
+        &bson::deserialize_from_reader::<_, T>(expected_bytes.as_slice()).expect(description),
         expected_value,
         "{}",
         description
     );
     assert_eq!(
-        &bson::from_reader::<_, Document>(expected_bytes.as_slice()).expect(description),
+        &bson::deserialize_from_reader::<_, Document>(expected_bytes.as_slice())
+            .expect(description),
         expected_doc,
         "{}",
         description
@@ -136,8 +132,8 @@ fn run_raw_round_trip_test<'de, T>(bytes: &'de [u8], description: &str)
 where
     T: Deserialize<'de> + Serialize + std::fmt::Debug,
 {
-    let t: T = bson::from_slice(bytes).expect(description);
-    let vec = bson::to_vec(&t).expect(description);
+    let t: T = bson::deserialize_from_slice(bytes).expect(description);
+    let vec = bson::serialize_to_vec(&t).expect(description);
     assert_eq!(vec.as_slice(), bytes);
 }
 
@@ -444,13 +440,12 @@ fn type_conversion() {
     let doc = doc! {
         "bar": 1_i64
     };
-    let deserialized: Foo = bson::from_document(doc.clone()).unwrap();
+    let deserialized: Foo = bson::deserialize_from_document(doc.clone()).unwrap();
     assert_eq!(deserialized, v);
 
-    let mut bytes = Vec::new();
-    doc.to_writer(&mut bytes).unwrap();
+    let bytes = doc.encode_to_vec().unwrap();
 
-    let bson_deserialized: Foo = bson::from_reader(bytes.as_slice()).unwrap();
+    let bson_deserialized: Foo = bson::deserialize_from_reader(bytes.as_slice()).unwrap();
     assert_eq!(bson_deserialized, v);
 }
 
@@ -463,12 +458,11 @@ fn missing_errors() {
 
     let doc = doc! {};
 
-    bson::from_document::<Foo>(doc.clone()).unwrap_err();
+    bson::deserialize_from_document::<Foo>(doc.clone()).unwrap_err();
 
-    let mut bytes = Vec::new();
-    doc.to_writer(&mut bytes).unwrap();
+    let bytes = doc.encode_to_vec().unwrap();
 
-    bson::from_reader::<_, Foo>(bytes.as_slice()).unwrap_err();
+    bson::deserialize_from_reader::<_, Foo>(bytes.as_slice()).unwrap_err();
 }
 
 #[test]
@@ -682,11 +676,12 @@ fn unused_fields_deny() {
         "a": 1,
         "b": 2,
     };
-    bson::from_document::<Foo>(doc.clone()).expect_err("extra fields should cause failure");
+    bson::deserialize_from_document::<Foo>(doc.clone())
+        .expect_err("extra fields should cause failure");
 
-    let mut bytes = Vec::new();
-    doc.to_writer(&mut bytes).unwrap();
-    bson::from_reader::<_, Foo>(bytes.as_slice()).expect_err("extra fields should cause failure");
+    let bytes = doc.encode_to_vec().unwrap();
+    bson::deserialize_from_reader::<_, Foo>(bytes.as_slice())
+        .expect_err("extra fields should cause failure");
 }
 
 #[test]
@@ -741,7 +736,7 @@ fn raw_doc_buf() {
         d: RawDocumentBuf,
     }
 
-    let bytes = bson::to_vec(&doc! {
+    let bytes = bson::serialize_to_vec(&doc! {
         "d": {
             "a": 12,
             "b": 5.5,
@@ -763,7 +758,7 @@ fn raw_doc() {
         d: &'a RawDocument,
     }
 
-    let bytes = bson::to_vec(&doc! {
+    let bytes = bson::serialize_to_vec(&doc! {
         "d": {
             "a": 12,
             "b": 5.5,
@@ -785,7 +780,7 @@ fn raw_array() {
         d: &'a RawArray,
     }
 
-    let bytes = bson::to_vec(&doc! {
+    let bytes = bson::serialize_to_vec(&doc! {
         "d": [1, true, { "ok": 1 }, [ "sub", "array" ], Uuid::new()]
     })
     .expect("raw_array");
@@ -810,7 +805,7 @@ fn raw_binary() {
         other: RawBinaryRef<'a>,
     }
 
-    let bytes = bson::to_vec(&doc! {
+    let bytes = bson::serialize_to_vec(&doc! {
         "generic": Binary {
             bytes: vec![1, 2, 3, 4, 5],
             subtype: BinarySubtype::Generic,
@@ -838,7 +833,7 @@ fn raw_regex() {
         r: RawRegexRef<'a>,
     }
 
-    let bytes = bson::to_vec(&doc! {
+    let bytes = bson::serialize_to_vec(&doc! {
         "r": Regex {
             pattern: "a[b-c]d".to_string(),
             options: "ab".to_string(),
@@ -857,7 +852,7 @@ fn raw_code_w_scope() {
         r: RawJavaScriptCodeWithScopeRef<'a>,
     }
 
-    let bytes = bson::to_vec(&doc! {
+    let bytes = bson::serialize_to_vec(&doc! {
         "r": JavaScriptCodeWithScope {
             code: "console.log(x)".to_string(),
             scope: doc! { "x": 1 },
@@ -949,7 +944,7 @@ impl AllTypes {
 
         let decimal = {
             let bytes = hex::decode("18000000136400D0070000000000000000000000003A3000").unwrap();
-            let d = Document::from_reader(bytes.as_slice()).unwrap();
+            let d = Document::decode_from_reader(bytes.as_slice()).unwrap();
             match d.get("d") {
                 Some(Bson::Decimal128(d)) => *d,
                 c => panic!("expected decimal128, got {:?}", c),
@@ -1053,7 +1048,7 @@ fn all_raw_types_rmp() {
         regex: RawRegexRef<'a>,
     }
 
-    let doc_bytes = bson::to_vec(&doc! {
+    let doc_bytes = bson::serialize_to_vec(&doc! {
         "bson": "some string",
         "array": [1, 2, 3],
         "binary": Binary { bytes: vec![1, 2, 3], subtype: BinarySubtype::Generic },
@@ -1068,7 +1063,7 @@ fn all_raw_types_rmp() {
         }
     })
     .unwrap();
-    let doc_buf = RawDocumentBuf::from_bytes(doc_bytes).unwrap();
+    let doc_buf = RawDocumentBuf::decode_from_bytes(doc_bytes).unwrap();
     let document = &doc_buf;
     let array = document.get_array("array").unwrap();
 
@@ -1124,8 +1119,7 @@ fn borrowed() {
         "cow": "cow",
         "array": ["borrowed string"],
     };
-    let mut bson = Vec::new();
-    doc.to_writer(&mut bson).unwrap();
+    let bson = doc.encode_to_vec().unwrap();
 
     let s = "borrowed string".to_string();
     let ss = "another borrowed string".to_string();
@@ -1142,7 +1136,7 @@ fn borrowed() {
     };
 
     let deserialized: Foo =
-        bson::from_slice(bson.as_slice()).expect("deserialization should succeed");
+        bson::deserialize_from_slice(bson.as_slice()).expect("deserialization should succeed");
     assert_eq!(deserialized, v);
 }
 
@@ -1185,8 +1179,8 @@ fn u2i() {
     let v = TooBig {
         u_64: i64::MAX as u64 + 1,
     };
-    bson::to_document(&v).unwrap_err();
-    bson::to_vec(&v).unwrap_err();
+    bson::serialize_to_document(&v).unwrap_err();
+    bson::serialize_to_vec(&v).unwrap_err();
 }
 
 #[test]
@@ -1268,14 +1262,16 @@ fn owned_raw_types() {
                 RawBson::JavaScriptCodeWithScope(raw_code_w_scope.clone()),
             ),
             ("decimal128", RawBson::Decimal128(d128)),
-        ]),
+        ])
+        .unwrap(),
         array: RawArrayBuf::from_iter([
             RawBson::String("a string".to_string()),
             RawBson::ObjectId(oid),
             RawBson::DateTime(dt),
             RawBson::JavaScriptCodeWithScope(raw_code_w_scope),
             RawBson::Decimal128(d128),
-        ]),
+        ])
+        .unwrap(),
     };
 
     let expected = doc! {
@@ -1317,15 +1313,15 @@ fn hint_cleared() {
         "binary": binary_value.clone()
     };
 
-    let bytes = bson::to_vec(&doc_value).unwrap();
+    let bytes = bson::serialize_to_vec(&doc_value).unwrap();
 
-    let doc = RawDocument::from_bytes(&bytes).unwrap();
+    let doc = RawDocument::decode_from_bytes(&bytes).unwrap();
     let binary = doc.get_binary("binary").unwrap();
 
     let f = Foo { doc, binary };
 
-    let serialized_bytes = bson::to_vec(&f).unwrap();
-    let round_doc: Document = bson::from_slice(&serialized_bytes).unwrap();
+    let serialized_bytes = bson::serialize_to_vec(&f).unwrap();
+    let round_doc: Document = bson::deserialize_from_slice(&serialized_bytes).unwrap();
 
     assert_eq!(round_doc, doc! { "doc": doc_value, "binary": binary_value });
 }
@@ -1333,5 +1329,5 @@ fn hint_cleared() {
 #[test]
 fn invalid_length() {
     // This is a regression test for fuzzer-generated input (RUST-1240).
-    assert!(bson::from_slice::<Document>(&[4, 0, 0, 128, 0, 87]).is_err());
+    assert!(bson::deserialize_from_slice::<Document>(&[4, 0, 0, 128, 0, 87]).is_err());
 }
diff --git a/src/binary.rs b/src/binary.rs
index f977088b..bd00a8db 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -2,9 +2,8 @@
 
 mod vector;
 
-use crate::{base64, spec::BinarySubtype, Document, RawBinaryRef};
+use crate::{base64, spec::BinarySubtype, RawBinaryRef};
 use std::{
-    convert::TryFrom,
     error,
     fmt::{self, Display},
 };
@@ -61,7 +60,8 @@ impl Binary {
         Ok(Binary { subtype, bytes })
     }
 
-    pub(crate) fn from_extended_doc(doc: &Document) -> Option<Self> {
+    #[cfg(feature = "serde")]
+    pub(crate) fn from_extended_doc(doc: &crate::Document) -> Option<Self> {
         let binary_doc = doc.get_document("$binary").ok()?;
 
         if let Ok(bytes) = binary_doc.get_str("base64") {
diff --git a/src/binary/vector.rs b/src/binary/vector.rs
index 7226e867..d67f3757 100644
--- a/src/binary/vector.rs
+++ b/src/binary/vector.rs
@@ -3,8 +3,6 @@ use std::{
     mem::size_of,
 };
 
-use serde::{Deserialize, Serialize};
-
 use super::{Binary, Error, Result};
 use crate::{spec::BinarySubtype, Bson, RawBson};
 
@@ -32,10 +30,10 @@ const PACKED_BIT: u8 = 0x10;
 /// }
 ///
 /// let data = Data { vector: Vector::Int8(vec![0, 1, 2]) };
-/// let document = bson::to_document(&data).unwrap();
+/// let document = bson::serialize_to_document(&data).unwrap();
 /// assert_eq!(document.get("vector").unwrap().element_type(), ElementType::Binary);
 ///
-/// let data: Data = bson::from_document(document).unwrap();
+/// let data: Data = bson::deserialize_from_document(document).unwrap();
 /// assert_eq!(data.vector, Vector::Int8(vec![0, 1, 2]));
 /// ```
 ///
@@ -267,7 +265,8 @@ impl From<Vector> for RawBson {
     }
 }
 
-impl Serialize for Vector {
+#[cfg(feature = "serde")]
+impl serde::Serialize for Vector {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -277,7 +276,8 @@ impl Serialize for Vector {
     }
 }
 
-impl<'de> Deserialize<'de> for Vector {
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for Vector {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
diff --git a/src/bson.rs b/src/bson.rs
index 9b5f0ca4..8f35899d 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -22,7 +22,7 @@
 //! BSON definition
 
 use std::{
-    convert::{TryFrom, TryInto},
+    convert::TryFrom,
     fmt::{self, Debug, Display, Formatter},
     hash::Hash,
     ops::Index,
@@ -31,13 +31,7 @@ use std::{
 use serde_json::{json, Value};
 
 pub use crate::document::Document;
-use crate::{
-    base64,
-    oid::{self, ObjectId},
-    spec::{BinarySubtype, ElementType},
-    Binary,
-    Decimal128,
-};
+use crate::{base64, oid, spec::ElementType, Binary, Decimal128};
 
 /// Possible BSON value types.
 #[derive(Clone, Default, PartialEq)]
@@ -501,7 +495,7 @@ impl Bson {
             Bson::JavaScriptCode(code) => json!({ "$code": code }),
             Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
                 "$code": code,
-                "$scope": scope,
+                "$scope": Bson::Document(scope).into_relaxed_extjson(),
             }),
             Bson::Int32(v) => v.into(),
             Bson::Int64(v) => v.into(),
@@ -618,6 +612,7 @@ impl Bson {
     /// This function mainly used for [extended JSON format](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
     // TODO RUST-426: Investigate either removing this from the serde implementation or unifying
     // with the extended JSON implementation.
+    #[cfg(feature = "serde")]
     pub(crate) fn into_extended_document(self, rawbson: bool) -> Document {
         match self {
             Bson::RegularExpression(Regex {
@@ -660,7 +655,7 @@ impl Bson {
                 if rawbson {
                     doc! {
                         "$binary": {
-                            "bytes": Binary { subtype: BinarySubtype::Generic, bytes },
+                            "bytes": Binary { subtype: crate::spec::BinarySubtype::Generic, bytes },
                             "subType": Bson::Int32(tval.into())
                         }
                     }
@@ -727,6 +722,7 @@ impl Bson {
         }
     }
 
+    #[cfg(feature = "serde")]
     pub(crate) fn from_extended_document(doc: Document) -> Bson {
         if doc.len() > 2 {
             return Bson::Document(doc);
@@ -738,7 +734,7 @@ impl Bson {
         match keys.as_slice() {
             ["$oid"] => {
                 if let Ok(oid) = doc.get_str("$oid") {
-                    if let Ok(oid) = ObjectId::parse_str(oid) {
+                    if let Ok(oid) = crate::oid::ObjectId::parse_str(oid) {
                         return Bson::ObjectId(oid);
                     }
                 }
diff --git a/src/datetime.rs b/src/datetime.rs
index b1394c32..41dca1df 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -73,7 +73,7 @@ use serde::{Deserialize, Deserializer, Serialize};
 ///
 /// # fn main() -> bson::ser::Result<()> {
 /// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() };
-/// println!("{:?}", bson::to_document(&f)?);
+/// println!("{:?}", bson::serialize_to_document(&f)?);
 /// # Ok(())
 /// # }
 /// ```
@@ -170,7 +170,7 @@ use serde::{Deserialize, Deserializer, Serialize};
 ///   "as_bson": bson::DateTime::from_chrono(dt),
 /// };
 ///
-/// assert_eq!(bson::to_document(&foo)?, expected);
+/// assert_eq!(bson::serialize_to_document(&foo)?, expected);
 /// # }
 /// # Ok::<(), Box<dyn std::error::Error>>(())
 /// ```
@@ -421,10 +421,6 @@ impl crate::DateTime {
         self.checked_duration_since(earlier)
             .unwrap_or(Duration::ZERO)
     }
-
-    pub(crate) fn as_le_bytes(&self) -> [u8; 8] {
-        self.0.to_le_bytes()
-    }
 }
 
 impl fmt::Debug for crate::DateTime {
diff --git a/src/de.rs b/src/de.rs
index c1e1312a..821a4dca 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -33,25 +33,20 @@ pub use self::{
 use std::io::Read;
 
 use crate::{
-    bson::{Bson, Document, Timestamp},
-    ser::write_i32,
+    bson::{Bson, Document},
+    raw::reader_to_vec,
     spec::BinarySubtype,
 };
 
 #[rustfmt::skip]
-use ::serde::{
-    de::{DeserializeOwned, Error as _},
-    Deserialize,
-};
+use ::serde::{de::DeserializeOwned, Deserialize};
 
 pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor};
 
+#[cfg(test)]
 pub(crate) use self::raw::Deserializer as RawDeserializer;
 
 pub(crate) const MAX_BSON_SIZE: i32 = i32::MAX;
-pub(crate) const MIN_BSON_DOCUMENT_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
-pub(crate) const MIN_BSON_STRING_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
-pub(crate) const MIN_CODE_WITH_SCOPE_SIZE: i32 = 4 + MIN_BSON_STRING_SIZE + MIN_BSON_DOCUMENT_SIZE;
 
 /// Hint provided to the deserializer via `deserialize_newtype_struct` as to the type of thing
 /// being deserialized.
@@ -69,21 +64,13 @@ enum DeserializerHint {
     RawBson,
 }
 
-impl Timestamp {
-    pub(crate) fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
-        let mut bytes = [0; 8];
-        reader.read_exact(&mut bytes)?;
-        Ok(Timestamp::from_le_bytes(bytes))
-    }
-}
-
 /// Deserialize a `T` from the provided [`Bson`] value.
 ///
 /// The [`Deserializer`] used by this function presents itself as human readable, whereas the
-/// one used in [`from_slice`] does not. This means that this function may deserialize differently
-/// than [`from_slice`] for types that change their deserialization logic depending on whether
-/// the format is human readable or not.
-pub fn from_bson<T>(bson: Bson) -> Result<T>
+/// one used in [`deserialize_from_slice`] does not. This means that this function may deserialize
+/// differently than [`deserialize_from_slice`] for types that change their deserialization logic
+/// depending on whether the format is human readable or not.
+pub fn deserialize_from_bson<T>(bson: Bson) -> Result<T>
 where
     T: DeserializeOwned,
 {
@@ -101,51 +88,35 @@ where
 /// Deserialize a `T` from the provided [`Document`].
 ///
 /// The [`Deserializer`] used by this function presents itself as human readable, whereas the
-/// one used in [`from_slice`] does not. This means that this function may deserialize differently
-/// than [`from_slice`] for types that change their deserialization logic depending on whether
-/// the format is human readable or not.
-pub fn from_document<T>(doc: Document) -> Result<T>
+/// one used in [`deserialize_from_slice`] does not. This means that this function may deserialize
+/// differently than [`deserialize_from_slice`] for types that change their deserialization logic
+/// depending on whether the format is human readable or not.
+pub fn deserialize_from_document<T>(doc: Document) -> Result<T>
 where
     T: DeserializeOwned,
 {
-    from_bson(Bson::Document(doc))
-}
-
-pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
-    let mut buf = [0; 4];
-    reader.read_exact(&mut buf)?;
-    let length = i32::from_le_bytes(buf);
-
-    if length < MIN_BSON_DOCUMENT_SIZE {
-        return Err(Error::custom("document size too small"));
-    }
-
-    let mut bytes = Vec::with_capacity(length as usize);
-    write_i32(&mut bytes, length).map_err(Error::custom)?;
-
-    reader.take(length as u64 - 4).read_to_end(&mut bytes)?;
-    Ok(bytes)
+    deserialize_from_bson(Bson::Document(doc))
 }
 
 /// Deserialize an instance of type `T` from an I/O stream of BSON.
-pub fn from_reader<R, T>(reader: R) -> Result<T>
+pub fn deserialize_from_reader<R, T>(reader: R) -> Result<T>
 where
     T: DeserializeOwned,
     R: Read,
 {
     let bytes = reader_to_vec(reader)?;
-    from_slice(bytes.as_slice())
+    deserialize_from_slice(bytes.as_slice())
 }
 
 /// Deserialize an instance of type `T` from a slice of BSON bytes.
-pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T>
+pub fn deserialize_from_slice<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    from_raw(raw::Deserializer::new(bytes)?)
+    deserialize_from_raw(raw::Deserializer::new(bytes)?)
 }
 
-pub(crate) fn from_raw<'de, T: Deserialize<'de>>(
+pub(crate) fn deserialize_from_raw<'de, T: Deserialize<'de>>(
     deserializer: raw::Deserializer<'de>,
 ) -> Result<T> {
     #[cfg(feature = "serde_path_to_error")]
diff --git a/src/decimal128.rs b/src/decimal128.rs
index 546b9619..036b1f77 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -38,6 +38,7 @@ impl Decimal128 {
         self.bytes
     }
 
+    #[cfg(feature = "serde")]
     pub(crate) fn deserialize_from_slice<E: serde::de::Error>(
         bytes: &[u8],
     ) -> std::result::Result<Self, E> {
diff --git a/src/document.rs b/src/document.rs
index eed8213c..5af4026b 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -673,7 +673,12 @@ impl Document {
         }
     }
 
-    /// Attempts to serialize the [`Document`] into a byte stream.
+    /// Attempt to encode the [`Document`] into a byte [`Vec`].
+    pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
+        Ok(crate::RawDocumentBuf::from_document(self)?.into_bytes())
+    }
+
+    /// Attempts to encode the [`Document`] into a byte stream.
     ///
     /// While the method signature indicates an owned writer must be passed in, a mutable reference
     /// may also be passed in due to blanket implementations of [`Write`] provided in the standard
@@ -685,22 +690,17 @@ impl Document {
     ///
     /// let mut v: Vec<u8> = Vec::new();
     /// let doc = doc! { "x" : 1 };
-    /// doc.to_writer(&mut v)?;
+    /// doc.encode_to_writer(&mut v)?;
     /// # Ok(())
     /// # }
     /// ```
-    pub fn to_writer<W: Write>(&self, mut writer: W) -> crate::ser::Result<()> {
-        let buf = crate::to_vec(self)?;
-        writer.write_all(&buf)?;
+    pub fn encode_to_writer<W: Write>(&self, mut writer: W) -> crate::error::Result<()> {
+        let buf = crate::RawDocumentBuf::from_document(self)?;
+        writer.write_all(buf.as_bytes())?;
         Ok(())
     }
 
-    fn decode<R: Read + ?Sized>(reader: &mut R) -> crate::de::Result<Document> {
-        let buf = crate::de::reader_to_vec(reader)?;
-        crate::de::from_raw(crate::de::RawDeserializer::new(&buf)?)
-    }
-
-    /// Attempts to deserialize a [`Document`] from a byte stream.
+    /// Attempts to decode a [`Document`] from a byte stream.
     ///
     /// While the method signature indicates an owned reader must be passed in, a mutable reference
     /// may also be passed in due to blanket implementations of [`Read`] provided in the standard
@@ -714,22 +714,23 @@ impl Document {
     ///
     /// let mut v: Vec<u8> = Vec::new();
     /// let doc = doc! { "x" : 1 };
-    /// doc.to_writer(&mut v)?;
+    /// doc.encode_to_writer(&mut v)?;
     ///
     /// // read from mutable reference
     /// let mut reader = Cursor::new(v.clone());
-    /// let doc1 = Document::from_reader(&mut reader)?;
+    /// let doc1 = Document::decode_from_reader(&mut reader)?;
     ///
     /// // read from owned value
-    /// let doc2 = Document::from_reader(Cursor::new(v))?;
+    /// let doc2 = Document::decode_from_reader(Cursor::new(v))?;
     ///
     /// assert_eq!(doc, doc1);
     /// assert_eq!(doc, doc2);
     /// # Ok(())
     /// # }
     /// ```
-    pub fn from_reader<R: Read>(mut reader: R) -> crate::de::Result<Document> {
-        Self::decode(&mut reader)
+    pub fn decode_from_reader<R: Read>(reader: R) -> crate::error::Result<Document> {
+        let raw = crate::raw::RawDocumentBuf::decode_from_reader(reader)?;
+        raw.try_into()
     }
 }
 
diff --git a/src/error.rs b/src/error.rs
index d1497760..20380dcf 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -51,9 +51,14 @@ pub enum ErrorKind {
         kind: ValueAccessErrorKind,
     },
 
+    /// A [`std::io::Error`] occurred.
+    #[error("An IO error occurred: {0}")]
+    Io(std::io::Error),
+
     /// A wrapped deserialization error.
     /// TODO RUST-1406: collapse this
-    #[error("Deserialization error")]
+    #[cfg(feature = "serde")]
+    #[error("Deserialization error: {0}")]
     DeError(crate::de::Error),
 }
 
@@ -67,13 +72,16 @@ impl From<ErrorKind> for Error {
     }
 }
 
+impl From<std::io::Error> for Error {
+    fn from(value: std::io::Error) -> Self {
+        ErrorKind::Io(value).into()
+    }
+}
+
+#[cfg(feature = "serde")]
 impl From<crate::de::Error> for Error {
     fn from(value: crate::de::Error) -> Self {
-        Self {
-            kind: ErrorKind::DeError(value),
-            key: None,
-            index: None,
-        }
+        ErrorKind::DeError(value).into()
     }
 }
 
@@ -162,4 +170,9 @@ impl Error {
             }
         )
     }
+
+    #[cfg(all(test, feature = "serde"))]
+    pub(crate) fn is_malformed_value(&self) -> bool {
+        matches!(self.kind, ErrorKind::MalformedValue { .. },)
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 3780be14..c5572c5d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -132,7 +132,7 @@
 //! use std::io::Read;
 //!
 //! let mut bytes = hex::decode("0C0000001069000100000000").unwrap();
-//! let doc = Document::from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 }
+//! let doc = Document::decode_from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 }
 //!
 //! let doc = doc! {
 //!    "hello": "world",
@@ -200,14 +200,14 @@
 //! // Deserialize the Person struct from the BSON data, automatically
 //! // verifying that the necessary keys are present and that they are of
 //! // the correct types.
-//! let mut person: Person = bson::from_bson(bson_data).unwrap();
+//! let mut person: Person = bson::deserialize_from_bson(bson_data).unwrap();
 //!
 //! // Do things just like with any other Rust data structure.
 //! println!("Redacting {}'s record.", person.name);
 //! person.name = "REDACTED".to_string();
 //!
 //! // Get a serialized version of the input data as a [`Bson`].
-//! let redacted_bson = bson::to_bson(&person).unwrap();
+//! let redacted_bson = bson::serialize_to_bson(&person).unwrap();
 //! ```
 //!
 //! Any types that implement [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize)
@@ -289,7 +289,6 @@ pub use self::{
     binary::Binary,
     bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
-    de::{from_bson, from_document, from_reader, from_slice, Deserializer},
     decimal128::Decimal128,
     raw::{
         RawArray,
@@ -304,24 +303,46 @@ pub use self::{
         RawJavaScriptCodeWithScopeRef,
         RawRegexRef,
     },
-    ser::{to_bson, to_document, to_raw_document_buf, to_vec, Serializer},
     uuid::{Uuid, UuidRepresentation},
 };
 
+#[cfg(feature = "serde")]
+#[doc(inline)]
+pub use self::{
+    de::{
+        deserialize_from_bson,
+        deserialize_from_document,
+        deserialize_from_reader,
+        deserialize_from_slice,
+        Deserializer,
+    },
+    ser::{
+        serialize_to_bson,
+        serialize_to_document,
+        serialize_to_raw_document_buf,
+        serialize_to_vec,
+        Serializer,
+    },
+};
+
 #[macro_use]
 mod macros;
 mod base64;
 pub mod binary;
 mod bson;
 pub mod datetime;
+#[cfg(feature = "serde")]
 pub mod de;
 pub mod decimal128;
 pub mod document;
 pub mod error;
+#[cfg(feature = "serde")]
 pub mod extjson;
 pub mod oid;
 pub mod raw;
+#[cfg(feature = "serde")]
 pub mod ser;
+#[cfg(feature = "serde")]
 pub mod serde_helpers;
 pub mod spec;
 pub mod uuid;
diff --git a/src/macros.rs b/src/macros.rs
index 3a0cb77b..62d640b7 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -240,12 +240,12 @@ macro_rules! rawbson {
 
     // Finished with trailing comma.
     (@array [$($elems:expr,)*]) => {
-        <$crate::RawArrayBuf as std::iter::FromIterator::<$crate::RawBson>>::from_iter(vec![$($elems,)*])
+        $crate::RawArrayBuf::from_iter(vec![$($elems,)*]).expect("invalid bson value")
     };
 
     // Finished without trailing comma.
     (@array [$($elems:expr),*]) => {
-        <$crate::RawArrayBuf as std::iter::FromIterator::<$crate::RawBson>>::from_iter(vec![$($elems),*])
+        $crate::RawArrayBuf::from_iter(vec![$($elems),*]).expect("invalid bson value")
     };
 
     // Next element is `null`.
@@ -293,13 +293,13 @@ macro_rules! rawbson {
 
     // Insert the current entry followed by trailing comma.
     (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
-        $object.append(($($key)+), $value);
+        $object.append(($($key)+), $value).expect("invalid bson 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);
+        $object.append(($($key)+), $value).expect("invalid bson value");
     };
 
     // Next value is `null`.
diff --git a/src/oid.rs b/src/oid.rs
index a6bb7dbd..074b4a06 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -92,7 +92,7 @@ impl error::Error for Error {}
 ///
 /// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
 /// let f = Foo { oid: ObjectId::new() };
-/// println!("bson: {}", bson::to_document(&f)?);
+/// println!("bson: {}", bson::serialize_to_document(&f)?);
 /// println!("json: {}", serde_json::to_string(&f)?);
 /// # Ok(())
 /// # }
@@ -127,7 +127,7 @@ impl error::Error for Error {}
 /// }
 /// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
 /// let f = Foo { oid: ObjectId::new(), oid_as_hex: ObjectId::new() };
-/// println!("bson: {}", bson::to_document(&f)?);
+/// println!("bson: {}", bson::serialize_to_document(&f)?);
 /// println!("json: {}", serde_json::to_string(&f)?);
 /// # Ok(())
 /// # }
diff --git a/src/raw.rs b/src/raw.rs
index 252832c2..9537e3da 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -23,7 +23,7 @@
 //! };
 //!
 //! // See http://bsonspec.org/spec.html for details on the binary encoding of BSON.
-//! let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?;
+//! let doc = RawDocumentBuf::decode_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!(
@@ -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::from_bytes(bytes)?.get_str("hi")?, "y'all");
+//! assert_eq!(RawDocument::decode_from_bytes(bytes)?.get_str("hi")?, "y'all");
 //! # Ok::<(), Box<dyn std::error::Error>>(())
 //! ```
 //!
@@ -119,17 +119,18 @@ mod bson_ref;
 mod document;
 mod document_buf;
 mod iter;
+#[cfg(feature = "serde")]
 pub(crate) mod serde;
 #[cfg(test)]
 mod test;
 
-use std::convert::{TryFrom, TryInto};
-
-use crate::{
-    de::MIN_BSON_STRING_SIZE,
-    error::{Error, ErrorKind, Result},
+use std::{
+    convert::{TryFrom, TryInto},
+    io::Read,
 };
 
+use crate::error::{Error, ErrorKind, Result};
+
 pub use self::{
     array::{RawArray, RawArrayIter},
     array_buf::RawArrayBuf,
@@ -146,15 +147,23 @@ pub use self::{
     iter::{RawElement, RawIter},
 };
 
+pub(crate) const MIN_BSON_STRING_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
+pub(crate) const MIN_BSON_DOCUMENT_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator
+pub(crate) const MIN_CODE_WITH_SCOPE_SIZE: i32 = 4 + MIN_BSON_STRING_SIZE + MIN_BSON_DOCUMENT_SIZE;
+
+#[cfg(feature = "serde")]
 pub(crate) use self::iter::{Utf8LossyBson, Utf8LossyJavaScriptCodeWithScope};
 
 /// Special newtype name indicating that the type being (de)serialized is a raw BSON document.
+#[cfg(feature = "serde")]
 pub(crate) const RAW_DOCUMENT_NEWTYPE: &str = "$__private__bson_RawDocument";
 
 /// Special newtype name indicating that the type being (de)serialized is a raw BSON array.
+#[cfg(feature = "serde")]
 pub(crate) const RAW_ARRAY_NEWTYPE: &str = "$__private__bson_RawArray";
 
 /// Special newtype name indicating that the type being (de)serialized is a raw BSON value.
+#[cfg(feature = "serde")]
 pub(crate) const RAW_BSON_NEWTYPE: &str = "$__private__bson_RawBson";
 
 /// Given a u8 slice, return an i32 calculated from the first four bytes in
@@ -285,3 +294,37 @@ fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
     lhs.checked_add(rhs)
         .ok_or_else(|| Error::malformed_value("attempted to add with overflow"))
 }
+
+pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
+    let mut buf = [0; 4];
+    reader.read_exact(&mut buf)?;
+    let length = i32::from_le_bytes(buf);
+
+    if length < MIN_BSON_DOCUMENT_SIZE {
+        return Err(Error::malformed_value("document size too small"));
+    }
+
+    let mut bytes = Vec::with_capacity(length as usize);
+    bytes.extend(buf);
+
+    reader.take(length as u64 - 4).read_to_end(&mut bytes)?;
+    Ok(bytes)
+}
+
+pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
+    buf.extend(&(s.len() as i32 + 1).to_le_bytes());
+    buf.extend(s.as_bytes());
+    buf.push(0);
+}
+
+pub(crate) fn write_cstring(buf: &mut Vec<u8>, s: &str) -> Result<()> {
+    if s.contains('\0') {
+        return Err(Error::malformed_value(format!(
+            "cstring with interior null: {:?}",
+            s
+        )));
+    }
+    buf.extend(s.as_bytes());
+    buf.push(0);
+    Ok(())
+}
diff --git a/src/raw/array.rs b/src/raw/array.rs
index a55daa03..0c6020d3 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -1,9 +1,6 @@
 use std::{borrow::Cow, convert::TryFrom};
 
-use serde::{ser::SerializeSeq, Deserialize, Serialize};
-
 use super::{
-    serde::OwnedOrBorrowedRawArray,
     Error as RawError,
     RawBinaryRef,
     RawBsonRef,
@@ -15,7 +12,6 @@ use super::{
 use crate::{
     error::{Error, Result},
     oid::ObjectId,
-    raw::RAW_ARRAY_NEWTYPE,
     spec::ElementType,
     Bson,
     DateTime,
@@ -41,9 +37,9 @@ use crate::{
 /// let doc = doc! {
 ///     "x": [1, true, "two", 5.5]
 /// };
-/// let bytes = bson::to_vec(&doc)?;
+/// let bytes = bson::serialize_to_vec(&doc)?;
 ///
-/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?;
+/// let rawdoc = RawDocument::decode_from_bytes(bytes.as_slice())?;
 /// let rawarray = rawdoc.get_array("x")?;
 ///
 /// for v in rawarray {
@@ -63,9 +59,9 @@ use crate::{
 /// let doc = doc! {
 ///     "x": [1, true, "two", 5.5]
 /// };
-/// let bytes = bson::to_vec(&doc)?;
+/// let bytes = doc.encode_to_vec()?;
 ///
-/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?;
+/// let rawdoc = RawDocument::decode_from_bytes(bytes.as_slice())?;
 /// let rawarray = rawdoc.get_array("x")?;
 ///
 /// assert_eq!(rawarray.get_bool(1)?, true);
@@ -91,6 +87,7 @@ impl RawArray {
         unsafe { &*(doc as *const RawDocument as *const RawArray) }
     }
 
+    #[cfg(feature = "serde")]
     pub(crate) fn as_doc(&self) -> &RawDocument {
         &self.doc
     }
@@ -294,11 +291,13 @@ impl<'a> Iterator for RawArrayIter<'a> {
     }
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for &'a RawArray {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
+        use super::serde::OwnedOrBorrowedRawArray;
         match OwnedOrBorrowedRawArray::deserialize(deserializer)? {
             OwnedOrBorrowedRawArray::Borrowed(b) => Ok(b),
             o => Err(serde::de::Error::custom(format!(
@@ -309,18 +308,20 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray {
     }
 }
 
-impl Serialize for &RawArray {
+#[cfg(feature = "serde")]
+impl serde::Serialize for &RawArray {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
         struct SeqSerializer<'a>(&'a RawArray);
 
-        impl Serialize for SeqSerializer<'_> {
+        impl serde::Serialize for SeqSerializer<'_> {
             fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where
                 S: serde::Serializer,
             {
+                use serde::ser::SerializeSeq as _;
                 if serializer.is_human_readable() {
                     let mut seq = serializer.serialize_seq(None)?;
                     for v in self.0 {
@@ -334,6 +335,6 @@ impl Serialize for &RawArray {
             }
         }
 
-        serializer.serialize_newtype_struct(RAW_ARRAY_NEWTYPE, &SeqSerializer(self))
+        serializer.serialize_newtype_struct(crate::raw::RAW_ARRAY_NEWTYPE, &SeqSerializer(self))
     }
 }
diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index b8ac1f06..d7e2068a 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -1,18 +1,15 @@
 use std::{
     borrow::{Borrow, Cow},
     fmt::Debug,
-    iter::FromIterator,
 };
 
-use serde::{Deserialize, Serialize};
-
 use crate::{RawArray, RawBsonRef, RawDocumentBuf};
 
-use super::{document_buf::BindRawBsonRef, serde::OwnedOrBorrowedRawArray, RawArrayIter};
+use super::{document_buf::BindRawBsonRef, 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.
+/// [`RawDocumentBuf`] or as a field in a [`Deserialize`](serde::Deserialize) struct.
 ///
 /// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`](crate::raw::RawBson)
 /// value that borrows from the original document without making any additional allocations.
@@ -56,6 +53,19 @@ impl RawArrayBuf {
         }
     }
 
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<B, I>(iter: I) -> crate::error::Result<Self>
+    where
+        B: BindRawBsonRef,
+        I: IntoIterator<Item = B>,
+    {
+        let mut array_buf = RawArrayBuf::new();
+        for item in iter {
+            array_buf.push(item)?;
+        }
+        Ok(array_buf)
+    }
+
     /// Construct a new [`RawArrayBuf`] from the provided [`Vec`] of bytes.
     ///
     /// This involves a traversal of the array to count the values.
@@ -92,9 +102,10 @@ impl RawArrayBuf {
     /// assert!(iter.next().is_none());
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn push(&mut self, value: impl BindRawBsonRef) {
-        self.inner.append(self.len.to_string(), value);
+    pub fn push(&mut self, value: impl BindRawBsonRef) -> crate::error::Result<()> {
+        self.inner.append(self.len.to_string(), value)?;
         self.len += 1;
+        Ok(())
     }
 }
 
@@ -148,26 +159,18 @@ impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> {
     }
 }
 
-impl<T: BindRawBsonRef> FromIterator<T> for RawArrayBuf {
-    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
-        let mut array_buf = RawArrayBuf::new();
-        for item in iter {
-            array_buf.push(item);
-        }
-        array_buf
-    }
-}
-
-impl<'de> Deserialize<'de> for RawArrayBuf {
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for RawArrayBuf {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
-        Ok(OwnedOrBorrowedRawArray::deserialize(deserializer)?.into_owned())
+        Ok(super::serde::OwnedOrBorrowedRawArray::deserialize(deserializer)?.into_owned())
     }
 }
 
-impl Serialize for RawArrayBuf {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawArrayBuf {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -181,3 +184,24 @@ impl Default for RawArrayBuf {
         Self::new()
     }
 }
+
+impl TryFrom<&crate::Array> for RawArrayBuf {
+    type Error = crate::error::Error;
+
+    fn try_from(value: &crate::Array) -> Result<Self, Self::Error> {
+        Self::try_from(value.clone())
+    }
+}
+
+impl TryFrom<crate::Array> for RawArrayBuf {
+    type Error = crate::error::Error;
+
+    fn try_from(value: crate::Array) -> Result<Self, Self::Error> {
+        let mut tmp = RawArrayBuf::new();
+        for val in value {
+            let raw: super::RawBson = val.try_into()?;
+            tmp.push(raw)?;
+        }
+        Ok(tmp)
+    }
+}
diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index 7bb475a4..fb2c7252 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -1,10 +1,7 @@
 use std::convert::{TryFrom, TryInto};
 
-use serde::{Deserialize, Serialize};
-
 use crate::{
     oid::{self, ObjectId},
-    raw::RAW_BSON_NEWTYPE,
     spec::ElementType,
     Binary,
     Bson,
@@ -23,11 +20,7 @@ use crate::{
     Timestamp,
 };
 
-use super::{
-    serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson},
-    Error,
-    Result,
-};
+use super::{Error, Result};
 
 /// A BSON value backed by owned raw BSON bytes.
 #[derive(Debug, Clone, PartialEq)]
@@ -424,21 +417,25 @@ impl From<DbPointer> for RawBson {
     }
 }
 
-impl<'de> Deserialize<'de> for RawBson {
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for RawBson {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
-        match deserializer
-            .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)?
-        {
+        use super::serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson};
+        match deserializer.deserialize_newtype_struct(
+            crate::raw::RAW_BSON_NEWTYPE,
+            OwnedOrBorrowedRawBsonVisitor,
+        )? {
             OwnedOrBorrowedRawBson::Owned(o) => Ok(o),
             OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_raw_bson()),
         }
     }
 }
 
-impl Serialize for RawBson {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawBson {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -483,18 +480,14 @@ impl TryFrom<RawBson> for Bson {
 }
 
 impl TryFrom<Bson> for RawBson {
-    type Error = Error;
+    type Error = crate::error::Error;
 
-    fn try_from(bson: Bson) -> Result<RawBson> {
+    fn try_from(bson: Bson) -> crate::error::Result<RawBson> {
         Ok(match bson {
             Bson::Double(d) => RawBson::Double(d),
             Bson::String(s) => RawBson::String(s),
-            Bson::Document(doc) => RawBson::Document((&doc).try_into()?),
-            Bson::Array(arr) => RawBson::Array(
-                arr.into_iter()
-                    .map(|b| -> Result<RawBson> { b.try_into() })
-                    .collect::<Result<RawArrayBuf>>()?,
-            ),
+            Bson::Document(doc) => RawBson::Document(doc.try_into()?),
+            Bson::Array(arr) => RawBson::Array(arr.try_into()?),
             Bson::Binary(bin) => RawBson::Binary(bin),
             Bson::ObjectId(id) => RawBson::ObjectId(id),
             Bson::Boolean(b) => RawBson::Boolean(b),
@@ -511,7 +504,7 @@ impl TryFrom<Bson> for RawBson {
             Bson::JavaScriptCodeWithScope(jcws) => {
                 RawBson::JavaScriptCodeWithScope(crate::RawJavaScriptCodeWithScope {
                     code: jcws.code,
-                    scope: (&jcws.scope).try_into()?,
+                    scope: jcws.scope.try_into()?,
                 })
             }
             Bson::Decimal128(d) => RawBson::Decimal128(d),
@@ -531,7 +524,8 @@ pub struct RawJavaScriptCodeWithScope {
     pub scope: RawDocumentBuf,
 }
 
-impl<'de> Deserialize<'de> for RawJavaScriptCodeWithScope {
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for RawJavaScriptCodeWithScope {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
@@ -546,7 +540,8 @@ impl<'de> Deserialize<'de> for RawJavaScriptCodeWithScope {
     }
 }
 
-impl Serialize for RawJavaScriptCodeWithScope {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawJavaScriptCodeWithScope {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index 94a9b9fb..2edceaa7 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -1,21 +1,9 @@
 use std::convert::{TryFrom, TryInto};
 
-use serde::{ser::SerializeStruct, Deserialize, Serialize};
-use serde_bytes::Bytes;
-
-use super::{
-    bson::RawBson,
-    serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson},
-    Error,
-    RawArray,
-    RawDocument,
-    Result,
-};
+use super::{bson::RawBson, Error, RawArray, RawDocument, Result};
 use crate::{
-    base64,
-    extjson,
     oid::{self, ObjectId},
-    raw::{RawJavaScriptCodeWithScope, RAW_BSON_NEWTYPE},
+    raw::RawJavaScriptCodeWithScope,
     spec::{BinarySubtype, ElementType},
     Binary,
     Bson,
@@ -27,6 +15,9 @@ use crate::{
     Timestamp,
 };
 
+#[cfg(feature = "serde")]
+use serde::ser::SerializeStruct as _;
+
 /// A BSON value referencing raw bytes stored elsewhere.
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum RawBsonRef<'a> {
@@ -296,14 +287,17 @@ impl<'a> RawBsonRef<'a> {
     }
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for RawBsonRef<'a> {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for RawBsonRef<'a> {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
-        match deserializer
-            .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)?
-        {
+        use super::serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson};
+        match deserializer.deserialize_newtype_struct(
+            crate::raw::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 {:?}",
@@ -313,7 +307,8 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawBsonRef<'a> {
     }
 }
 
-impl Serialize for RawBsonRef<'_> {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawBsonRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -477,7 +472,8 @@ impl RawBinaryRef<'_> {
     }
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for RawBinaryRef<'a> {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for RawBinaryRef<'a> {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
@@ -492,7 +488,8 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawBinaryRef<'a> {
     }
 }
 
-impl Serialize for RawBinaryRef<'_> {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawBinaryRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -500,7 +497,9 @@ impl Serialize for RawBinaryRef<'_> {
         if let BinarySubtype::Generic = self.subtype {
             serializer.serialize_bytes(self.bytes)
         } else if !serializer.is_human_readable() {
-            #[derive(Serialize)]
+            use serde_bytes::Bytes;
+
+            #[derive(serde::Serialize)]
             struct BorrowedBinary<'a> {
                 bytes: &'a Bytes,
 
@@ -517,8 +516,8 @@ impl Serialize for RawBinaryRef<'_> {
             state.end()
         } else {
             let mut state = serializer.serialize_struct("$binary", 1)?;
-            let body = extjson::models::BinaryBody {
-                base64: base64::encode(self.bytes),
+            let body = crate::extjson::models::BinaryBody {
+                base64: crate::base64::encode(self.bytes),
                 subtype: hex::encode([self.subtype.into()]),
             };
             state.serialize_field("$binary", &body)?;
@@ -555,7 +554,8 @@ pub struct RawRegexRef<'a> {
     pub options: &'a str,
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for RawRegexRef<'a> {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for RawRegexRef<'a> {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
@@ -570,12 +570,13 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawRegexRef<'a> {
     }
 }
 
-impl Serialize for RawRegexRef<'_> {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawRegexRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
-        #[derive(Serialize)]
+        #[derive(serde::Serialize)]
         struct BorrowedRegexBody<'a> {
             pattern: &'a str,
             options: &'a str,
@@ -613,7 +614,8 @@ impl RawJavaScriptCodeWithScopeRef<'_> {
     }
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScopeRef<'a> {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for RawJavaScriptCodeWithScopeRef<'a> {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
@@ -628,7 +630,8 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScopeRef<'a> {
     }
 }
 
-impl Serialize for RawJavaScriptCodeWithScopeRef<'_> {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawJavaScriptCodeWithScopeRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -653,7 +656,8 @@ pub struct RawDbPointerRef<'a> {
     pub(crate) id: ObjectId,
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for RawDbPointerRef<'a> {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for RawDbPointerRef<'a> {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
@@ -668,12 +672,13 @@ impl<'de: 'a, 'a> Deserialize<'de> for RawDbPointerRef<'a> {
     }
 }
 
-impl Serialize for RawDbPointerRef<'_> {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawDbPointerRef<'_> {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
-        #[derive(Serialize)]
+        #[derive(serde::Serialize)]
         struct BorrowedDbPointerBody<'a> {
             #[serde(rename = "$ref")]
             ref_ns: &'a str,
diff --git a/src/raw/document.rs b/src/raw/document.rs
index e62eb62e..262df7ec 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -3,12 +3,8 @@ use std::{
     convert::{TryFrom, TryInto},
 };
 
-use serde::{ser::SerializeMap, Deserialize, Serialize};
-
 use crate::{
-    de::MIN_BSON_DOCUMENT_SIZE,
     error::{Error, Result},
-    raw::{serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE},
     Bson,
     DateTime,
     JavaScriptCodeWithScope,
@@ -29,6 +25,7 @@ use super::{
     RawIter,
     RawRegexRef,
     Result as RawResult,
+    MIN_BSON_DOCUMENT_SIZE,
 };
 use crate::{oid::ObjectId, spec::ElementType, Document};
 
@@ -49,7 +46,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document};
 /// # use bson::error::Error;
 /// use bson::raw::RawDocument;
 ///
-/// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?;
+/// let doc = RawDocument::decode_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");
@@ -66,7 +63,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document};
 /// ```
 /// use bson::raw::RawDocument;
 ///
-/// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?;
+/// let doc = RawDocument::decode_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<dyn std::error::Error>>(())
 /// ```
@@ -92,10 +89,10 @@ impl RawDocument {
     /// ```
     /// use bson::raw::RawDocument;
     ///
-    /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?;
+    /// let doc = RawDocument::decode_from_bytes(b"\x05\0\0\0\0")?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
+    pub fn decode_from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
         let data = data.as_ref();
 
         if data.len() < 5 {
@@ -135,12 +132,12 @@ impl RawDocument {
     /// use bson::raw::{RawDocument, RawDocumentBuf};
     ///
     /// let data = b"\x05\0\0\0\0";
-    /// let doc_ref = RawDocument::from_bytes(data)?;
+    /// let doc_ref = RawDocument::decode_from_bytes(data)?;
     /// let doc: RawDocumentBuf = doc_ref.to_raw_document_buf();
     /// # Ok::<(), bson::error::Error>(())
     pub fn to_raw_document_buf(&self) -> RawDocumentBuf {
         // unwrap is ok here because we already verified the bytes in `RawDocumentRef::new`
-        RawDocumentBuf::from_bytes(self.data.to_owned()).unwrap()
+        RawDocumentBuf::decode_from_bytes(self.data.to_owned()).unwrap()
     }
 
     /// Gets a reference to the value corresponding to the given key by iterating until the key is
@@ -563,11 +560,13 @@ fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
     }
 }
 
-impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
+#[cfg(feature = "serde")]
+impl<'de: 'a, 'a> serde::Deserialize<'de> for &'a RawDocument {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
+        use super::serde::OwnedOrBorrowedRawDocument;
         match OwnedOrBorrowedRawDocument::deserialize(deserializer)? {
             OwnedOrBorrowedRawDocument::Borrowed(b) => Ok(b),
             OwnedOrBorrowedRawDocument::Owned(d) => Err(serde::de::Error::custom(format!(
@@ -578,18 +577,20 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
     }
 }
 
-impl Serialize for &RawDocument {
+#[cfg(feature = "serde")]
+impl serde::Serialize for &RawDocument {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
         struct KvpSerializer<'a>(&'a RawDocument);
 
-        impl Serialize for KvpSerializer<'_> {
+        impl serde::Serialize for KvpSerializer<'_> {
             fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where
                 S: serde::Serializer,
             {
+                use serde::ser::SerializeMap as _;
                 if serializer.is_human_readable() {
                     let mut map = serializer.serialize_map(None)?;
                     for kvp in self.0 {
@@ -602,7 +603,7 @@ impl Serialize for &RawDocument {
                 }
             }
         }
-        serializer.serialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, &KvpSerializer(self))
+        serializer.serialize_newtype_struct(super::RAW_DOCUMENT_NEWTYPE, &KvpSerializer(self))
     }
 }
 
@@ -645,6 +646,22 @@ impl TryFrom<&RawDocument> for crate::Document {
     }
 }
 
+impl TryFrom<RawDocumentBuf> for Document {
+    type Error = crate::error::Error;
+
+    fn try_from(raw: RawDocumentBuf) -> Result<Document> {
+        Document::try_from(raw.as_ref())
+    }
+}
+
+impl TryFrom<&RawDocumentBuf> for Document {
+    type Error = crate::error::Error;
+
+    fn try_from(raw: &RawDocumentBuf) -> Result<Document> {
+        Document::try_from(raw.as_ref())
+    }
+}
+
 impl<'a> IntoIterator for &'a RawDocument {
     type IntoIter = Iter<'a>;
     type Item = RawResult<(&'a str, RawBsonRef<'a>)>;
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index e89ef704..2f5c22b9 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -1,24 +1,12 @@
 use std::{
     borrow::{Borrow, Cow},
     convert::TryFrom,
-    iter::FromIterator,
     ops::Deref,
 };
 
-use serde::{Deserialize, Serialize};
+use crate::{raw::MIN_BSON_DOCUMENT_SIZE, Document};
 
-use crate::{de::MIN_BSON_DOCUMENT_SIZE, Document};
-
-use super::{
-    bson::RawBson,
-    iter::Iter,
-    serde::OwnedOrBorrowedRawDocument,
-    Error,
-    RawBsonRef,
-    RawDocument,
-    RawIter,
-    Result,
-};
+use super::{bson::RawBson, iter::Iter, RawBsonRef, RawDocument, RawIter, Result};
 
 mod raw_writer;
 
@@ -36,7 +24,7 @@ mod raw_writer;
 /// # use bson::error::Error;
 /// use bson::raw::RawDocumentBuf;
 ///
-/// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?;
+/// let doc = RawDocumentBuf::decode_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");
@@ -54,7 +42,7 @@ mod raw_writer;
 /// ```
 /// use bson::raw::RawDocumentBuf;
 ///
-/// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?;
+/// let doc = RawDocumentBuf::decode_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<dyn std::error::Error>>(())
 /// ```
@@ -86,17 +74,31 @@ impl RawDocumentBuf {
     ///
     /// ```
     /// # use bson::raw::RawDocumentBuf;
-    /// let doc = RawDocumentBuf::from_bytes(b"\x05\0\0\0\0".to_vec())?;
+    /// let doc = RawDocumentBuf::decode_from_bytes(b"\x05\0\0\0\0".to_vec())?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn from_bytes(data: Vec<u8>) -> Result<Self> {
-        let _ = RawDocument::from_bytes(data.as_slice())?;
+    pub fn decode_from_bytes(data: Vec<u8>) -> Result<Self> {
+        let _ = RawDocument::decode_from_bytes(data.as_slice())?;
         Ok(Self { data })
     }
 
-    pub fn from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
-        let buf = crate::de::reader_to_vec(reader)?;
-        Self::from_bytes(buf)
+    pub fn decode_from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
+        let buf = crate::raw::reader_to_vec(reader)?;
+        Self::decode_from_bytes(buf)
+    }
+
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<S, B, I>(iter: I) -> Result<Self>
+    where
+        S: AsRef<str>,
+        B: BindRawBsonRef,
+        I: IntoIterator<Item = (S, B)>,
+    {
+        let mut buf = RawDocumentBuf::new();
+        for (k, v) in iter {
+            buf.append(k, v)?;
+        }
+        Ok(buf)
     }
 
     /// Create a [`RawDocumentBuf`] from a [`Document`].
@@ -112,11 +114,13 @@ impl RawDocumentBuf {
     /// let doc = RawDocumentBuf::from_document(&document)?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn from_document(doc: &Document) -> Result<RawDocumentBuf> {
-        let mut data = Vec::new();
-        doc.to_writer(&mut data).map_err(Error::malformed_value)?;
-
-        Ok(Self { data })
+    pub fn from_document(doc: impl Borrow<Document>) -> Result<Self> {
+        let mut out = RawDocumentBuf::new();
+        for (k, v) in doc.borrow() {
+            let val: RawBson = v.clone().try_into()?;
+            out.append(k, val)?;
+        }
+        Ok(out)
     }
 
     /// Gets an iterator over the elements in the [`RawDocumentBuf`], which yields
@@ -211,11 +215,13 @@ impl RawDocumentBuf {
     /// assert_eq!(doc.to_document()?, expected);
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn append(&mut self, key: impl AsRef<str>, value: impl BindRawBsonRef) {
+    pub fn append(
+        &mut self,
+        key: impl AsRef<str>,
+        value: impl BindRawBsonRef,
+    ) -> crate::error::Result<()> {
         value.bind(|value_ref| {
-            raw_writer::RawWriter::new(&mut self.data)
-                .append(key.as_ref(), value_ref)
-                .expect("key should not contain interior null byte")
+            raw_writer::RawWriter::new(&mut self.data).append(key.as_ref(), value_ref)
         })
     }
 }
@@ -226,16 +232,18 @@ impl Default for RawDocumentBuf {
     }
 }
 
-impl<'de> Deserialize<'de> for RawDocumentBuf {
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for RawDocumentBuf {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
-        Ok(OwnedOrBorrowedRawDocument::deserialize(deserializer)?.into_owned())
+        Ok(super::serde::OwnedOrBorrowedRawDocument::deserialize(deserializer)?.into_owned())
     }
 }
 
-impl Serialize for RawDocumentBuf {
+#[cfg(feature = "serde")]
+impl serde::Serialize for RawDocumentBuf {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -265,19 +273,24 @@ impl<'a> From<&'a RawDocumentBuf> for Cow<'a, RawDocument> {
     }
 }
 
-impl TryFrom<RawDocumentBuf> for Document {
-    type Error = Error;
+impl TryFrom<&Document> for RawDocumentBuf {
+    type Error = crate::error::Error;
 
-    fn try_from(raw: RawDocumentBuf) -> Result<Document> {
-        Document::try_from(raw.as_ref())
+    fn try_from(doc: &Document) -> std::result::Result<Self, Self::Error> {
+        RawDocumentBuf::from_document(doc)
     }
 }
 
-impl TryFrom<&Document> for RawDocumentBuf {
-    type Error = Error;
+impl TryFrom<Document> for RawDocumentBuf {
+    type Error = crate::error::Error;
 
-    fn try_from(doc: &Document) -> Result<RawDocumentBuf> {
-        RawDocumentBuf::from_document(doc)
+    fn try_from(doc: Document) -> std::result::Result<Self, Self::Error> {
+        let mut out = RawDocumentBuf::new();
+        for (k, v) in doc {
+            let val: RawBson = v.try_into()?;
+            out.append(k, val)?;
+        }
+        Ok(out)
     }
 }
 
@@ -310,16 +323,6 @@ impl Borrow<RawDocument> for RawDocumentBuf {
     }
 }
 
-impl<S: AsRef<str>, T: BindRawBsonRef> FromIterator<(S, T)> for RawDocumentBuf {
-    fn from_iter<I: IntoIterator<Item = (S, T)>>(iter: I) -> Self {
-        let mut buf = RawDocumentBuf::new();
-        for (k, v) in iter {
-            buf.append(k, v);
-        }
-        buf
-    }
-}
-
 /// Types that can be consumed to produce raw bson references valid for a limited lifetime.
 /// Conceptually a union between `T: Into<RawBson>` and `T: Into<RawBsonRef>`; if your type
 /// implements `Into<RawBsonRef>` it will automatically implement this, but if it only
diff --git a/src/raw/document_buf/raw_writer.rs b/src/raw/document_buf/raw_writer.rs
index 1d6fae22..59edfc82 100644
--- a/src/raw/document_buf/raw_writer.rs
+++ b/src/raw/document_buf/raw_writer.rs
@@ -1,5 +1,5 @@
 use crate::{
-    ser::{write_cstring, write_string},
+    raw::{write_cstring, write_string},
     spec::BinarySubtype,
     RawBsonRef,
 };
@@ -13,7 +13,7 @@ impl<'a> RawWriter<'a> {
         Self { data }
     }
 
-    pub(super) fn append(&mut self, key: &str, value: RawBsonRef) -> crate::ser::Result<()> {
+    pub(super) fn append(&mut self, key: &str, value: RawBsonRef) -> crate::error::Result<()> {
         let original_len = self.data.len();
         self.data[original_len - 1] = value.element_type() as u8;
 
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 8dddbf5b..6c3c640e 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -1,9 +1,8 @@
 use std::convert::TryInto;
 
 use crate::{
-    de::{MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE},
     oid::ObjectId,
-    raw::{Error, Result},
+    raw::{Error, Result, MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE},
     spec::{BinarySubtype, ElementType},
     Bson,
     DateTime,
@@ -144,8 +143,9 @@ impl TryInto<Bson> for RawElement<'_> {
 }
 
 impl<'a> RawElement<'a> {
+    #[cfg(feature = "serde")]
     pub(crate) fn toplevel(bytes: &'a [u8]) -> Result<Self> {
-        let doc = RawDocument::from_bytes(bytes)?;
+        let doc = RawDocument::decode_from_bytes(bytes)?;
         Ok(Self {
             key: "TOPLEVEL",
             kind: ElementType::EmbeddedDocument,
@@ -179,11 +179,11 @@ impl<'a> RawElement<'a> {
             ElementType::Double => RawBsonRef::Double(f64_from_slice(self.slice())?),
             ElementType::String => RawBsonRef::String(self.read_str()?),
             ElementType::EmbeddedDocument => {
-                RawBsonRef::Document(RawDocument::from_bytes(self.slice())?)
-            }
-            ElementType::Array => {
-                RawBsonRef::Array(RawArray::from_doc(RawDocument::from_bytes(self.slice())?))
+                RawBsonRef::Document(RawDocument::decode_from_bytes(self.slice())?)
             }
+            ElementType::Array => RawBsonRef::Array(RawArray::from_doc(
+                RawDocument::decode_from_bytes(self.slice())?,
+            )),
             ElementType::Boolean => RawBsonRef::Boolean(
                 bool_from_slice(self.slice()).map_err(|e| self.malformed_error(e))?,
             ),
@@ -210,9 +210,12 @@ impl<'a> RawElement<'a> {
                         .read_cstring_at(self.start_at + pattern.len() + 1)?,
                 })
             }
-            ElementType::Timestamp => RawBsonRef::Timestamp(
-                Timestamp::from_reader(self.slice()).map_err(|e| self.malformed_error(e))?,
-            ),
+            ElementType::Timestamp => RawBsonRef::Timestamp({
+                let bytes: [u8; 8] = self.slice()[0..8]
+                    .try_into()
+                    .map_err(|e| self.malformed_error(e))?;
+                Timestamp::from_le_bytes(bytes)
+            }),
             ElementType::Binary => {
                 let len = self.size.checked_sub(4 + 1).ok_or_else(|| {
                     self.malformed_error(format!("length exceeds maximum: {}", self.size))
@@ -258,7 +261,7 @@ impl<'a> RawElement<'a> {
                 let slice = self.slice();
                 let code = read_lenencode(&slice[4..])?;
                 let scope_start = 4 + 4 + code.len() + 1;
-                let scope = RawDocument::from_bytes(&slice[scope_start..])?;
+                let scope = RawDocument::decode_from_bytes(&slice[scope_start..])?;
 
                 RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { code, scope })
             }
@@ -284,7 +287,7 @@ impl<'a> RawElement<'a> {
                 let slice = self.slice();
                 let code = String::from_utf8_lossy(read_lenencode_bytes(&slice[4..])?).into_owned();
                 let scope_start = 4 + 4 + code.len() + 1;
-                let scope = RawDocument::from_bytes(&slice[scope_start..])?;
+                let scope = RawDocument::decode_from_bytes(&slice[scope_start..])?;
 
                 Utf8LossyBson::JavaScriptCodeWithScope(Utf8LossyJavaScriptCodeWithScope {
                     code,
diff --git a/src/raw/serde.rs b/src/raw/serde.rs
index 40dc03fb..6e2da2e2 100644
--- a/src/raw/serde.rs
+++ b/src/raw/serde.rs
@@ -108,8 +108,8 @@ impl<'a, 'de: 'a> TryFrom<CowByteBuffer<'de>> for OwnedOrBorrowedRawDocument<'a>
 
     fn try_from(buffer: CowByteBuffer<'de>) -> Result<Self, Self::Error> {
         let doc = match buffer.0 {
-            Some(Cow::Borrowed(borrowed)) => RawDocument::from_bytes(borrowed)?.into(),
-            Some(Cow::Owned(owned)) => RawDocumentBuf::from_bytes(owned)?.into(),
+            Some(Cow::Borrowed(borrowed)) => RawDocument::decode_from_bytes(borrowed)?.into(),
+            Some(Cow::Owned(owned)) => RawDocumentBuf::decode_from_bytes(owned)?.into(),
             None => RawDocumentBuf::new().into(),
         };
         Ok(doc)
@@ -134,14 +134,14 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> {
                 if b.subtype == BinarySubtype::Generic =>
             {
                 Ok(Self::Borrowed(
-                    RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?,
+                    RawDocument::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?,
                 ))
             }
             OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
                 Ok(Self::Owned(
-                    RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?,
+                    RawDocumentBuf::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?,
                 ))
             }
 
@@ -186,13 +186,13 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> {
             OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
-                let doc = RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?;
+                let doc = RawDocument::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?;
                 Ok(Self::Borrowed(RawArray::from_doc(doc)))
             }
             OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
-                let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?;
+                let doc = RawDocumentBuf::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?;
                 Ok(Self::Owned(RawArrayBuf::from_raw_document_buf(doc)))
             }
 
diff --git a/src/raw/serde/bson_visitor.rs b/src/raw/serde/bson_visitor.rs
index 24d7af35..8739321e 100644
--- a/src/raw/serde/bson_visitor.rs
+++ b/src/raw/serde/bson_visitor.rs
@@ -185,12 +185,12 @@ impl OwnedOrBorrowedRawBsonVisitor {
             }
             RAW_DOCUMENT_NEWTYPE => {
                 let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
+                let doc = RawDocument::decode_from_bytes(bson).map_err(SerdeError::custom)?;
                 RawBsonRef::Document(doc).into()
             }
             RAW_ARRAY_NEWTYPE => {
                 let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
+                let doc = RawDocument::decode_from_bytes(bson).map_err(SerdeError::custom)?;
                 RawBsonRef::Array(RawArray::from_doc(doc)).into()
             }
             _ => return Ok(MapParse::Aggregate(first_key)),
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
index 16bbf466..2b5034fa 100644
--- a/src/raw/serde/seeded_visitor.rs
+++ b/src/raw/serde/seeded_visitor.rs
@@ -6,8 +6,7 @@ use serde::{
 };
 
 use crate::{
-    raw::RAW_BSON_NEWTYPE,
-    ser::{write_cstring, write_string},
+    raw::{write_cstring, write_string, RAW_BSON_NEWTYPE},
     spec::{BinarySubtype, ElementType},
     RawBson,
     RawBsonRef,
@@ -294,7 +293,8 @@ impl<'de> Visitor<'de> for SeededVisitor<'_, 'de> {
                         }
                         RawBsonRef::Undefined => Ok(ElementType::Undefined),
                         RawBsonRef::DateTime(dt) => {
-                            self.buffer.append_bytes(&dt.as_le_bytes());
+                            self.buffer
+                                .append_bytes(&dt.timestamp_millis().to_le_bytes());
                             Ok(ElementType::DateTime)
                         }
                         RawBsonRef::Timestamp(ts) => {
diff --git a/src/raw/test.rs b/src/raw/test.rs
index caf1fc99..0bc6db71 100644
--- a/src/raw/test.rs
+++ b/src/raw/test.rs
@@ -120,12 +120,13 @@ fn rawdoc_to_doc() {
     };
 
     let doc: crate::Document = rawdoc.clone().try_into().expect("invalid bson");
-    let round_tripped_bytes = crate::to_vec(&doc).expect("serialize should work");
-    assert_eq!(round_tripped_bytes.as_slice(), rawdoc.as_bytes());
+    #[cfg(feature = "serde")]
+    {
+        let round_tripped_bytes = crate::serialize_to_vec(&doc).expect("serialize should work");
+        assert_eq!(round_tripped_bytes.as_slice(), rawdoc.as_bytes());
+    }
 
-    let mut vec_writer_bytes = vec![];
-    doc.to_writer(&mut vec_writer_bytes)
-        .expect("to writer should work");
+    let vec_writer_bytes = doc.encode_to_vec().expect("encode should work");
     assert_eq!(vec_writer_bytes, rawdoc.into_bytes());
 }
 
@@ -430,7 +431,7 @@ fn into_bson_conversion() {
         "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] },
         "boolean": false,
     };
-    let rawbson = RawBsonRef::Document(RawDocument::from_bytes(rawdoc.as_bytes()).unwrap());
+    let rawbson = RawBsonRef::Document(RawDocument::decode_from_bytes(rawdoc.as_bytes()).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));
@@ -470,12 +471,13 @@ fn into_bson_conversion() {
     );
 }
 
+#[cfg(feature = "serde")]
 #[test]
 fn fuzz_oom() {
     let bytes: &[u8] = &[
         17, 0, 0, 0, 11, 36, 100, 97, 116, 101, 0, 111, 112, 101, 0, 4, 0,
     ];
-    let _ = crate::from_slice::<crate::Document>(bytes);
+    let _ = crate::deserialize_from_slice::<crate::Document>(bytes);
 }
 
 use props::arbitrary_bson;
@@ -485,15 +487,21 @@ use std::convert::TryInto;
 proptest! {
     #[test]
     fn no_crashes(s: Vec<u8>) {
-        let _ = RawDocumentBuf::from_bytes(s);
+        let _ = RawDocumentBuf::decode_from_bytes(s);
     }
 
     #[test]
     fn roundtrip_bson(bson in arbitrary_bson()) {
         let doc = doc! { "bson": bson };
-        let raw = crate::to_vec(&doc);
-        prop_assert!(raw.is_ok());
-        let raw = RawDocumentBuf::from_bytes(raw.unwrap());
+        let bytes = doc.encode_to_vec();
+        prop_assert!(bytes.is_ok());
+        let bytes = bytes.unwrap();
+        #[cfg(feature = "serde")]
+        {
+            let raw = crate::serialize_to_vec(&doc);
+            prop_assert!(raw.is_ok());
+        }
+        let raw = RawDocumentBuf::decode_from_bytes(bytes);
         prop_assert!(raw.is_ok());
         let raw = raw.unwrap();
         let roundtrip: Result<crate::Document> = raw.try_into();
diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs
index 147fa152..fdaeef7f 100644
--- a/src/raw/test/append.rs
+++ b/src/raw/test/append.rs
@@ -1,5 +1,3 @@
-use std::iter::FromIterator;
-
 use crate::{
     oid::ObjectId,
     raw::RawJavaScriptCodeWithScope,
@@ -21,10 +19,13 @@ use crate::{
 
 use pretty_assertions::assert_eq;
 
-fn append_test(expected: Document, append: impl FnOnce(&mut RawDocumentBuf)) {
-    let bytes = crate::to_vec(&expected).unwrap();
+fn append_test(
+    expected: Document,
+    append: impl FnOnce(&mut RawDocumentBuf) -> crate::error::Result<()>,
+) {
+    let bytes = expected.encode_to_vec().unwrap();
     let mut buf = RawDocumentBuf::new();
-    append(&mut buf);
+    assert!(append(&mut buf).is_ok());
     assert_eq!(buf.as_bytes(), bytes);
 }
 
@@ -36,9 +37,10 @@ fn i32() {
         "c": 0_i32
     };
     append_test(expected, |doc| {
-        doc.append("a", -1_i32);
-        doc.append("b", 123_i32);
-        doc.append("c", 0_i32);
+        doc.append("a", -1_i32)?;
+        doc.append("b", 123_i32)?;
+        doc.append("c", 0_i32)?;
+        Ok(())
     });
 }
 
@@ -50,9 +52,10 @@ fn i64() {
         "c": 0_i64
     };
     append_test(expected, |doc| {
-        doc.append("a", -1_i64);
-        doc.append("b", 123_i64);
-        doc.append("c", 0_i64);
+        doc.append("a", -1_i64)?;
+        doc.append("b", 123_i64)?;
+        doc.append("c", 0_i64)?;
+        Ok(())
     });
 }
 
@@ -65,10 +68,11 @@ fn str() {
         "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");
+        doc.append("first", "the quick")?;
+        doc.append("second", "brown fox")?;
+        doc.append("third", "jumped over")?;
+        doc.append("last", "the lazy sheep dog")?;
+        Ok(())
     });
 }
 
@@ -82,11 +86,12 @@ fn double() {
         "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);
+        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)?;
+        Ok(())
     });
 }
 
@@ -97,8 +102,9 @@ fn boolean() {
         "false": false,
     };
     append_test(expected, |doc| {
-        doc.append("true", true);
-        doc.append("false", false);
+        doc.append("true", true)?;
+        doc.append("false", false)?;
+        Ok(())
     });
 }
 
@@ -107,9 +113,7 @@ fn null() {
     let expected = doc! {
         "null": null,
     };
-    append_test(expected, |doc| {
-        doc.append("null", RawBson::Null);
-    });
+    append_test(expected, |doc| doc.append("null", RawBson::Null));
 }
 
 #[test]
@@ -122,11 +126,12 @@ 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);
+        buf.append("a", 1_i32)?;
+        buf.append("b", true)?;
+        doc.append("subdoc", buf)?;
+        Ok(())
     });
 }
 
@@ -142,15 +147,16 @@ fn array() {
         ]
     };
     append_test(expected, |doc| {
-        doc.append("empty", RawArrayBuf::new());
+        doc.append("empty", RawArrayBuf::new())?;
         let mut buf = RawArrayBuf::new();
-        buf.push(true);
-        buf.push("string");
+        buf.push(true)?;
+        buf.push("string")?;
         let mut subdoc = RawDocumentBuf::new();
-        subdoc.append("a", "subdoc");
-        buf.push(subdoc);
-        buf.push(123_i32);
-        doc.append("array", buf);
+        subdoc.append("a", "subdoc")?;
+        buf.push(subdoc)?;
+        buf.push(123_i32)?;
+        doc.append("array", buf)?;
+        Ok(())
     });
 }
 
@@ -176,8 +182,9 @@ fn datetime() {
     };
 
     append_test(expected, |doc| {
-        doc.append("now", dt);
-        doc.append("old", old);
+        doc.append("now", dt)?;
+        doc.append("old", old)?;
+        Ok(())
     });
 }
 
@@ -192,9 +199,7 @@ fn timestamp() {
         "ts": ts,
     };
 
-    append_test(expected, |doc| {
-        doc.append("ts", ts);
-    });
+    append_test(expected, |doc| doc.append("ts", ts));
 }
 
 #[test]
@@ -217,8 +222,9 @@ fn binary() {
     };
 
     append_test(expected, |doc| {
-        doc.append("generic", bin);
-        doc.append("binary_old", old);
+        doc.append("generic", bin)?;
+        doc.append("binary_old", old)?;
+        Ok(())
     });
 }
 
@@ -230,8 +236,9 @@ fn min_max_key() {
     };
 
     append_test(expected, |doc| {
-        doc.append("min", RawBson::MinKey);
-        doc.append("max", RawBson::MaxKey);
+        doc.append("min", RawBson::MinKey)?;
+        doc.append("max", RawBson::MaxKey)?;
+        Ok(())
     });
 }
 
@@ -241,9 +248,7 @@ fn undefined() {
         "undefined": Bson::Undefined,
     };
 
-    append_test(expected, |doc| {
-        doc.append("undefined", RawBson::Undefined);
-    });
+    append_test(expected, |doc| doc.append("undefined", RawBson::Undefined));
 }
 
 #[test]
@@ -253,7 +258,7 @@ fn regex() {
     };
 
     append_test(expected, |doc| {
-        doc.append("regex", Regex::new("some pattern", "abc"));
+        doc.append("regex", Regex::new("some pattern", "abc"))
     });
 }
 
@@ -270,18 +275,19 @@ fn code() {
     };
 
     append_test(expected, |doc| {
-        doc.append("code", RawBson::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);
+        scope.append("a", 1_i32)?;
+        scope.append("b", true)?;
         doc.append(
             "code_w_scope",
             RawJavaScriptCodeWithScope {
                 code: "some code".to_string(),
                 scope,
             },
-        );
+        )?;
+        Ok(())
     });
 }
 
@@ -292,7 +298,7 @@ fn symbol() {
     };
 
     append_test(expected, |doc| {
-        doc.append("symbol", RawBson::Symbol("symbol".to_string()));
+        doc.append("symbol", RawBson::Symbol("symbol".to_string()))
     });
 }
 
@@ -316,7 +322,7 @@ fn dbpointer() {
                 namespace: "ns".to_string(),
                 id,
             }),
-        );
+        )
     });
 }
 
@@ -327,9 +333,7 @@ fn decimal128() {
         "decimal": decimal
     };
 
-    append_test(expected, |doc| {
-        doc.append("decimal", decimal);
-    });
+    append_test(expected, |doc| doc.append("decimal", decimal));
 }
 
 #[test]
@@ -348,33 +352,34 @@ fn general() {
     };
 
     append_test(expected, |doc| {
-        doc.append("a", true);
-        doc.append("second key", 123.4);
-        doc.append("third", 15_i64);
-        doc.append("32", -100101_i32);
+        doc.append("a", true)?;
+        doc.append("second key", 123.4)?;
+        doc.append("third", 15_i64)?;
+        doc.append("32", -100101_i32)?;
 
         let mut subdoc = RawDocumentBuf::new();
-        subdoc.append("a", "subkey");
+        subdoc.append("a", "subkey")?;
 
         let mut subsubdoc = RawDocumentBuf::new();
-        subsubdoc.append("subdoc", dt);
-        subdoc.append("another", subsubdoc);
-        doc.append("subdoc", subdoc);
+        subsubdoc.append("subdoc", dt)?;
+        subdoc.append("another", subsubdoc)?;
+        doc.append("subdoc", subdoc)?;
 
         let mut array = RawArrayBuf::new();
-        array.push(1_i64);
-        array.push(true);
+        array.push(1_i64)?;
+        array.push(true)?;
 
         let mut array_subdoc = RawDocumentBuf::new();
-        array_subdoc.append("doc", 23_i64);
-        array.push(array_subdoc);
+        array_subdoc.append("doc", 23_i64)?;
+        array.push(array_subdoc)?;
 
         let mut sub_array = RawArrayBuf::new();
-        sub_array.push("another");
-        sub_array.push("array");
-        array.push(sub_array);
+        sub_array.push("another")?;
+        sub_array.push("array")?;
+        array.push(sub_array)?;
 
-        doc.append("array", array);
+        doc.append("array", array)?;
+        Ok(())
     });
 }
 
@@ -383,17 +388,24 @@ 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".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())),
+                        ])
+                        .unwrap(),
+                    ),
+                ])
+                .unwrap(),
+            ),
         ),
         ("bool", RawBson::Boolean(true)),
         ("string", RawBson::String("some string".to_string())),
-    ]);
+    ])
+    .unwrap();
 
     let doc = doc! {
         "array": [
@@ -408,24 +420,22 @@ fn from_iter() {
     };
 
     let expected = doc! { "expected": doc };
-    append_test(expected, |doc| {
-        doc.append("expected", doc_buf);
-    });
+    append_test(expected, |doc| doc.append("expected", doc_buf));
 }
 
 #[test]
 fn array_buf() {
     let mut arr_buf = RawArrayBuf::new();
-    arr_buf.push(true);
+    arr_buf.push(true).unwrap();
 
     let mut doc_buf = RawDocumentBuf::new();
-    doc_buf.append("x", 3_i32);
-    doc_buf.append("string", "string");
-    arr_buf.push(doc_buf);
+    doc_buf.append("x", 3_i32).unwrap();
+    doc_buf.append("string", "string").unwrap();
+    arr_buf.push(doc_buf).unwrap();
 
     let mut sub_arr = RawArrayBuf::new();
-    sub_arr.push("a string");
-    arr_buf.push(sub_arr);
+    sub_arr.push("a string").unwrap();
+    arr_buf.push(sub_arr).unwrap();
 
     let arr = rawbson!([
         true,
diff --git a/src/ser.rs b/src/ser.rs
index 65f6c9b1..43ead226 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -43,21 +43,6 @@ use crate::{
     RawDocumentBuf,
 };
 
-pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
-    buf.extend(&(s.len() as i32 + 1).to_le_bytes());
-    buf.extend(s.as_bytes());
-    buf.push(0);
-}
-
-pub(crate) fn write_cstring(buf: &mut Vec<u8>, s: &str) -> Result<()> {
-    if s.contains('\0') {
-        return Err(Error::InvalidCString(s.into()));
-    }
-    buf.extend(s.as_bytes());
-    buf.push(0);
-    Ok(())
-}
-
 #[inline]
 pub(crate) fn write_i32<W: Write + ?Sized>(writer: &mut W, val: i32) -> Result<()> {
     writer
@@ -110,10 +95,10 @@ fn write_binary<W: Write>(mut writer: W, bytes: &[u8], subtype: BinarySubtype) -
 /// Encode a `T` Serializable into a [`Bson`] value.
 ///
 /// The [`Serializer`] used by this function presents itself as human readable, whereas the
-/// one used in [`to_vec`] does not. This means that this function will produce different BSON than
-/// [`to_vec`] for types that change their serialization output depending on whether
-/// the format is human readable or not.
-pub fn to_bson<T>(value: &T) -> Result<Bson>
+/// one used in [`serialize_to_vec`] does not. This means that this function will produce different
+/// BSON than [`serialize_to_vec`] for types that change their serialization output depending on
+/// whether the format is human readable or not.
+pub fn serialize_to_bson<T>(value: &T) -> Result<Bson>
 where
     T: Serialize + ?Sized,
 {
@@ -135,17 +120,17 @@ where
     value.serialize(ser)
 }
 
-/// Encode a `T` Serializable into a BSON [`Document`].
+/// Serialize a `T` Serializable into a BSON [`Document`].
 ///
 /// The [`Serializer`] used by this function presents itself as human readable, whereas the
-/// one used in [`to_vec`] does not. This means that this function will produce different BSON than
-/// [`to_vec`] for types that change their serialization output depending on whether
-/// the format is human readable or not.
-pub fn to_document<T>(value: &T) -> Result<Document>
+/// one used in [`serialize_to_vec`] does not. This means that this function will produce different
+/// BSON than [`serialize_to_vec`] for types that change their serialization output depending on
+/// whether the format is human readable or not.
+pub fn serialize_to_document<T>(value: &T) -> Result<Document>
 where
     T: Serialize + ?Sized,
 {
-    match to_bson(value)? {
+    match serialize_to_bson(value)? {
         Bson::Document(doc) => Ok(doc),
         bson => Err(Error::SerializationError {
             message: format!(
@@ -158,7 +143,7 @@ where
 
 /// Serialize the given `T` as a BSON byte vector.
 #[inline]
-pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
+pub fn serialize_to_vec<T>(value: &T) -> Result<Vec<u8>>
 where
     T: Serialize,
 {
@@ -187,14 +172,14 @@ where
 /// }
 ///
 /// let cat = Cat { name: "Garfield".to_string(), age: 43 };
-/// let doc = bson::to_raw_document_buf(&cat)?;
+/// let doc = bson::serialize_to_raw_document_buf(&cat)?;
 /// assert_eq!(doc, rawdoc! { "name": "Garfield", "age": 43 });
 /// # Ok::<(), Box<dyn std::error::Error>>(())
 /// ```
 #[inline]
-pub fn to_raw_document_buf<T>(value: &T) -> Result<RawDocumentBuf>
+pub fn serialize_to_raw_document_buf<T>(value: &T) -> Result<RawDocumentBuf>
 where
     T: Serialize,
 {
-    RawDocumentBuf::from_bytes(to_vec(value)?).map_err(Error::custom)
+    RawDocumentBuf::decode_from_bytes(serialize_to_vec(value)?).map_err(Error::custom)
 }
diff --git a/src/ser/error.rs b/src/ser/error.rs
index 6f3b8877..1bddb7df 100644
--- a/src/ser/error.rs
+++ b/src/ser/error.rs
@@ -14,9 +14,6 @@ pub enum Error {
     /// A key could not be serialized to a BSON string.
     InvalidDocumentKey(Bson),
 
-    /// An invalid string was specified.
-    InvalidCString(String),
-
     /// A general error that occurred during serialization.
     /// See: <https://docs.rs/serde/1.0.110/serde/ser/trait.Error.html#tymethod.custom>
     #[non_exhaustive]
@@ -38,6 +35,9 @@ pub enum Error {
         /// The original error.
         source: Box<Error>,
     },
+
+    /// TODO RUST-1406 remove this
+    Crate(Arc<crate::error::Error>),
 }
 
 impl Error {
@@ -68,14 +68,17 @@ impl From<io::Error> for Error {
     }
 }
 
+impl From<crate::error::Error> for Error {
+    fn from(err: crate::error::Error) -> Error {
+        Error::Crate(Arc::new(err))
+    }
+}
+
 impl fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Error::Io(inner) => inner.fmt(fmt),
             Error::InvalidDocumentKey(key) => write!(fmt, "Invalid map key type: {}", key),
-            Error::InvalidCString(ref string) => {
-                write!(fmt, "cstrings cannot contain null bytes: {:?}", string)
-            }
             Error::SerializationError { message } => message.fmt(fmt),
             Error::UnsignedIntegerExceededRange(value) => write!(
                 fmt,
@@ -86,6 +89,7 @@ impl fmt::Display for Error {
             ),
             #[cfg(feature = "serde_path_to_error")]
             Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source),
+            Error::Crate(inner) => inner.fmt(fmt),
         }
     }
 }
diff --git a/src/ser/raw.rs b/src/ser/raw.rs
index 69b7320e..480fdd46 100644
--- a/src/ser/raw.rs
+++ b/src/ser/raw.rs
@@ -10,9 +10,9 @@ use serde::{
 
 use self::value_serializer::{ValueSerializer, ValueType};
 
-use super::{write_binary, write_cstring, write_f64, write_i32, write_i64, write_string};
+use super::{write_binary, write_f64, write_i32, write_i64};
 use crate::{
-    raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    raw::{write_cstring, write_string, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     ser::{Error, Result},
     serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index 114a11e9..10e3b93e 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -1,8 +1,9 @@
 use serde::{ser::Impossible, Serialize};
 
 use crate::{
-    ser::{write_cstring, write_i32, Error, Result},
-    to_bson,
+    raw::write_cstring,
+    ser::{write_i32, Error, Result},
+    serialize_to_bson,
     Bson,
 };
 
@@ -185,7 +186,7 @@ struct KeySerializer<'a> {
 
 impl KeySerializer<'_> {
     fn invalid_key<T: Serialize>(v: T) -> Error {
-        Error::InvalidDocumentKey(to_bson(&v).unwrap_or(Bson::Null))
+        Error::InvalidDocumentKey(serialize_to_bson(&v).unwrap_or(Bson::Null))
     }
 }
 
@@ -264,7 +265,7 @@ impl serde::Serializer for KeySerializer<'_> {
 
     #[inline]
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
-        write_cstring(&mut self.root_serializer.bytes, v)
+        Ok(write_cstring(&mut self.root_serializer.bytes, v)?)
     }
 
     #[inline]
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 8c0b2215..45a4ff6a 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -8,8 +8,8 @@ use serde::{
 use crate::{
     base64,
     oid::ObjectId,
-    raw::RAW_DOCUMENT_NEWTYPE,
-    ser::{write_binary, write_cstring, write_i32, write_i64, write_string, Error, Result},
+    raw::{write_cstring, write_string, RAW_DOCUMENT_NEWTYPE},
+    ser::{write_binary, write_i32, write_i64, Error, Result},
     spec::{BinarySubtype, ElementType},
     RawDocument,
     RawJavaScriptCodeWithScopeRef,
@@ -311,7 +311,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::CodeWithScopeScope { ref code, raw } if raw => {
                 let raw = RawJavaScriptCodeWithScopeRef {
                     code,
-                    scope: RawDocument::from_bytes(v).map_err(Error::custom)?,
+                    scope: RawDocument::decode_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/ser/serde.rs b/src/ser/serde.rs
index 053f1e93..99abc7c9 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -305,7 +305,8 @@ impl ser::Serializer for Serializer {
                 .serialize(self)?
             {
                 Bson::Binary(b) => {
-                    let doc = Document::from_reader(b.bytes.as_slice()).map_err(Error::custom)?;
+                    let doc =
+                        Document::decode_from_reader(b.bytes.as_slice()).map_err(Error::custom)?;
 
                     if name == RAW_DOCUMENT_NEWTYPE {
                         Ok(Bson::Document(doc))
diff --git a/src/tests.rs b/src/tests.rs
index a3134674..2093ae83 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -1,8 +1,11 @@
 mod binary_subtype;
 mod datetime;
 mod modules;
+#[cfg(feature = "serde")]
 mod serde;
+#[cfg(feature = "serde")]
 mod serde_helpers;
+#[cfg(feature = "serde")]
 mod spec;
 
 use modules::TestLock;
diff --git a/src/tests/modules.rs b/src/tests/modules.rs
index d55a287e..c37da5af 100644
--- a/src/tests/modules.rs
+++ b/src/tests/modules.rs
@@ -4,7 +4,9 @@ mod document;
 mod lock;
 mod macros;
 mod oid;
+#[cfg(feature = "serde")]
 mod ser;
+#[cfg(feature = "serde")]
 mod serializer_deserializer;
 
 pub use self::lock::TestLock;
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index c3ccabeb..2f80e7c5 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -18,7 +18,7 @@ use crate::{
     Timestamp,
 };
 
-use serde_json::{json, Value};
+use serde_json::Value;
 
 #[test]
 fn to_json() {
@@ -173,8 +173,10 @@ fn from_impls() {
         Bson::from(vec![1, 2, 3]),
         Bson::Array(vec![Bson::Int32(1), Bson::Int32(2), Bson::Int32(3)])
     );
+    #[cfg(feature = "serde")]
     assert_eq!(
-        Bson::try_from(json!({"_id": {"$oid": oid.to_hex()}, "name": ["bson-rs"]})).unwrap(),
+        Bson::try_from(serde_json::json!({"_id": {"$oid": oid.to_hex()}, "name": ["bson-rs"]}))
+            .unwrap(),
         Bson::Document(doc! {"_id": &oid, "name": ["bson-rs"]})
     );
 
@@ -204,15 +206,18 @@ fn from_impls() {
     assert_eq!(doc! {"x": Some(4)}, doc! {"x": 4});
     assert_eq!(doc! {"x": None::<i32>}, doc! {"x": Bson::Null});
 
-    let db_pointer = Bson::try_from(json!({
-        "$dbPointer": {
-            "$ref": "db.coll",
-            "$id": { "$oid": "507f1f77bcf86cd799439011" },
-        }
-    }))
-    .unwrap();
-    let db_pointer = db_pointer.as_db_pointer().unwrap();
-    assert_eq!(Bson::from(db_pointer), Bson::DbPointer(db_pointer.clone()));
+    #[cfg(feature = "serde")]
+    {
+        let db_pointer = Bson::try_from(serde_json::json!({
+            "$dbPointer": {
+                "$ref": "db.coll",
+                "$id": { "$oid": "507f1f77bcf86cd799439011" },
+            }
+        }))
+        .unwrap();
+        let db_pointer = db_pointer.as_db_pointer().unwrap();
+        assert_eq!(Bson::from(db_pointer), Bson::DbPointer(db_pointer.clone()));
+    }
 }
 
 #[test]
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
index 12e718dd..642dfe58 100644
--- a/src/tests/modules/macros.rs
+++ b/src/tests/modules/macros.rs
@@ -46,29 +46,6 @@ fn standard_format() {
         "date": Bson::DateTime(crate::DateTime::from_time_0_3(date)),
     };
 
-    let rawdoc = rawdoc! {
-        "float": 2.4,
-        "string": "hello",
-        "array": ["testing", 1, true, [1, 2]],
-        "doc": {
-            "fish": "in",
-            "a": "barrel",
-            "!": 1,
-        },
-        "bool": true,
-        "null": null,
-        "regexp": Regex { pattern: "s[ao]d".to_owned(), options: "i".to_owned() },
-        "with_wrapped_parens": (-20),
-        "code": RawBson::JavaScriptCode("function(x) { return x._id; }".to_owned()),
-        "i32": 12,
-        "i64": -55,
-        "timestamp": Timestamp { time: 0, increment: 229_999_444 },
-        "binary": Binary { subtype: BinarySubtype::Md5, bytes: "thingies".to_owned().into_bytes() },
-        "encrypted": Binary { subtype: BinarySubtype::Encrypted, bytes: "secret".to_owned().into_bytes() },
-        "_id": id,
-        "date": crate::DateTime::from_time_0_3(date),
-    };
-
     let ts_nanos = date.unix_timestamp_nanos();
     let ts_millis = ts_nanos - (ts_nanos % 1_000_000);
     let date_trunc = time::OffsetDateTime::from_unix_timestamp_nanos(ts_millis).unwrap();
@@ -87,7 +64,32 @@ fn standard_format() {
 
     assert_eq!(expected, format!("{}", doc));
 
-    assert_eq!(rawdoc.into_bytes(), crate::to_vec(&doc).unwrap());
+    #[cfg(feature = "serde")]
+    {
+        let rawdoc = rawdoc! {
+            "float": 2.4,
+            "string": "hello",
+            "array": ["testing", 1, true, [1, 2]],
+            "doc": {
+                "fish": "in",
+                "a": "barrel",
+                "!": 1,
+            },
+            "bool": true,
+            "null": null,
+            "regexp": Regex { pattern: "s[ao]d".to_owned(), options: "i".to_owned() },
+            "with_wrapped_parens": (-20),
+            "code": RawBson::JavaScriptCode("function(x) { return x._id; }".to_owned()),
+            "i32": 12,
+            "i64": -55,
+            "timestamp": Timestamp { time: 0, increment: 229_999_444 },
+            "binary": Binary { subtype: BinarySubtype::Md5, bytes: "thingies".to_owned().into_bytes() },
+            "encrypted": Binary { subtype: BinarySubtype::Encrypted, bytes: "secret".to_owned().into_bytes() },
+            "_id": id,
+            "date": crate::DateTime::from_time_0_3(date),
+        };
+        assert_eq!(rawdoc.into_bytes(), crate::serialize_to_vec(&doc).unwrap());
+    }
 }
 
 #[test]
@@ -124,24 +126,6 @@ fn recursive_macro() {
         "e": { "single": "test" },
         "n": (Bson::Null),
     };
-    let rawdoc = rawdoc! {
-        "a": "foo",
-        "b": {
-            "bar": {
-                "harbor": ["seal", false],
-                "jelly": 42.0,
-            },
-            "grape": 27,
-        },
-        "c": [-7],
-        "d": [
-            {
-                "apple": "ripe",
-            }
-        ],
-        "e": { "single": "test" },
-        "n": (RawBson::Null),
-    };
 
     match doc.get("a") {
         Some(Bson::String(s)) => assert_eq!("foo", s),
@@ -241,7 +225,28 @@ fn recursive_macro() {
         _ => panic!("Null was not inserted correctly."),
     }
 
-    assert_eq!(rawdoc.into_bytes(), crate::to_vec(&doc).unwrap());
+    #[cfg(feature = "serde")]
+    {
+        let rawdoc = rawdoc! {
+            "a": "foo",
+            "b": {
+                "bar": {
+                    "harbor": ["seal", false],
+                    "jelly": 42.0,
+                },
+                "grape": 27,
+            },
+            "c": [-7],
+            "d": [
+                {
+                    "apple": "ripe",
+                }
+            ],
+            "e": { "single": "test" },
+            "n": (RawBson::Null),
+        };
+        assert_eq!(rawdoc.into_bytes(), crate::serialize_to_vec(&doc).unwrap());
+    }
 }
 
 #[test]
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index aa95651c..9eb839db 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -2,17 +2,27 @@ use std::collections::BTreeMap;
 
 use assert_matches::assert_matches;
 
-use crate::{from_bson, oid::ObjectId, ser, tests::LOCK, to_bson, to_vec, Bson, Document, Regex};
+use crate::{
+    deserialize_from_bson,
+    oid::ObjectId,
+    ser,
+    serialize_to_bson,
+    serialize_to_vec,
+    tests::LOCK,
+    Bson,
+    Document,
+    Regex,
+};
 
 #[test]
 #[allow(clippy::float_cmp)]
 fn floating_point() {
     let _guard = LOCK.run_concurrently();
     let obj = Bson::Double(240.5);
-    let f: f64 = from_bson(obj.clone()).unwrap();
+    let f: f64 = deserialize_from_bson(obj.clone()).unwrap();
     assert_eq!(f, 240.5);
 
-    let deser: Bson = to_bson(&f).unwrap();
+    let deser: Bson = serialize_to_bson(&f).unwrap();
     assert_eq!(obj, deser);
 }
 
@@ -20,10 +30,10 @@ fn floating_point() {
 fn string() {
     let _guard = LOCK.run_concurrently();
     let obj = Bson::String("avocado".to_owned());
-    let s: String = from_bson(obj.clone()).unwrap();
+    let s: String = deserialize_from_bson(obj.clone()).unwrap();
     assert_eq!(s, "avocado");
 
-    let deser: Bson = to_bson(&s).unwrap();
+    let deser: Bson = serialize_to_bson(&s).unwrap();
     assert_eq!(obj, deser);
 }
 
@@ -36,10 +46,10 @@ fn arr() {
         Bson::Int32(2),
         Bson::Int32(3),
     ]);
-    let arr: Vec<i32> = from_bson(obj.clone()).unwrap();
+    let arr: Vec<i32> = deserialize_from_bson(obj.clone()).unwrap();
     assert_eq!(arr, vec![0i32, 1i32, 2i32, 3i32]);
 
-    let deser: Bson = to_bson(&arr).unwrap();
+    let deser: Bson = serialize_to_bson(&arr).unwrap();
     assert_eq!(deser, obj);
 }
 
@@ -47,10 +57,10 @@ fn arr() {
 fn boolean() {
     let _guard = LOCK.run_concurrently();
     let obj = Bson::Boolean(true);
-    let b: bool = from_bson(obj.clone()).unwrap();
+    let b: bool = deserialize_from_bson(obj.clone()).unwrap();
     assert!(b);
 
-    let deser: Bson = to_bson(&b).unwrap();
+    let deser: Bson = serialize_to_bson(&b).unwrap();
     assert_eq!(deser, obj);
 }
 
@@ -58,58 +68,58 @@ fn boolean() {
 fn int32() {
     let _guard = LOCK.run_concurrently();
     let obj = Bson::Int32(101);
-    let i: i32 = from_bson(obj.clone()).unwrap();
+    let i: i32 = deserialize_from_bson(obj.clone()).unwrap();
 
     assert_eq!(i, 101);
 
-    let deser: Bson = to_bson(&i).unwrap();
+    let deser: Bson = serialize_to_bson(&i).unwrap();
     assert_eq!(deser, obj);
 }
 
 #[test]
 fn uint8_u2i() {
     let _guard = LOCK.run_concurrently();
-    let obj: Bson = to_bson(&u8::MIN).unwrap();
-    let deser: u8 = from_bson(obj).unwrap();
+    let obj: Bson = serialize_to_bson(&u8::MIN).unwrap();
+    let deser: u8 = deserialize_from_bson(obj).unwrap();
     assert_eq!(deser, u8::MIN);
 
-    let obj_max: Bson = to_bson(&u8::MAX).unwrap();
-    let deser_max: u8 = from_bson(obj_max).unwrap();
+    let obj_max: Bson = serialize_to_bson(&u8::MAX).unwrap();
+    let deser_max: u8 = deserialize_from_bson(obj_max).unwrap();
     assert_eq!(deser_max, u8::MAX);
 }
 
 #[test]
 fn uint16_u2i() {
     let _guard = LOCK.run_concurrently();
-    let obj: Bson = to_bson(&u16::MIN).unwrap();
-    let deser: u16 = from_bson(obj).unwrap();
+    let obj: Bson = serialize_to_bson(&u16::MIN).unwrap();
+    let deser: u16 = deserialize_from_bson(obj).unwrap();
     assert_eq!(deser, u16::MIN);
 
-    let obj_max: Bson = to_bson(&u16::MAX).unwrap();
-    let deser_max: u16 = from_bson(obj_max).unwrap();
+    let obj_max: Bson = serialize_to_bson(&u16::MAX).unwrap();
+    let deser_max: u16 = deserialize_from_bson(obj_max).unwrap();
     assert_eq!(deser_max, u16::MAX);
 }
 
 #[test]
 fn uint32_u2i() {
     let _guard = LOCK.run_concurrently();
-    let obj_min: Bson = to_bson(&u32::MIN).unwrap();
-    let deser_min: u32 = from_bson(obj_min).unwrap();
+    let obj_min: Bson = serialize_to_bson(&u32::MIN).unwrap();
+    let deser_min: u32 = deserialize_from_bson(obj_min).unwrap();
     assert_eq!(deser_min, u32::MIN);
 
-    let obj_max: Bson = to_bson(&u32::MAX).unwrap();
-    let deser_max: u32 = from_bson(obj_max).unwrap();
+    let obj_max: Bson = serialize_to_bson(&u32::MAX).unwrap();
+    let deser_max: u32 = deserialize_from_bson(obj_max).unwrap();
     assert_eq!(deser_max, u32::MAX);
 }
 
 #[test]
 fn uint64_u2i() {
     let _guard = LOCK.run_concurrently();
-    let obj_min: Bson = to_bson(&u64::MIN).unwrap();
-    let deser_min: u64 = from_bson(obj_min).unwrap();
+    let obj_min: Bson = serialize_to_bson(&u64::MIN).unwrap();
+    let deser_min: u64 = deserialize_from_bson(obj_min).unwrap();
     assert_eq!(deser_min, u64::MIN);
 
-    let err: ser::Error = to_bson(&u64::MAX).unwrap_err().strip_path();
+    let err: ser::Error = serialize_to_bson(&u64::MAX).unwrap_err().strip_path();
     assert_matches!(err, ser::Error::UnsignedIntegerExceededRange(u64::MAX));
 }
 
@@ -117,10 +127,10 @@ fn uint64_u2i() {
 fn int64() {
     let _guard = LOCK.run_concurrently();
     let obj = Bson::Int64(101);
-    let i: i64 = from_bson(obj.clone()).unwrap();
+    let i: i64 = deserialize_from_bson(obj.clone()).unwrap();
     assert_eq!(i, 101);
 
-    let deser: Bson = to_bson(&i).unwrap();
+    let deser: Bson = serialize_to_bson(&i).unwrap();
     assert_eq!(deser, obj);
 }
 
@@ -129,13 +139,13 @@ fn oid() {
     let _guard = LOCK.run_concurrently();
     let oid = ObjectId::new();
     let obj = Bson::ObjectId(oid);
-    let s: BTreeMap<String, String> = from_bson(obj.clone()).unwrap();
+    let s: BTreeMap<String, String> = deserialize_from_bson(obj.clone()).unwrap();
 
     let mut expected = BTreeMap::new();
     expected.insert("$oid".to_owned(), oid.to_string());
     assert_eq!(s, expected);
 
-    let deser: Bson = to_bson(&s).unwrap();
+    let deser: Bson = serialize_to_bson(&s).unwrap();
     assert_eq!(deser, obj);
 }
 
@@ -156,14 +166,15 @@ fn cstring_null_bytes_error() {
     verify_doc(regex);
 
     fn verify_doc(doc: Document) {
-        let mut vec = Vec::new();
-        assert!(matches!(
-            doc.to_writer(&mut vec).unwrap_err().strip_path(),
-            ser::Error::InvalidCString(_)
-        ));
-        assert!(matches!(
-            to_vec(&doc).unwrap_err().strip_path(),
-            ser::Error::InvalidCString(_)
-        ));
+        let result = doc.encode_to_vec();
+        assert!(result.is_err(), "unexpected success");
+        let err = result.unwrap_err();
+        assert!(err.is_malformed_value(), "unexpected error: {:?}", err);
+        let result = serialize_to_vec(&doc);
+        assert!(result.is_err(), "unexpected success");
+        match result.unwrap_err().strip_path() {
+            ser::Error::Crate(inner) if inner.is_malformed_value() => (),
+            err => panic!("unexpected error: {:?}", err),
+        };
     }
 }
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 63182cde..2afc6a73 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -6,13 +6,13 @@ use std::{
 use serde::{Deserialize, Serialize};
 
 use crate::{
-    de::from_document,
+    de::deserialize_from_document,
     doc,
     oid::ObjectId,
     ser::Error,
+    serialize_to_document,
     spec::BinarySubtype,
     tests::LOCK,
-    to_document,
     Binary,
     Bson,
     Decimal128,
@@ -35,11 +35,11 @@ fn test_serialize_deserialize_floating_point() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -55,11 +55,11 @@ fn test_serialize_deserialize_utf8_string() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -71,10 +71,10 @@ fn test_encode_decode_utf8_string_invalid() {
     let doc = doc! { "key": &src, "subdoc": { "subkey": &src } };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     let expected = doc! { "key": "��", "subdoc": { "subkey": "��" } };
-    let decoded = RawDocumentBuf::from_reader(&mut Cursor::new(buf))
+    let decoded = RawDocumentBuf::decode_from_reader(&mut Cursor::new(buf))
         .unwrap()
         .to_document_utf8_lossy()
         .unwrap();
@@ -93,11 +93,11 @@ fn test_serialize_deserialize_array() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -113,11 +113,11 @@ fn test_serialize_deserialize() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -130,11 +130,11 @@ fn test_serialize_deserialize_boolean() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -147,11 +147,11 @@ fn test_serialize_deserialize_null() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -167,11 +167,11 @@ fn test_serialize_deserialize_regexp() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -184,11 +184,11 @@ fn test_serialize_deserialize_javascript_code() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -206,11 +206,11 @@ fn test_serialize_deserialize_javascript_code_with_scope() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -223,11 +223,11 @@ fn test_serialize_deserialize_i32() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -242,11 +242,11 @@ fn test_serialize_deserialize_i64() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -264,11 +264,11 @@ fn test_serialize_deserialize_timestamp() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -286,11 +286,11 @@ fn test_serialize_binary_generic() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -305,11 +305,11 @@ fn test_serialize_deserialize_object_id() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -334,11 +334,11 @@ fn test_serialize_utc_date_time() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -353,11 +353,11 @@ fn test_serialize_deserialize_symbol() {
     let doc = doc! { "key": symbol };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -375,7 +375,7 @@ fn test_deserialize_utc_date_time_overflows() {
     raw.write_all(&raw0).unwrap();
     raw.write_all(&[0]).unwrap();
 
-    let deserialized = Document::from_reader(&mut Cursor::new(raw)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(raw)).unwrap();
 
     let expected = doc! { "A": crate::DateTime::from_time_0_3(time::OffsetDateTime::from_unix_timestamp(1_530_492_218).unwrap() + time::Duration::nanoseconds(999 * 1_000_000))};
     assert_eq!(deserialized, expected);
@@ -386,7 +386,7 @@ fn test_deserialize_invalid_utf8_string_issue64() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"\x13\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x00foo\x00\x13\x05\x00\x00\x00";
 
-    assert!(Document::from_reader(&mut Cursor::new(buffer)).is_err());
+    assert!(Document::decode_from_reader(&mut Cursor::new(buffer)).is_err());
 }
 
 #[test]
@@ -394,7 +394,7 @@ fn test_deserialize_multiply_overflows_issue64() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"*\xc9*\xc9\t\x00\x00\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\x01\t\x00\x00\x01\x10";
 
-    assert!(Document::from_reader(&mut Cursor::new(&buffer[..])).is_err());
+    assert!(Document::decode_from_reader(&mut Cursor::new(&buffer[..])).is_err());
 }
 
 #[test]
@@ -410,11 +410,11 @@ fn test_serialize_deserialize_decimal128() {
     let doc = doc! { "key": val };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -424,7 +424,7 @@ fn test_illegal_size() {
     let buffer = [
         0x06, 0xcc, 0xf9, 0x0a, 0x05, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff,
     ];
-    assert!(Document::from_reader(&mut Cursor::new(&buffer[..])).is_err());
+    assert!(Document::decode_from_reader(&mut Cursor::new(&buffer[..])).is_err());
 }
 
 #[test]
@@ -436,11 +436,11 @@ fn test_serialize_deserialize_undefined() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -453,11 +453,11 @@ fn test_serialize_deserialize_min_key() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -470,11 +470,11 @@ fn test_serialize_deserialize_max_key() {
     let doc = doc! {"key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -496,11 +496,11 @@ fn test_serialize_deserialize_db_pointer() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.to_writer(&mut buf).unwrap();
+    doc.encode_to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -515,10 +515,10 @@ fn test_serialize_deserialize_document() {
     }
     let src = Point { x: 1, y: 2 };
 
-    let doc = to_document(&src).unwrap();
+    let doc = serialize_to_document(&src).unwrap();
     assert_eq!(doc, doc! { "x": 1, "y": 2 });
 
-    let point: Point = from_document(doc).unwrap();
+    let point: Point = deserialize_from_document(doc).unwrap();
     assert_eq!(src, point);
 
     #[derive(Debug, Deserialize, Serialize, PartialEq)]
@@ -531,17 +531,17 @@ fn test_serialize_deserialize_document() {
         p2: Point { x: 1, y: 1 },
     };
 
-    let doc = to_document(&src).unwrap();
+    let doc = serialize_to_document(&src).unwrap();
     assert_eq!(
         doc,
         doc! { "p1": { "x": 0, "y": 0 }, "p2": { "x": 1, "y": 1 } }
     );
 
-    let line: Line = from_document(doc).unwrap();
+    let line: Line = deserialize_from_document(doc).unwrap();
     assert_eq!(src, line);
 
     let x = 1;
-    let err = to_document(&x).unwrap_err();
+    let err = serialize_to_document(&x).unwrap_err();
     match err {
         Error::SerializationError { message } => {
             assert!(message.contains("Could not be serialized to Document"));
@@ -550,7 +550,7 @@ fn test_serialize_deserialize_document() {
     }
 
     let bad_point = doc! { "x": "one", "y": "two" };
-    let bad_point: Result<Point, crate::de::Error> = from_document(bad_point);
+    let bad_point: Result<Point, crate::de::Error> = deserialize_from_document(bad_point);
     assert!(bad_point.is_err());
 }
 
@@ -559,7 +559,7 @@ fn test_serialize_deserialize_document() {
 fn test_deserialize_invalid_array_length() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"\n\x00\x00\x00\x04\x00\x00\x00\x00\x00";
-    Document::from_reader(&mut std::io::Cursor::new(buffer))
+    Document::decode_from_reader(&mut std::io::Cursor::new(buffer))
         .expect_err("expected deserialization to fail");
 }
 
@@ -568,10 +568,10 @@ fn test_deserialize_invalid_array_length() {
 fn test_deserialize_invalid_old_binary_length() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"\x0F\x00\x00\x00\x05\x00\x00\x00\x00\x00\x02\xFC\xFF\xFF\xFF";
-    Document::from_reader(&mut std::io::Cursor::new(buffer))
+    Document::decode_from_reader(&mut std::io::Cursor::new(buffer))
         .expect_err("expected deserialization to fail");
 
     let buffer = b".\x00\x00\x00\x05\x01\x00\x00\x00\x00\x00\x02\xfc\xff\xff\xff\xff\xff\xff\xff\x00\x00*\x00h\x0e\x10++\x00h\x0e++\x00\x00\t\x00\x00\x00\x00\x00*\x0e\x10++";
-    Document::from_reader(&mut std::io::Cursor::new(buffer))
+    Document::decode_from_reader(&mut std::io::Cursor::new(buffer))
         .expect_err("expected deserialization to fail");
 }
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index f92d064d..aedc739d 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -2,9 +2,9 @@
 
 use crate::{
     bson,
+    deserialize_from_bson,
+    deserialize_from_document,
     doc,
-    from_bson,
-    from_document,
     oid::ObjectId,
     serde_helpers,
     serde_helpers::{
@@ -16,10 +16,10 @@ use crate::{
         timestamp_as_u32,
         u32_as_timestamp,
     },
+    serialize_to_bson,
+    serialize_to_document,
     spec::BinarySubtype,
     tests::LOCK,
-    to_bson,
-    to_document,
     Binary,
     Bson,
     DateTime,
@@ -106,13 +106,13 @@ fn test_ser_timestamp() {
         },
     };
 
-    let x = to_bson(&foo).unwrap();
+    let x = serialize_to_bson(&foo).unwrap();
     assert_eq!(
         x.as_document().unwrap(),
         &doc! { "ts": Bson::Timestamp(Timestamp { time: 0x0000_000C, increment: 0x0000_000A }) }
     );
 
-    let xfoo: Foo = from_bson(x).unwrap();
+    let xfoo: Foo = deserialize_from_bson(x).unwrap();
     assert_eq!(xfoo, foo);
 }
 
@@ -126,7 +126,7 @@ fn test_de_timestamp() {
         ts: Timestamp,
     }
 
-    let foo: Foo = from_bson(Bson::Document(doc! {
+    let foo: Foo = deserialize_from_bson(Bson::Document(doc! {
         "ts": Bson::Timestamp(Timestamp { time: 0x0000_000C, increment: 0x0000_000A }),
     }))
     .unwrap();
@@ -159,13 +159,13 @@ fn test_ser_regex() {
         regex: regex.clone(),
     };
 
-    let x = to_bson(&foo).unwrap();
+    let x = serialize_to_bson(&foo).unwrap();
     assert_eq!(
         x.as_document().unwrap(),
         &doc! { "regex": Bson::RegularExpression(regex) }
     );
 
-    let xfoo: Foo = from_bson(x).unwrap();
+    let xfoo: Foo = deserialize_from_bson(x).unwrap();
     assert_eq!(xfoo, foo);
 }
 
@@ -184,7 +184,7 @@ fn test_de_regex() {
         options: "01".into(),
     };
 
-    let foo: Foo = from_bson(Bson::Document(doc! {
+    let foo: Foo = deserialize_from_bson(Bson::Document(doc! {
         "regex": Bson::RegularExpression(regex.clone()),
     }))
     .unwrap();
@@ -211,13 +211,13 @@ fn test_ser_code_with_scope() {
         code_with_scope: code_with_scope.clone(),
     };
 
-    let x = to_bson(&foo).unwrap();
+    let x = serialize_to_bson(&foo).unwrap();
     assert_eq!(
         x.as_document().unwrap(),
         &doc! { "code_with_scope": Bson::JavaScriptCodeWithScope(code_with_scope) }
     );
 
-    let xfoo: Foo = from_bson(x).unwrap();
+    let xfoo: Foo = deserialize_from_bson(x).unwrap();
     assert_eq!(xfoo, foo);
 }
 
@@ -236,7 +236,7 @@ fn test_de_code_with_scope() {
         scope: doc! { "x": 12 },
     };
 
-    let foo: Foo = from_bson(Bson::Document(doc! {
+    let foo: Foo = deserialize_from_bson(Bson::Document(doc! {
         "code_with_scope": Bson::JavaScriptCodeWithScope(code_with_scope.clone()),
     }))
     .unwrap();
@@ -258,13 +258,13 @@ fn test_ser_datetime() {
 
     let foo = Foo { date: now };
 
-    let x = to_bson(&foo).unwrap();
+    let x = serialize_to_bson(&foo).unwrap();
     assert_eq!(
         x.as_document().unwrap(),
         &doc! { "date": (Bson::DateTime(now)) }
     );
 
-    let xfoo: Foo = from_bson(x).unwrap();
+    let xfoo: Foo = deserialize_from_bson(x).unwrap();
     assert_eq!(xfoo, foo);
 }
 
@@ -283,13 +283,13 @@ fn test_binary_generic_roundtrip() {
         }),
     };
 
-    let b = to_bson(&x).unwrap();
+    let b = serialize_to_bson(&x).unwrap();
     assert_eq!(
         b.as_document().unwrap(),
         &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })}
     );
 
-    let f = from_bson::<Foo>(b).unwrap();
+    let f = deserialize_from_bson::<Foo>(b).unwrap();
     assert_eq!(x, f);
 }
 
@@ -308,13 +308,13 @@ fn test_binary_non_generic_roundtrip() {
         }),
     };
 
-    let b = to_bson(&x).unwrap();
+    let b = serialize_to_bson(&x).unwrap();
     assert_eq!(
         b.as_document().unwrap(),
         &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::BinaryOld, bytes: b"12345abcde".to_vec() })}
     );
 
-    let f = from_bson::<Foo>(b).unwrap();
+    let f = deserialize_from_bson::<Foo>(b).unwrap();
     assert_eq!(x, f);
 }
 
@@ -333,13 +333,13 @@ fn test_binary_helper_generic_roundtrip() {
         },
     };
 
-    let b = to_bson(&x).unwrap();
+    let b = serialize_to_bson(&x).unwrap();
     assert_eq!(
         b.as_document().unwrap(),
         &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })}
     );
 
-    let f = from_bson::<Foo>(b).unwrap();
+    let f = deserialize_from_bson::<Foo>(b).unwrap();
     assert_eq!(x, f);
 }
 
@@ -358,13 +358,13 @@ fn test_binary_helper_non_generic_roundtrip() {
         },
     };
 
-    let b = to_bson(&x).unwrap();
+    let b = serialize_to_bson(&x).unwrap();
     assert_eq!(
         b.as_document().unwrap(),
         &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::BinaryOld, bytes: b"12345abcde".to_vec() })}
     );
 
-    let f = from_bson::<Foo>(b).unwrap();
+    let f = deserialize_from_bson::<Foo>(b).unwrap();
     assert_eq!(x, f);
 }
 
@@ -381,19 +381,13 @@ fn test_byte_vec() {
         challenge: b"18762b98b7c34c25bf9dc3154e4a5ca3",
     };
 
-    let b = to_bson(&x).unwrap();
+    let b = serialize_to_bson(&x).unwrap();
     assert_eq!(
         b,
         Bson::Document(
             doc! { "challenge": (Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: x.challenge.to_vec() }))}
         )
     );
-
-    // let mut buf = Vec::new();
-    // b.as_document().unwrap().to_writer(&mut buf).unwrap();
-
-    // let xb = Document::from_reader(&mut Cursor::new(buf)).unwrap();
-    // assert_eq!(b.as_document().unwrap(), &xb);
 }
 
 #[test]
@@ -409,13 +403,13 @@ fn test_serde_bytes() {
         data: b"12345abcde".to_vec(),
     };
 
-    let b = to_bson(&x).unwrap();
+    let b = serialize_to_bson(&x).unwrap();
     assert_eq!(
         b.as_document().unwrap(),
         &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })}
     );
 
-    let f = from_bson::<Foo>(b).unwrap();
+    let f = deserialize_from_bson::<Foo>(b).unwrap();
     assert_eq!(x, f);
 }
 
@@ -426,12 +420,12 @@ fn test_serde_newtype_struct() {
     struct Email(String);
 
     let email_1 = Email(String::from("bson@serde.rs"));
-    let b = to_bson(&email_1).unwrap();
+    let b = serialize_to_bson(&email_1).unwrap();
     assert_eq!(b, Bson::String(email_1.0));
 
     let s = String::from("root@localho.st");
     let de = Bson::String(s.clone());
-    let email_2 = from_bson::<Email>(de).unwrap();
+    let email_2 = deserialize_from_bson::<Email>(de).unwrap();
     assert_eq!(email_2, Email(s));
 }
 
@@ -442,12 +436,12 @@ fn test_serde_tuple_struct() {
     struct Name(String, String); // first, last
 
     let name_1 = Name(String::from("Graydon"), String::from("Hoare"));
-    let b = to_bson(&name_1).unwrap();
+    let b = serialize_to_bson(&name_1).unwrap();
     assert_eq!(b, bson!([name_1.0.clone(), name_1.1]));
 
     let (first, last) = (String::from("Donald"), String::from("Knuth"));
     let de = bson!([first.clone(), last.clone()]);
-    let name_2 = from_bson::<Name>(de).unwrap();
+    let name_2 = deserialize_from_bson::<Name>(de).unwrap();
     assert_eq!(name_2, Name(first, last));
 }
 
@@ -463,12 +457,12 @@ fn test_serde_newtype_variant() {
 
     let n = 42;
     let num_1 = Number::Int(n);
-    let b = to_bson(&num_1).unwrap();
+    let b = serialize_to_bson(&num_1).unwrap();
     assert_eq!(b, bson!({ "type": "Int", "value": n }));
 
     let x = 1337.0;
     let de = bson!({ "type": "Float", "value": x });
-    let num_2 = from_bson::<Number>(de).unwrap();
+    let num_2 = deserialize_from_bson::<Number>(de).unwrap();
     assert_eq!(num_2, Number::Float(x));
 }
 
@@ -484,12 +478,12 @@ fn test_serde_tuple_variant() {
     #[allow(clippy::approx_constant)]
     let (x1, y1) = (3.14, -2.71);
     let p1 = Point::TwoDim(x1, y1);
-    let b = to_bson(&p1).unwrap();
+    let b = serialize_to_bson(&p1).unwrap();
     assert_eq!(b, bson!({ "TwoDim": [x1, y1] }));
 
     let (x2, y2, z2) = (0.0, -13.37, 4.2);
     let de = bson!({ "ThreeDim": [x2, y2, z2] });
-    let p2 = from_bson::<Point>(de).unwrap();
+    let p2 = deserialize_from_bson::<Point>(de).unwrap();
     assert_eq!(p2, Point::ThreeDim(x2, y2, z2));
 }
 
@@ -517,13 +511,13 @@ fn test_ser_db_pointer() {
         db_pointer: db_pointer.clone(),
     };
 
-    let x = to_bson(&foo).unwrap();
+    let x = serialize_to_bson(&foo).unwrap();
     assert_eq!(
         x.as_document().unwrap(),
         &doc! {"db_pointer": Bson::DbPointer(db_pointer.clone()) }
     );
 
-    let xfoo: Foo = from_bson(x).unwrap();
+    let xfoo: Foo = deserialize_from_bson(x).unwrap();
     assert_eq!(xfoo, foo);
 }
 
@@ -546,7 +540,7 @@ fn test_de_db_pointer() {
     .unwrap();
     let db_pointer = db_pointer.as_db_pointer().unwrap();
 
-    let foo: Foo = from_bson(Bson::Document(
+    let foo: Foo = deserialize_from_bson(Bson::Document(
         doc! {"db_pointer": Bson::DbPointer(db_pointer.clone())},
     ))
     .unwrap();
@@ -577,7 +571,7 @@ fn test_serde_legacy_uuid_1() {
         csharp_legacy: uuid,
     };
 
-    let x = to_bson(&foo).unwrap();
+    let x = serialize_to_bson(&foo).unwrap();
     assert_eq!(
         x.as_document().unwrap(),
         &doc! {
@@ -596,7 +590,7 @@ fn test_serde_legacy_uuid_1() {
         }
     );
 
-    let foo: Foo = from_bson(x).unwrap();
+    let foo: Foo = deserialize_from_bson(x).unwrap();
     assert_eq!(foo.java_legacy, uuid);
     assert_eq!(foo.python_legacy, uuid);
     assert_eq!(foo.csharp_legacy, uuid);
@@ -608,7 +602,7 @@ fn test_de_uuid_extjson_string() {
 
     let uuid_bson_bytes =
         hex::decode("1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400").unwrap();
-    let uuid_document = Document::from_reader(uuid_bson_bytes.as_slice()).unwrap();
+    let uuid_document = Document::decode_from_reader(uuid_bson_bytes.as_slice()).unwrap();
     let expected_uuid_bson = Bson::from_extended_document(uuid_document);
 
     let ext_json_uuid = "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}";
@@ -677,7 +671,7 @@ fn test_unsigned_helpers() {
     }
 
     let a = A { num_1: 1, num_2: 2 };
-    let doc = to_document(&a).unwrap();
+    let doc = serialize_to_document(&a).unwrap();
     assert!(doc.get_i32("num_1").unwrap() == 1);
     assert!(doc.get_i32("num_2").unwrap() == 2);
 
@@ -685,14 +679,14 @@ fn test_unsigned_helpers() {
         num_1: u32::MAX,
         num_2: 1,
     };
-    let doc_result = to_document(&a);
+    let doc_result = serialize_to_document(&a);
     assert!(doc_result.is_err());
 
     let a = A {
         num_1: 1,
         num_2: u64::MAX,
     };
-    let doc_result = to_document(&a);
+    let doc_result = serialize_to_document(&a);
     assert!(doc_result.is_err());
 
     #[derive(Serialize)]
@@ -707,7 +701,7 @@ fn test_unsigned_helpers() {
         num_1: u32::MAX,
         num_2: i64::MAX as u64,
     };
-    let doc = to_document(&b).unwrap();
+    let doc = serialize_to_document(&b).unwrap();
     assert!(doc.get_i64("num_1").unwrap() == u32::MAX as i64);
     assert!(doc.get_i64("num_2").unwrap() == i64::MAX);
 
@@ -715,7 +709,7 @@ fn test_unsigned_helpers() {
         num_1: 1,
         num_2: i64::MAX as u64 + 1,
     };
-    let doc_result = to_document(&b);
+    let doc_result = serialize_to_document(&b);
     assert!(doc_result.is_err());
 
     #[derive(Deserialize, Serialize, Debug, PartialEq)]
@@ -730,11 +724,11 @@ fn test_unsigned_helpers() {
         num_1: 101,
         num_2: 12345,
     };
-    let doc = to_document(&f).unwrap();
+    let doc = serialize_to_document(&f).unwrap();
     assert!((doc.get_f64("num_1").unwrap() - 101.0).abs() < f64::EPSILON);
     assert!((doc.get_f64("num_2").unwrap() - 12345.0).abs() < f64::EPSILON);
 
-    let back: F = from_document(doc).unwrap();
+    let back: F = deserialize_from_document(doc).unwrap();
     assert_eq!(back, f);
 
     let f = F {
@@ -742,14 +736,14 @@ fn test_unsigned_helpers() {
         // f64 cannot represent many large integers exactly, u64::MAX included
         num_2: u64::MAX,
     };
-    let doc_result = to_document(&f);
+    let doc_result = serialize_to_document(&f);
     assert!(doc_result.is_err());
 
     let f = F {
         num_1: 1,
         num_2: u64::MAX - 255,
     };
-    let doc_result = to_document(&f);
+    let doc_result = serialize_to_document(&f);
     assert!(doc_result.is_err());
 }
 
@@ -770,9 +764,9 @@ fn test_datetime_helpers() {
     let a = A {
         date: crate::DateTime::from_time_0_3(date),
     };
-    let doc = to_document(&a).unwrap();
+    let doc = serialize_to_document(&a).unwrap();
     assert_eq!(doc.get_str("date").unwrap(), iso);
-    let a: A = from_document(doc).unwrap();
+    let a: A = deserialize_from_document(doc).unwrap();
     assert_eq!(a.date.to_time_0_3(), date);
 
     #[cfg(feature = "time-0_3")]
@@ -797,9 +791,9 @@ fn test_datetime_helpers() {
         let b: B = serde_json::from_value(json).unwrap();
         let expected = datetime!(2020-06-09 10:58:07.095 UTC);
         assert_eq!(b.date, expected);
-        let doc = to_document(&b).unwrap();
+        let doc = serialize_to_document(&b).unwrap();
         assert_eq!(doc.get_datetime("date").unwrap().to_time_0_3(), expected);
-        let b: B = from_document(doc).unwrap();
+        let b: B = deserialize_from_document(doc).unwrap();
         assert_eq!(b.date, expected);
     }
 
@@ -825,9 +819,9 @@ fn test_datetime_helpers() {
         let expected: chrono::DateTime<chrono::Utc> =
             chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap();
         assert_eq!(b.date, expected);
-        let doc = to_document(&b).unwrap();
+        let doc = serialize_to_document(&b).unwrap();
         assert_eq!(doc.get_datetime("date").unwrap().to_chrono(), expected);
-        let b: B = from_document(doc).unwrap();
+        let b: B = deserialize_from_document(doc).unwrap();
         assert_eq!(b.date, expected);
     }
 
@@ -853,12 +847,12 @@ fn test_datetime_helpers() {
         let expected: Option<chrono::DateTime<chrono::Utc>> =
             Some(chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap());
         assert_eq!(b.date, expected);
-        let doc = to_document(&b).unwrap();
+        let doc = serialize_to_document(&b).unwrap();
         assert_eq!(
             Some(doc.get_datetime("date").unwrap().to_chrono()),
             expected
         );
-        let b: B = from_document(doc).unwrap();
+        let b: B = deserialize_from_document(doc).unwrap();
         assert_eq!(b.date, expected);
     }
 
@@ -878,9 +872,9 @@ fn test_datetime_helpers() {
         let b: B = serde_json::from_value(json).unwrap();
         let expected = None;
         assert_eq!(b.date, expected);
-        let doc = to_document(&b).unwrap();
+        let doc = serialize_to_document(&b).unwrap();
         assert_eq!(None, expected);
-        let b: B = from_document(doc).unwrap();
+        let b: B = deserialize_from_document(doc).unwrap();
         assert_eq!(b.date, expected);
     }
 
@@ -894,9 +888,9 @@ fn test_datetime_helpers() {
     let c = C {
         date: date.to_string(),
     };
-    let doc = to_document(&c).unwrap();
+    let doc = serialize_to_document(&c).unwrap();
     assert!(doc.get_datetime("date").is_ok());
-    let c: C = from_document(doc).unwrap();
+    let c: C = deserialize_from_document(doc).unwrap();
     assert_eq!(c.date.as_str(), date);
 }
 
@@ -914,9 +908,9 @@ fn test_oid_helpers() {
     let a = A {
         oid: oid.to_string(),
     };
-    let doc = to_document(&a).unwrap();
+    let doc = serialize_to_document(&a).unwrap();
     assert_eq!(doc.get_object_id("oid").unwrap(), oid);
-    let a: A = from_document(doc).unwrap();
+    let a: A = deserialize_from_document(doc).unwrap();
     assert_eq!(a.oid, oid.to_string());
 }
 
@@ -934,9 +928,9 @@ fn test_i64_as_bson_datetime() {
     let a = A {
         now: now.timestamp_millis(),
     };
-    let doc = to_document(&a).unwrap();
+    let doc = serialize_to_document(&a).unwrap();
     assert_eq!(doc.get_datetime("now").unwrap(), &now);
-    let a: A = from_document(doc).unwrap();
+    let a: A = deserialize_from_document(doc).unwrap();
     assert_eq!(a.now, now.timestamp_millis());
 }
 
@@ -956,7 +950,7 @@ fn test_uuid_1_helpers() {
 
     let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
     let a = A { uuid };
-    let doc = to_document(&a).unwrap();
+    let doc = serialize_to_document(&a).unwrap();
     match doc.get("uuid").unwrap() {
         Bson::Binary(bin) => {
             assert_eq!(bin.subtype, BinarySubtype::Uuid);
@@ -964,7 +958,7 @@ fn test_uuid_1_helpers() {
         }
         _ => panic!("expected Bson::Binary"),
     }
-    let a: A = from_document(doc).unwrap();
+    let a: A = deserialize_from_document(doc).unwrap();
     assert_eq!(a.uuid, uuid);
 }
 
@@ -980,11 +974,11 @@ fn test_timestamp_helpers() {
 
     let time = 12345;
     let a = A { time };
-    let doc = to_document(&a).unwrap();
+    let doc = serialize_to_document(&a).unwrap();
     let timestamp = doc.get_timestamp("time").unwrap();
     assert_eq!(timestamp.time, time);
     assert_eq!(timestamp.increment, 0);
-    let a: A = from_document(doc).unwrap();
+    let a: A = deserialize_from_document(doc).unwrap();
     assert_eq!(a.time, time);
 
     #[derive(Deserialize, Serialize)]
@@ -1044,14 +1038,14 @@ fn oid_as_hex_string() {
 
     let oid = ObjectId::new();
     let foo = Foo { oid };
-    let doc = to_document(&foo).unwrap();
+    let doc = serialize_to_document(&foo).unwrap();
     assert_eq!(doc.get_str("oid").unwrap(), oid.to_hex());
 }
 
 #[test]
 fn fuzz_regression_00() {
     let buf: &[u8] = &[227, 0, 35, 4, 2, 0, 255, 255, 255, 127, 255, 255, 255, 47];
-    let _ = crate::from_slice::<Document>(buf);
+    let _ = crate::deserialize_from_slice::<Document>(buf);
 }
 
 #[cfg(feature = "serde_path_to_error")]
@@ -1079,7 +1073,7 @@ mod serde_path_to_error {
                 "value": "hello",
             },
         };
-        let result: Result<Foo, _> = crate::from_document(src);
+        let result: Result<Foo, _> = crate::deserialize_from_document(src);
         assert!(result.is_err());
         match result.unwrap_err() {
             crate::de::Error::WithPath { source: _, path } => {
@@ -1100,7 +1094,7 @@ mod serde_path_to_error {
             },
         }
         .into_bytes();
-        let result: Result<Foo, _> = crate::from_slice(&src);
+        let result: Result<Foo, _> = crate::deserialize_from_slice(&src);
         assert!(result.is_err());
         match result.unwrap_err() {
             crate::de::Error::WithPath { source: _, path } => {
@@ -1116,7 +1110,7 @@ mod serde_path_to_error {
             one: Bar { value: 42 },
             two: Bar { value: u64::MAX },
         };
-        let result = crate::to_bson(&src);
+        let result = crate::serialize_to_bson(&src);
         assert!(result.is_err());
         match result.unwrap_err() {
             crate::ser::Error::WithPath { source: _, path } => {
@@ -1132,7 +1126,7 @@ mod serde_path_to_error {
             one: Bar { value: 42 },
             two: Bar { value: u64::MAX },
         };
-        let result = crate::to_vec(&src);
+        let result = crate::serialize_to_vec(&src);
         assert!(result.is_err());
         match result.unwrap_err() {
             crate::ser::Error::WithPath { source: _, path } => {
diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs
index 817b8d88..0f74e352 100644
--- a/src/tests/serde_helpers.rs
+++ b/src/tests/serde_helpers.rs
@@ -3,7 +3,7 @@ use core::str;
 use serde::{de::Visitor, Deserialize, Serialize};
 
 use crate::{
-    from_slice,
+    deserialize_from_slice,
     serde_helpers::{HumanReadable, Utf8LossyDeserialization},
 };
 
@@ -88,7 +88,7 @@ fn human_readable_wrapper() {
         }),
     };
     // use the raw serializer, which is non-human-readable
-    let data_doc = crate::to_raw_document_buf(&data).unwrap();
+    let data_doc = crate::serialize_to_raw_document_buf(&data).unwrap();
     let expected_data_doc = rawdoc! {
         "first": "human readable",
         "outer": "not human readable",
@@ -99,7 +99,7 @@ fn human_readable_wrapper() {
     };
     assert_eq!(data_doc, expected_data_doc);
 
-    let tripped: Data = crate::from_slice(expected_data_doc.as_bytes()).unwrap();
+    let tripped: Data = crate::deserialize_from_slice(expected_data_doc.as_bytes()).unwrap();
     let expected = Data {
         first: HumanReadable(Detector {
             serialized_as: true,
@@ -142,11 +142,13 @@ fn utf8_lossy_wrapper() {
         s2: String,
     }
 
-    from_slice::<NoUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
+    deserialize_from_slice::<NoUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
 
-    let s = from_slice::<Utf8LossyDeserialization<NoUtf8Lossy>>(&both_strings_invalid_bytes)
-        .unwrap()
-        .0;
+    let s = deserialize_from_slice::<Utf8LossyDeserialization<NoUtf8Lossy>>(
+        &both_strings_invalid_bytes,
+    )
+    .unwrap()
+    .0;
     assert_eq!(s.s1, expected_replacement);
     assert_eq!(s.s2, expected_replacement);
 
@@ -156,16 +158,17 @@ fn utf8_lossy_wrapper() {
         s2: String,
     }
 
-    let s = from_slice::<FirstStringUtf8Lossy>(&first_string_invalid_bytes).unwrap();
+    let s = deserialize_from_slice::<FirstStringUtf8Lossy>(&first_string_invalid_bytes).unwrap();
     assert_eq!(s.s1.0, expected_replacement);
     assert_eq!(&s.s2, ":)");
 
-    from_slice::<FirstStringUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
+    deserialize_from_slice::<FirstStringUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
 
-    let s =
-        from_slice::<Utf8LossyDeserialization<FirstStringUtf8Lossy>>(&both_strings_invalid_bytes)
-            .unwrap()
-            .0;
+    let s = deserialize_from_slice::<Utf8LossyDeserialization<FirstStringUtf8Lossy>>(
+        &both_strings_invalid_bytes,
+    )
+    .unwrap()
+    .0;
     assert_eq!(s.s1.0, expected_replacement);
     assert_eq!(s.s2, expected_replacement);
 }
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 1ef1893e..0255cf41 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,
 };
@@ -111,70 +110,74 @@ fn run_test(test: TestFile) {
 
         // these four cover the four ways to create a [`Document`] from the provided BSON.
         let documentfromreader_cb =
-            Document::from_reader(canonical_bson.as_slice()).expect(&description);
+            Document::decode_from_reader(canonical_bson.as_slice()).expect(&description);
 
         let fromreader_cb: Document =
-            crate::from_reader(canonical_bson.as_slice()).expect(&description);
+            crate::deserialize_from_reader(canonical_bson.as_slice()).expect(&description);
 
         let fromdocument_documentfromreader_cb: Document =
-            crate::from_document(documentfromreader_cb.clone()).expect(&description);
+            crate::deserialize_from_document(documentfromreader_cb.clone()).expect(&description);
 
         let todocument_documentfromreader_cb: Document =
-            crate::to_document(&documentfromreader_cb).expect(&description);
+            crate::serialize_to_document(&documentfromreader_cb).expect(&description);
 
         let canonical_raw_document =
-            RawDocument::from_bytes(canonical_bson.as_slice()).expect(&description);
+            RawDocument::decode_from_bytes(canonical_bson.as_slice()).expect(&description);
         let document_from_raw_document: Document =
             canonical_raw_document.try_into().expect(&description);
 
         let canonical_raw_bson_from_slice =
-            crate::from_slice::<RawBsonRef>(canonical_bson.as_slice())
+            crate::deserialize_from_slice::<RawBsonRef>(canonical_bson.as_slice())
                 .expect(&description)
                 .as_document()
                 .expect(&description);
 
         let canonical_owned_raw_bson_from_slice =
-            crate::from_slice::<RawBson>(canonical_bson.as_slice()).expect(&description);
+            crate::deserialize_from_slice::<RawBson>(canonical_bson.as_slice())
+                .expect(&description);
 
         let canonical_raw_document_from_slice =
-            crate::from_slice::<&RawDocument>(canonical_bson.as_slice()).expect(&description);
+            crate::deserialize_from_slice::<&RawDocument>(canonical_bson.as_slice())
+                .expect(&description);
 
         // These cover the ways to serialize those [`Documents`] back to BSON.
         let mut documenttowriter_documentfromreader_cb = Vec::new();
         documentfromreader_cb
-            .to_writer(&mut documenttowriter_documentfromreader_cb)
+            .encode_to_writer(&mut documenttowriter_documentfromreader_cb)
             .expect(&description);
 
         let mut documenttowriter_fromreader_cb = Vec::new();
         fromreader_cb
-            .to_writer(&mut documenttowriter_fromreader_cb)
+            .encode_to_writer(&mut documenttowriter_fromreader_cb)
             .expect(&description);
 
         let mut documenttowriter_fromdocument_documentfromreader_cb = Vec::new();
         fromdocument_documentfromreader_cb
-            .to_writer(&mut documenttowriter_fromdocument_documentfromreader_cb)
+            .encode_to_writer(&mut documenttowriter_fromdocument_documentfromreader_cb)
             .expect(&description);
 
         let mut documenttowriter_todocument_documentfromreader_cb = Vec::new();
         todocument_documentfromreader_cb
-            .to_writer(&mut documenttowriter_todocument_documentfromreader_cb)
+            .encode_to_writer(&mut documenttowriter_todocument_documentfromreader_cb)
             .expect(&description);
 
         let tovec_documentfromreader_cb =
-            crate::to_vec(&documentfromreader_cb).expect(&description);
+            crate::serialize_to_vec(&documentfromreader_cb).expect(&description);
 
         let mut documenttowriter_document_from_raw_document = Vec::new();
         document_from_raw_document
-            .to_writer(&mut documenttowriter_document_from_raw_document)
+            .encode_to_writer(&mut documenttowriter_document_from_raw_document)
             .expect(&description);
 
         // Serialize the raw versions "back" to BSON also.
-        let tovec_rawdocument = crate::to_vec(&canonical_raw_document).expect(&description);
+        let tovec_rawdocument =
+            crate::serialize_to_vec(&canonical_raw_document).expect(&description);
         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);
+            crate::serialize_to_vec(&canonical_raw_document_from_slice).expect(&description);
+        let tovec_rawbson =
+            crate::serialize_to_vec(&canonical_raw_bson_from_slice).expect(&description);
         let tovec_ownedrawbson =
-            crate::to_vec(&canonical_owned_raw_bson_from_slice).expect(&description);
+            crate::serialize_to_vec(&canonical_owned_raw_bson_from_slice).expect(&description);
 
         // test Bson / RawBson field deserialization
         if let Some(ref test_key) = test.test_key {
@@ -199,7 +202,9 @@ fn run_test(test: TestFile) {
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
                     .expect(&description);
                 let from_slice_owned_vec =
-                    RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_bytes();
+                    RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)])
+                        .expect(&description)
+                        .into_bytes();
 
                 // deserialize the field from raw Bytes into a Bson
                 let deserializer_value =
@@ -234,11 +239,13 @@ 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_raw_vec = crate::serialize_to_vec(&from_raw_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_value_raw_vec = crate::to_vec(&from_value_raw_doc).expect(&description);
+                    crate::serialize_to_vec(&from_slice_value_doc).expect(&description);
+                let from_bson_value_vec =
+                    crate::serialize_to_vec(&from_value_value_doc).expect(&description);
+                let from_value_raw_vec =
+                    crate::serialize_to_vec(&from_value_raw_doc).expect(&description);
 
                 assert_eq!(from_raw_vec, canonical_bson, "{}", description);
                 assert_eq!(from_slice_value_vec, canonical_bson, "{}", description);
@@ -343,10 +350,11 @@ fn run_test(test: TestFile) {
         if let Some(db) = valid.degenerate_bson {
             let db = hex::decode(&db).expect(&description);
 
-            let bson_to_native_db = Document::from_reader(db.as_slice()).expect(&description);
+            let bson_to_native_db =
+                Document::decode_from_reader(db.as_slice()).expect(&description);
             let mut native_to_bson_bson_to_native_db = Vec::new();
             bson_to_native_db
-                .to_writer(&mut native_to_bson_bson_to_native_db)
+                .encode_to_writer(&mut native_to_bson_bson_to_native_db)
                 .unwrap();
             assert_eq!(
                 hex::encode(native_to_bson_bson_to_native_db).to_lowercase(),
@@ -356,10 +364,10 @@ fn run_test(test: TestFile) {
             );
 
             let bson_to_native_db_serde: Document =
-                crate::from_reader(db.as_slice()).expect(&description);
+                crate::deserialize_from_reader(db.as_slice()).expect(&description);
             let mut native_to_bson_bson_to_native_db_serde = Vec::new();
             bson_to_native_db_serde
-                .to_writer(&mut native_to_bson_bson_to_native_db_serde)
+                .encode_to_writer(&mut native_to_bson_bson_to_native_db_serde)
                 .unwrap();
             assert_eq!(
                 hex::encode(native_to_bson_bson_to_native_db_serde).to_lowercase(),
@@ -368,13 +376,14 @@ fn run_test(test: TestFile) {
                 description,
             );
 
-            let document_from_raw_document: Document = RawDocument::from_bytes(db.as_slice())
-                .expect(&description)
-                .try_into()
-                .expect(&description);
+            let document_from_raw_document: Document =
+                RawDocument::decode_from_bytes(db.as_slice())
+                    .expect(&description)
+                    .try_into()
+                    .expect(&description);
             let mut documenttowriter_document_from_raw_document = Vec::new();
             document_from_raw_document
-                .to_writer(&mut documenttowriter_document_from_raw_document)
+                .encode_to_writer(&mut documenttowriter_document_from_raw_document)
                 .expect(&description);
             assert_eq!(
                 hex::encode(documenttowriter_document_from_raw_document).to_lowercase(),
@@ -468,7 +477,7 @@ fn run_test(test: TestFile) {
             json_to_native_cej
                 .as_document()
                 .unwrap()
-                .to_writer(&mut native_to_bson_json_to_native_cej)
+                .encode_to_writer(&mut native_to_bson_json_to_native_cej)
                 .unwrap();
 
             assert_eq!(
@@ -503,7 +512,7 @@ fn run_test(test: TestFile) {
                 json_to_native_dej
                     .as_document()
                     .unwrap()
-                    .to_writer(&mut native_to_bson_json_to_native_dej)
+                    .encode_to_writer(&mut native_to_bson_json_to_native_dej)
                     .unwrap();
 
                 assert_eq!(
@@ -540,7 +549,7 @@ fn run_test(test: TestFile) {
         );
         let bson = hex::decode(&decode_error.bson).expect("should decode from hex");
 
-        if let Ok(doc) = RawDocument::from_bytes(bson.as_slice()) {
+        if let Ok(doc) = RawDocument::decode_from_bytes(bson.as_slice()) {
             Document::try_from(doc).expect_err(description.as_str());
         }
 
@@ -551,11 +560,12 @@ fn run_test(test: TestFile) {
             continue;
         }
 
-        Document::from_reader(bson.as_slice()).expect_err(&description);
-        crate::from_reader::<_, Document>(bson.as_slice()).expect_err(description.as_str());
+        Document::decode_from_reader(bson.as_slice()).expect_err(&description);
+        crate::deserialize_from_reader::<_, Document>(bson.as_slice())
+            .expect_err(description.as_str());
 
         if decode_error.description.contains("invalid UTF-8") {
-            RawDocumentBuf::from_reader(bson.as_slice())
+            RawDocumentBuf::decode_from_reader(bson.as_slice())
                 .expect(&description)
                 .to_document_utf8_lossy()
                 .unwrap_or_else(|err| {
@@ -564,7 +574,7 @@ fn run_test(test: TestFile) {
                         description, err
                     )
                 });
-            crate::from_slice::<Utf8LossyDeserialization<Document>>(bson.as_slice())
+            crate::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(bson.as_slice())
                 .expect(&description);
         }
     }
@@ -579,7 +589,7 @@ fn run_test(test: TestFile) {
 
         if let Ok(bson) = Bson::try_from(json.clone()) {
             // if converting to bson succeeds, assert that translating that bson to bytes fails
-            assert!(crate::to_vec(&bson).is_err());
+            assert!(crate::serialize_to_vec(&bson).is_err());
         }
     }
 }
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
index 95f389ce..d25090da 100644
--- a/src/tests/spec/vector.rs
+++ b/src/tests/spec/vector.rs
@@ -4,11 +4,11 @@ use serde::{Deserialize, Deserializer, Serialize};
 
 use crate::{
     binary::{Binary, PackedBitVector, Vector},
-    from_document,
-    from_slice,
+    deserialize_from_document,
+    deserialize_from_slice,
+    serialize_to_document,
+    serialize_to_raw_document_buf,
     spec::BinarySubtype,
-    to_document,
-    to_raw_document_buf,
     Bson,
     Document,
     RawDocumentBuf,
@@ -107,7 +107,7 @@ fn vector_from_numbers(
 // Only return the binary if it represents a valid vector; otherwise, return an error.
 fn binary_from_bytes(bson: &str, test_key: &str, description: &str) -> Result<Binary, String> {
     let bytes = hex::decode(bson).expect(description);
-    let mut test_document = Document::from_reader(bytes.as_slice()).expect(description);
+    let mut test_document = Document::decode_from_reader(bytes.as_slice()).expect(description);
     let bson = test_document.remove(test_key).expect(description);
     let binary = match bson {
         Bson::Binary(binary) => binary,
@@ -187,20 +187,21 @@ fn run_test_file(test_file: TestFile) {
         };
 
         // Serialize for Vector (Document)
-        let serialized_document = to_document(&data).expect(&description);
+        let serialized_document = serialize_to_document(&data).expect(&description);
         assert_eq!(serialized_document, test_document);
 
         // Deserialize for Vector (Document)
-        let deserialized_data: Data = from_document(serialized_document).expect(&description);
+        let deserialized_data: Data =
+            deserialize_from_document(serialized_document).expect(&description);
         assert_eq!(deserialized_data, data);
 
         // Serialize for Vector (RawDocumentBuf)
-        let serialized_raw_document = to_raw_document_buf(&data).expect(&description);
+        let serialized_raw_document = serialize_to_raw_document_buf(&data).expect(&description);
         assert_eq!(serialized_raw_document, test_raw_document);
 
         // Deserialize for Vector (RawDocumentBuf)
         let deserialized_data: Data =
-            from_slice(serialized_raw_document.as_bytes()).expect(&description);
+            deserialize_from_slice(serialized_raw_document.as_bytes()).expect(&description);
         assert_eq!(deserialized_data, data);
     }
 }
diff --git a/src/uuid.rs b/src/uuid.rs
index c6bf3aef..61897b2e 100644
--- a/src/uuid.rs
+++ b/src/uuid.rs
@@ -101,7 +101,7 @@
 //!   "as_bson": bson::Uuid::from(foo.as_bson.unwrap()),
 //! };
 //!
-//! assert_eq!(bson::to_document(&foo)?, expected);
+//! assert_eq!(bson::serialize_to_document(&foo)?, expected);
 //! # }
 //! # Ok::<(), Box<dyn std::error::Error>>(())
 //! ```
@@ -135,19 +135,15 @@
 #[cfg(test)]
 mod test;
 
-use std::{
-    fmt::{self, Display},
-    str::FromStr,
-};
+use std::fmt::{self, Display};
 
-use serde::{Deserialize, Serialize};
-
-use crate::{de::BsonVisitor, spec::BinarySubtype, Binary, Bson};
+use crate::{spec::BinarySubtype, Binary, Bson};
 
 /// Special type name used in the [`Uuid`] serialization implementation to indicate a BSON
 /// UUID is being serialized or deserialized. The BSON serializers/deserializers will handle this
 /// name specially, but other serializers/deserializers will just ignore it and use [`uuid::Uuid`]'s
 /// serde integration.
+#[cfg(feature = "serde")]
 pub(crate) const UUID_NEWTYPE_NAME: &str = "$__bson_private_uuid";
 
 /// A struct modeling a BSON UUID value (i.e. a Binary value with subtype 4).
@@ -227,7 +223,8 @@ impl Uuid {
     }
 }
 
-impl Serialize for Uuid {
+#[cfg(feature = "serde")]
+impl serde::Serialize for Uuid {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
@@ -236,12 +233,13 @@ impl Serialize for Uuid {
     }
 }
 
-impl<'de> Deserialize<'de> for Uuid {
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for Uuid {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
-        match deserializer.deserialize_newtype_struct(UUID_NEWTYPE_NAME, BsonVisitor)? {
+        match deserializer.deserialize_newtype_struct(UUID_NEWTYPE_NAME, crate::de::BsonVisitor)? {
             // Need to support deserializing from generic subtypes for non-BSON formats.
             // When using the BSON deserializer, the newtype name will ensure the subtype is only
             // ever BinarySubtype::Uuid.
@@ -258,6 +256,7 @@ impl<'de> Deserialize<'de> for Uuid {
                 ))
             }
             Bson::String(s) => {
+                use std::str::FromStr as _;
                 let uuid = uuid::Uuid::from_str(s.as_str()).map_err(serde::de::Error::custom)?;
                 Ok(Self::from_external_uuid(uuid))
             }
@@ -460,6 +459,7 @@ macro_rules! trait_impls {
             where
                 D: serde::Deserializer<'de>,
             {
+                use serde::Deserialize as _;
                 let uuid = Uuid::deserialize(deserializer)?;
                 Ok(uuid.into())
             }
@@ -472,6 +472,7 @@ macro_rules! trait_impls {
             where
                 S: serde::Serializer,
             {
+                use serde::Serialize as _;
                 let uuid = Uuid::from(*source);
                 uuid.serialize(serializer)
             }
diff --git a/src/uuid/test.rs b/src/uuid/test.rs
index 29c0048c..17efdbf6 100644
--- a/src/uuid/test.rs
+++ b/src/uuid/test.rs
@@ -1,16 +1,12 @@
 use crate::{
-    from_document,
-    from_slice,
     spec::BinarySubtype,
     uuid::{Uuid, UuidRepresentation},
     Binary,
     Bson,
-    Document,
 };
-use serde::{Deserialize, Serialize};
-use serde_json::json;
 
-#[derive(Debug, Serialize, Deserialize, PartialEq)]
+#[cfg(feature = "serde")]
+#[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq)]
 struct U {
     uuid: Uuid,
 }
@@ -28,18 +24,20 @@ fn into_bson() {
     assert_eq!(bson, Bson::Binary(binary));
 }
 
+#[cfg(feature = "serde")]
 #[test]
 fn raw_serialization() {
     let u = U { uuid: Uuid::new() };
-    let bytes = crate::to_vec(&u).unwrap();
+    let bytes = crate::serialize_to_vec(&u).unwrap();
 
-    let doc: Document = crate::from_slice(bytes.as_slice()).unwrap();
+    let doc: crate::Document = crate::deserialize_from_slice(bytes.as_slice()).unwrap();
     assert_eq!(doc, doc! { "uuid": u.uuid });
 
-    let u_roundtrip: U = crate::from_slice(bytes.as_slice()).unwrap();
+    let u_roundtrip: U = crate::deserialize_from_slice(bytes.as_slice()).unwrap();
     assert_eq!(u_roundtrip, u);
 }
 
+#[cfg(feature = "serde")]
 #[test]
 fn bson_serialization() {
     let u = U { uuid: Uuid::new() };
@@ -52,24 +50,26 @@ fn bson_serialization() {
 
     assert_eq!(doc! { "uuid": u.uuid }, correct);
 
-    let doc = crate::to_document(&u).unwrap();
+    let doc = crate::serialize_to_document(&u).unwrap();
     assert_eq!(doc, correct);
 
-    let u_roundtrip: U = crate::from_document(doc).unwrap();
+    let u_roundtrip: U = crate::deserialize_from_document(doc).unwrap();
     assert_eq!(u_roundtrip, u);
 }
 
+#[cfg(feature = "serde")]
 #[test]
 fn json() {
     let u = U { uuid: Uuid::new() };
 
     let json = serde_json::to_value(&u).unwrap();
-    assert_eq!(json, json!({ "uuid": u.uuid.to_string() }));
+    assert_eq!(json, serde_json::json!({ "uuid": u.uuid.to_string() }));
 
     let u_roundtrip_json: U = serde_json::from_value(json).unwrap();
     assert_eq!(u_roundtrip_json, u);
 }
 
+#[cfg(feature = "serde")]
 #[test]
 fn wrong_subtype() {
     let generic = doc! {
@@ -78,9 +78,9 @@ fn wrong_subtype() {
             subtype: BinarySubtype::Generic
         }
     };
-    crate::from_document::<U>(generic.clone()).unwrap_err();
-    let generic_bytes = crate::to_vec(&generic).unwrap();
-    crate::from_slice::<U>(&generic_bytes).unwrap_err();
+    crate::deserialize_from_document::<U>(generic.clone()).unwrap_err();
+    let generic_bytes = crate::serialize_to_vec(&generic).unwrap();
+    crate::deserialize_from_slice::<U>(&generic_bytes).unwrap_err();
 
     let old = doc! {
         "uuid": Binary {
@@ -88,9 +88,9 @@ fn wrong_subtype() {
             subtype: BinarySubtype::UuidOld
         }
     };
-    crate::from_document::<U>(old.clone()).unwrap_err();
-    let old_bytes = crate::to_vec(&old).unwrap();
-    crate::from_slice::<U>(&old_bytes).unwrap_err();
+    crate::deserialize_from_document::<U>(old.clone()).unwrap_err();
+    let old_bytes = crate::serialize_to_vec(&old).unwrap();
+    crate::deserialize_from_slice::<U>(&old_bytes).unwrap_err();
 
     let other = doc! {
         "uuid": Binary {
@@ -98,9 +98,9 @@ fn wrong_subtype() {
             subtype: BinarySubtype::UserDefined(100)
         }
     };
-    crate::from_document::<U>(other.clone()).unwrap_err();
-    let other_bytes = crate::to_vec(&other).unwrap();
-    crate::from_slice::<U>(&other_bytes).unwrap_err();
+    crate::deserialize_from_document::<U>(other.clone()).unwrap_err();
+    let other_bytes = crate::serialize_to_vec(&other).unwrap();
+    crate::deserialize_from_slice::<U>(&other_bytes).unwrap_err();
 }
 
 #[test]
@@ -256,9 +256,10 @@ fn interop_1() {
     assert_eq!(d_bson, d_uuid);
 }
 
+#[cfg(feature = "serde")]
 #[test]
 fn deserialize_uuid_from_string() {
-    #[derive(Deserialize)]
+    #[derive(serde::Deserialize)]
     struct UuidWrapper {
         uuid: Uuid,
     }
@@ -266,11 +267,12 @@ fn deserialize_uuid_from_string() {
     let uuid = Uuid::new();
 
     let doc = doc! { "uuid": uuid.to_string() };
-    let wrapper: UuidWrapper = from_document(doc).expect("failed to deserialize document");
+    let wrapper: UuidWrapper =
+        crate::deserialize_from_document(doc).expect("failed to deserialize document");
     assert_eq!(wrapper.uuid, uuid);
 
     let raw_doc = rawdoc! { "uuid": uuid.to_string() };
-    let wrapper: UuidWrapper =
-        from_slice(raw_doc.as_bytes()).expect("failed to deserialize raw document");
+    let wrapper: UuidWrapper = crate::deserialize_from_slice(raw_doc.as_bytes())
+        .expect("failed to deserialize raw document");
     assert_eq!(wrapper.uuid, uuid);
 }

From 3cbf444830f95937b0120d7bb7f380cc2b716432 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Wed, 18 Jun 2025 15:47:56 -0400
Subject: [PATCH 124/156] RUST-1406 Add type-specific errors to standard error
 type (#555)

---
 src/binary.rs             |  41 +++-------
 src/binary/vector.rs      |  59 +++++++-------
 src/datetime.rs           |  50 ++----------
 src/datetime/builder.rs   |  16 ++--
 src/decimal128.rs         | 110 ++++++++++----------------
 src/error.rs              | 158 +++++++++++++++++++-------------------
 src/error/decimal128.rs   |  59 ++++++++++++++
 src/error/oid.rs          |  52 +++++++++++++
 src/error/uuid.rs         |  74 ++++++++++++++++++
 src/error/value_access.rs |  77 +++++++++++++++++++
 src/extjson/de.rs         |  10 +--
 src/extjson/models.rs     |   3 +-
 src/oid.rs                |  73 ++----------------
 src/raw.rs                |  28 +++----
 src/raw/document.rs       |  10 +--
 src/raw/iter.rs           |  18 ++---
 src/raw/test.rs           |   8 +-
 src/tests/modules/ser.rs  |   4 +-
 src/uuid.rs               |  98 +++++------------------
 19 files changed, 492 insertions(+), 456 deletions(-)
 create mode 100644 src/error/decimal128.rs
 create mode 100644 src/error/oid.rs
 create mode 100644 src/error/uuid.rs
 create mode 100644 src/error/value_access.rs

diff --git a/src/binary.rs b/src/binary.rs
index bd00a8db..58416ee1 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -1,13 +1,18 @@
 #! Module containing functionality related to BSON binary values.
-
 mod vector;
 
-use crate::{base64, spec::BinarySubtype, RawBinaryRef};
 use std::{
-    error,
+    convert::TryFrom,
     fmt::{self, Display},
 };
 
+use crate::{
+    base64,
+    error::{Error, Result},
+    spec::BinarySubtype,
+    RawBinaryRef,
+};
+
 pub use vector::{PackedBitVector, Vector};
 
 /// Represents a BSON binary value.
@@ -37,7 +42,7 @@ impl Binary {
     /// [`BinarySubtype::Generic`].
     ///
     /// ```rust
-    /// # use bson::{Binary, binary::Result};
+    /// # use bson::{Binary, error::Result};
     /// # fn example() -> Result<()> {
     /// let input = base64::encode("hello");
     /// let binary = Binary::from_base64(input, None)?;
@@ -50,9 +55,7 @@ impl Binary {
         input: impl AsRef<str>,
         subtype: impl Into<Option<BinarySubtype>>,
     ) -> Result<Self> {
-        let bytes = base64::decode(input.as_ref()).map_err(|e| Error::DecodingError {
-            message: e.to_string(),
-        })?;
+        let bytes = base64::decode(input.as_ref()).map_err(Error::binary)?;
         let subtype = match subtype.into() {
             Some(s) => s,
             None => BinarySubtype::Generic,
@@ -97,27 +100,3 @@ impl Binary {
         }
     }
 }
-
-/// Possible errors that can arise during [`Binary`] construction.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Error {
-    /// While trying to decode from base64, an error was returned.
-    DecodingError { message: String },
-
-    /// A [`Vector`]-related error occurred.
-    Vector { message: String },
-}
-
-impl error::Error for Error {}
-
-impl std::fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::DecodingError { message } => fmt.write_str(message),
-            Error::Vector { message } => fmt.write_str(message),
-        }
-    }
-}
-
-pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/binary/vector.rs b/src/binary/vector.rs
index d67f3757..a427dfea 100644
--- a/src/binary/vector.rs
+++ b/src/binary/vector.rs
@@ -23,7 +23,7 @@ const PACKED_BIT: u8 = 0x10;
 ///
 /// ```rust
 /// # use serde::{Serialize, Deserialize};
-/// # use bson::{binary::{Result, Vector}, spec::ElementType};
+/// # use bson::{binary::Vector, error::Result, spec::ElementType};
 /// #[derive(Serialize, Deserialize)]
 /// struct Data {
 ///     vector: Vector,
@@ -64,7 +64,7 @@ impl PackedBitVector {
     /// single-bit elements in little-endian format. For example, the following vector:
     ///
     /// ```rust
-    /// # use bson::binary::{Result, PackedBitVector};
+    /// # use bson::{binary::PackedBitVector, error::Result};
     /// # fn main() -> Result<()> {
     /// let packed_bits = vec![238, 224];
     /// let vector = PackedBitVector::new(packed_bits, 0)?;
@@ -91,17 +91,14 @@ impl PackedBitVector {
     pub fn new(vector: Vec<u8>, padding: impl Into<Option<u8>>) -> Result<Self> {
         let padding = padding.into().unwrap_or(0);
         if !(0..8).contains(&padding) {
-            return Err(Error::Vector {
-                message: format!("padding must be within 0-7 inclusive, got {}", padding),
-            });
+            return Err(Error::binary(format!(
+                "vector padding must be within 0-7 inclusive, got {padding}"
+            )));
         }
         if padding != 0 && vector.is_empty() {
-            return Err(Error::Vector {
-                message: format!(
-                    "cannot specify non-zero padding if the provided vector is empty, got {}",
-                    padding
-                ),
-            });
+            return Err(Error::binary(format!(
+                "cannot specify non-zero padding if the provided vector is empty, got {padding}",
+            )));
         }
         Ok(Self { vector, padding })
     }
@@ -115,24 +112,19 @@ impl Vector {
         let bytes = bytes.as_ref();
 
         if bytes.len() < 2 {
-            return Err(Error::Vector {
-                message: format!(
-                    "the provided bytes must have a length of at least 2, got {}",
-                    bytes.len()
-                ),
-            });
+            return Err(Error::binary(format!(
+                "the provided vector bytes must have a length of at least 2, got {}",
+                bytes.len()
+            )));
         }
 
         let d_type = bytes[0];
         let padding = bytes[1];
         if d_type != PACKED_BIT && padding != 0 {
-            return Err(Error::Vector {
-                message: format!(
-                    "padding can only be specified for a packed bit vector (data type {}), got \
-                     type {}",
-                    PACKED_BIT, d_type
-                ),
-            });
+            return Err(Error::binary(format!(
+                "padding can only be specified for a packed bit vector (data type {}), got type {}",
+                PACKED_BIT, d_type
+            )));
         }
         let number_bytes = &bytes[2..];
 
@@ -149,11 +141,11 @@ impl Vector {
 
                 let mut vector = Vec::new();
                 for chunk in number_bytes.chunks(F32_BYTES) {
-                    let bytes: [u8; F32_BYTES] = chunk.try_into().map_err(|_| Error::Vector {
-                        message: format!(
+                    let bytes: [u8; F32_BYTES] = chunk.try_into().map_err(|_| {
+                        Error::binary(format!(
                             "f32 vector values must be {} bytes, got {:?}",
                             F32_BYTES, chunk,
-                        ),
+                        ))
                     })?;
                     vector.push(f32::from_le_bytes(bytes));
                 }
@@ -163,9 +155,9 @@ impl Vector {
                 let packed_bit_vector = PackedBitVector::new(number_bytes.to_vec(), padding)?;
                 Ok(Self::PackedBit(packed_bit_vector))
             }
-            other => Err(Error::Vector {
-                message: format!("unsupported vector data type: {}", other),
-            }),
+            other => Err(Error::binary(format!(
+                "unsupported vector data type: {other}"
+            ))),
         }
     }
 
@@ -228,9 +220,10 @@ impl TryFrom<&Binary> for Vector {
 
     fn try_from(binary: &Binary) -> Result<Self> {
         if binary.subtype != BinarySubtype::Vector {
-            return Err(Error::Vector {
-                message: format!("expected vector binary subtype, got {:?}", binary.subtype),
-            });
+            return Err(Error::binary(format!(
+                "expected vector binary subtype, got {:?}",
+                binary.subtype
+            )));
         }
         Self::from_bytes(&binary.bytes)
     }
diff --git a/src/datetime.rs b/src/datetime.rs
index 41dca1df..e87e342b 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -1,18 +1,13 @@
 //! Module containing functionality related to BSON DateTimes.
 //! For more information, see the documentation for the [`DateTime`] type.
+pub(crate) mod builder;
 
 use std::{
     convert::TryInto,
-    error,
     fmt::{self, Display},
-    result,
     time::{Duration, SystemTime},
 };
 
-pub(crate) mod builder;
-pub use crate::datetime::builder::DateTimeBuilder;
-use time::format_description::well_known::Rfc3339;
-
 #[cfg(feature = "chrono-0_4")]
 use chrono::{LocalResult, TimeZone, Utc};
 #[cfg(all(
@@ -20,6 +15,10 @@ use chrono::{LocalResult, TimeZone, Utc};
     any(feature = "chrono-0_4", feature = "time-0_3")
 ))]
 use serde::{Deserialize, Deserializer, Serialize};
+use time::format_description::well_known::Rfc3339;
+
+pub use crate::datetime::builder::DateTimeBuilder;
+use crate::error::{Error, Result};
 
 /// Struct representing a BSON datetime.
 /// Note: BSON datetimes have millisecond precision.
@@ -388,21 +387,13 @@ impl crate::DateTime {
 
     /// Convert this [`DateTime`] to an RFC 3339 formatted string.
     pub fn try_to_rfc3339_string(self) -> Result<String> {
-        self.to_time_0_3()
-            .format(&Rfc3339)
-            .map_err(|e| Error::CannotFormat {
-                message: e.to_string(),
-            })
+        self.to_time_0_3().format(&Rfc3339).map_err(Error::datetime)
     }
 
     /// Convert the given RFC 3339 formatted string to a [`DateTime`], truncating it to millisecond
     /// precision.
     pub fn parse_rfc3339_str(s: impl AsRef<str>) -> Result<Self> {
-        let odt = time::OffsetDateTime::parse(s.as_ref(), &Rfc3339).map_err(|e| {
-            Error::InvalidTimestamp {
-                message: e.to_string(),
-            }
-        })?;
+        let odt = time::OffsetDateTime::parse(s.as_ref(), &Rfc3339).map_err(Error::datetime)?;
         Ok(Self::from_time_0_3(odt))
     }
 
@@ -543,30 +534,3 @@ impl serde_with::SerializeAs<time::OffsetDateTime> for crate::DateTime {
         dt.serialize(serializer)
     }
 }
-
-/// Errors that can occur during [`DateTime`] construction and generation.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Error {
-    /// Error returned when an invalid datetime format is provided to a conversion method.
-    #[non_exhaustive]
-    InvalidTimestamp { message: String },
-    /// Error returned when a [`DateTime`] cannot be represented in a particular format.
-    #[non_exhaustive]
-    CannotFormat { message: String },
-}
-
-/// Alias for `Result<T, DateTime::Error>`
-pub type Result<T> = result::Result<T, Error>;
-
-impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::InvalidTimestamp { message } | Error::CannotFormat { message } => {
-                write!(fmt, "{}", message)
-            }
-        }
-    }
-}
-
-impl error::Error for Error {}
diff --git a/src/datetime/builder.rs b/src/datetime/builder.rs
index c16e22e2..d8cd8ff8 100644
--- a/src/datetime/builder.rs
+++ b/src/datetime/builder.rs
@@ -1,7 +1,12 @@
-use super::*;
 use std::convert::TryFrom;
+
 use time::Date;
 
+use crate::{
+    datetime::DateTime,
+    error::{Error, Result},
+};
+
 /// Builder for constructing a BSON [`DateTime`]
 pub struct DateTimeBuilder<Y = NoYear, M = NoMonth, D = NoDay> {
     pub(crate) year: Y,
@@ -169,19 +174,16 @@ impl DateTimeBuilder<Year, Month, Day> {
     ///
     /// Note: You cannot call `build()` before setting at least the year, month and day.
     pub fn build(self) -> Result<DateTime> {
-        let err = |e: time::error::ComponentRange| Error::InvalidTimestamp {
-            message: e.to_string(),
-        };
-        let month = time::Month::try_from(self.month.0).map_err(err)?;
+        let month = time::Month::try_from(self.month.0).map_err(Error::datetime)?;
         let dt = Date::from_calendar_date(self.year.0, month, self.day.0)
-            .map_err(err)?
+            .map_err(Error::datetime)?
             .with_hms_milli(
                 self.hour.unwrap_or(0),
                 self.minute.unwrap_or(0),
                 self.second.unwrap_or(0),
                 self.millisecond.unwrap_or(0),
             )
-            .map_err(err)?;
+            .map_err(Error::datetime)?;
         Ok(DateTime::from_time_private(dt.assume_utc()))
     }
 }
diff --git a/src/decimal128.rs b/src/decimal128.rs
index 036b1f77..b827e986 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -1,9 +1,11 @@
 //! [BSON Decimal128](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) data type representation
 
-use std::{convert::TryInto, fmt};
+use std::{convert::TryInto, fmt, num::ParseIntError};
 
 use bitvec::prelude::*;
 
+use crate::error::{Decimal128ErrorKind, Error, Result};
+
 /// Struct representing a BSON Decimal128 type.
 ///
 /// This type supports conversion to and from human-readable strings via the [std::fmt::Display] and
@@ -60,9 +62,9 @@ impl fmt::Display for Decimal128 {
 }
 
 impl std::str::FromStr for Decimal128 {
-    type Err = ParseError;
+    type Err = Error;
 
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
+    fn from_str(s: &str) -> Result<Self> {
         Ok(s.parse::<ParsedDecimal128>()?.pack())
     }
 }
@@ -138,10 +140,7 @@ impl Coefficient {
     /// The maximum allowable value of a coefficient.
     const MAX_VALUE: u128 = 9_999_999_999_999_999_999_999_999_999_999_999;
 
-    fn from_bits(
-        src_prefix: &BitSlice<u8, Msb0>,
-        src_suffix: &BitSlice<u8, Msb0>,
-    ) -> Result<Self, ParseError> {
+    fn from_bits(src_prefix: &BitSlice<u8, Msb0>, src_suffix: &BitSlice<u8, Msb0>) -> Result<Self> {
         let mut bytes = [0u8; 16];
         let bits = &mut bytes.view_bits_mut::<Msb0>()[Self::UNUSED_BITS..];
         let prefix_len = src_prefix.len();
@@ -149,7 +148,7 @@ impl Coefficient {
         bits[prefix_len..].copy_from_bitslice(src_suffix);
         let out = Self(bytes);
         if out.value() > Self::MAX_VALUE {
-            Err(ParseError::Overflow)
+            Err(Error::decimal128(Decimal128ErrorKind::Overflow {}))
         } else {
             Ok(out)
         }
@@ -325,46 +324,10 @@ impl fmt::Display for ParsedDecimal128 {
     }
 }
 
-#[derive(Debug)]
-#[non_exhaustive]
-pub enum ParseError {
-    EmptyExponent,
-    InvalidExponent(std::num::ParseIntError),
-    InvalidCoefficient(std::num::ParseIntError),
-    Overflow,
-    Underflow,
-    InexactRounding,
-    Unparseable,
-}
-
-impl fmt::Display for ParseError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            ParseError::EmptyExponent => write!(f, "empty exponent"),
-            ParseError::InvalidExponent(e) => write!(f, "invalid exponent: {}", e),
-            ParseError::InvalidCoefficient(e) => write!(f, "invalid coefficient: {}", e),
-            ParseError::Overflow => write!(f, "overflow"),
-            ParseError::Underflow => write!(f, "underflow"),
-            ParseError::InexactRounding => write!(f, "inexact rounding"),
-            ParseError::Unparseable => write!(f, "unparseable"),
-        }
-    }
-}
-
-impl std::error::Error for ParseError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match self {
-            ParseError::InvalidExponent(e) => Some(e),
-            ParseError::InvalidCoefficient(e) => Some(e),
-            _ => None,
-        }
-    }
-}
-
 impl std::str::FromStr for ParsedDecimal128 {
-    type Err = ParseError;
+    type Err = Error;
 
-    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
+    fn from_str(mut s: &str) -> Result<Self> {
         let sign;
         if let Some(rest) = s.strip_prefix(&['-', '+'][..]) {
             sign = s.starts_with('-');
@@ -385,21 +348,28 @@ impl std::str::FromStr for ParsedDecimal128 {
                         decimal_str = finite_str;
                         exp_str = "0";
                     }
-                    Some((_, "")) => return Err(ParseError::EmptyExponent),
+                    Some((_, "")) => {
+                        return Err(Error::decimal128(Decimal128ErrorKind::EmptyExponent {}))
+                    }
                     Some((pre, post)) => {
                         decimal_str = pre;
                         exp_str = post;
                     }
                 }
-                let mut exp = exp_str
-                    .parse::<i16>()
-                    .map_err(ParseError::InvalidExponent)?;
+                let mut exp = exp_str.parse::<i16>().map_err(|e| {
+                    Error::decimal128(Decimal128ErrorKind::InvalidExponent {}).with_message(e)
+                })?;
 
                 // Remove decimal point and adjust exponent
                 let joined_str;
                 if let Some((pre, post)) = decimal_str.split_once('.') {
-                    let exp_adj = post.len().try_into().map_err(|_| ParseError::Underflow)?;
-                    exp = exp.checked_sub(exp_adj).ok_or(ParseError::Underflow)?;
+                    let exp_adj = post
+                        .len()
+                        .try_into()
+                        .map_err(|_| Error::decimal128(Decimal128ErrorKind::Underflow {}))?;
+                    exp = exp
+                        .checked_sub(exp_adj)
+                        .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Underflow {}))?;
                     joined_str = format!("{}{}", pre, post);
                     decimal_str = &joined_str;
                 }
@@ -415,8 +385,10 @@ impl std::str::FromStr for ParsedDecimal128 {
                         decimal_str = round_decimal_str(decimal_str, Coefficient::MAX_DIGITS)?;
                         let exp_adj = (len - decimal_str.len())
                             .try_into()
-                            .map_err(|_| ParseError::Overflow)?;
-                        exp = exp.checked_add(exp_adj).ok_or(ParseError::Overflow)?;
+                            .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
+                        exp = exp
+                            .checked_add(exp_adj)
+                            .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                     }
                 }
 
@@ -425,11 +397,11 @@ impl std::str::FromStr for ParsedDecimal128 {
                     if decimal_str != "0" {
                         let delta = (Exponent::TINY - exp)
                             .try_into()
-                            .map_err(|_| ParseError::Overflow)?;
+                            .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                         let new_precision = decimal_str
                             .len()
                             .checked_sub(delta)
-                            .ok_or(ParseError::Underflow)?;
+                            .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                         decimal_str = round_decimal_str(decimal_str, new_precision)?;
                     }
                     exp = Exponent::TINY;
@@ -439,14 +411,14 @@ impl std::str::FromStr for ParsedDecimal128 {
                     if decimal_str != "0" {
                         let delta = (exp - Exponent::MAX)
                             .try_into()
-                            .map_err(|_| ParseError::Overflow)?;
+                            .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                         if decimal_str
                             .len()
                             .checked_add(delta)
-                            .ok_or(ParseError::Overflow)?
+                            .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?
                             > Coefficient::MAX_DIGITS
                         {
-                            return Err(ParseError::Overflow);
+                            return Err(Error::decimal128(Decimal128ErrorKind::Overflow {}));
                         }
                         padded_str = format!("{}{}", decimal_str, "0".repeat(delta));
                         decimal_str = &padded_str;
@@ -456,9 +428,9 @@ impl std::str::FromStr for ParsedDecimal128 {
 
                 // Assemble the final value
                 let exponent = Exponent::from_native(exp);
-                let coeff: u128 = decimal_str
-                    .parse()
-                    .map_err(ParseError::InvalidCoefficient)?;
+                let coeff: u128 = decimal_str.parse().map_err(|e: ParseIntError| {
+                    Error::decimal128(Decimal128ErrorKind::InvalidCoefficient {}).with_message(e)
+                })?;
                 let coefficient = Coefficient::from_native(coeff);
                 Decimal128Kind::Finite {
                     exponent,
@@ -471,17 +443,13 @@ impl std::str::FromStr for ParsedDecimal128 {
     }
 }
 
-fn round_decimal_str(s: &str, precision: usize) -> Result<&str, ParseError> {
-    // TODO: In 1.80+ there's split_at_checked to make sure the split doesn't
-    // panic if the index doesn't falls at a codepoint boundary, until then
-    // we can check it with s.is_char_boundary(precision)
-    if !s.is_char_boundary(precision) {
-        return Err(ParseError::Unparseable);
-    }
-    let (pre, post) = s.split_at(precision);
+fn round_decimal_str(s: &str, precision: usize) -> Result<&str> {
+    let (pre, post) = s
+        .split_at_checked(precision)
+        .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Unparseable {}))?;
     // Any nonzero trimmed digits mean it would be an imprecise round.
     if post.chars().any(|c| c != '0') {
-        return Err(ParseError::InexactRounding);
+        return Err(Error::decimal128(Decimal128ErrorKind::InexactRounding {}));
     }
     Ok(pre)
 }
diff --git a/src/error.rs b/src/error.rs
index 20380dcf..d3ed5740 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,16 +1,27 @@
+mod decimal128;
+mod oid;
+mod uuid;
+mod value_access;
+
 use thiserror::Error;
 
-use crate::spec::ElementType;
+pub use decimal128::Decimal128ErrorKind;
+pub use oid::ObjectIdErrorKind;
+pub use uuid::UuidErrorKind;
+pub use value_access::ValueAccessErrorKind;
 
 pub type Result<T> = std::result::Result<T, Error>;
 
 /// An error that can occur in the `bson` crate.
-#[derive(Debug, Error)]
+#[derive(Clone, Debug, Error)]
 #[non_exhaustive]
 pub struct Error {
     /// The kind of error that occurred.
     pub kind: ErrorKind,
 
+    /// An optional message describing the error.
+    pub message: Option<String>,
+
     /// The document key associated with the error, if any.
     pub key: Option<String>,
 
@@ -20,28 +31,69 @@ pub struct Error {
 
 impl std::fmt::Display for Error {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "BSON error")?;
+
         if let Some(key) = self.key.as_deref() {
-            write!(f, "Error at key \"{key}\": ")?;
+            write!(f, " at key \"{key}\"")?;
         } else if let Some(index) = self.index {
-            write!(f, "Error at array index {index}: ")?;
+            write!(f, " at array index {index}")?;
         }
 
-        write!(f, "{}", self.kind)
+        write!(f, ". Kind: {}", self.kind)?;
+        if let Some(ref message) = self.message {
+            write!(f, ". Message: {}", message)?;
+        }
+        write!(f, ".")
     }
 }
 
 /// The types of errors that can occur in the `bson` crate.
-#[derive(Debug, Error)]
+#[derive(Clone, Debug, Error)]
 #[non_exhaustive]
 pub enum ErrorKind {
+    /// An error related to the [`Binary`](crate::Binary) type occurred.
+    #[error("A Binary-related error occurred")]
+    #[non_exhaustive]
+    Binary {},
+
+    /// An error related to the [`DateTime`](crate::DateTime) type occurred.
+    #[error("A DateTime-related error occurred")]
+    #[non_exhaustive]
+    DateTime {},
+
+    /// An error related to the [`Decimal128`](crate::Decimal128) type occurred.
+    #[error("A Decimal128-related error occurred: {kind}")]
+    #[non_exhaustive]
+    Decimal128 {
+        /// The kind of error that occurred.
+        kind: Decimal128ErrorKind,
+    },
+
     /// Malformed BSON bytes were encountered.
-    #[error("Malformed BSON: {message}")]
+    #[error("Malformed BSON bytes")]
     #[non_exhaustive]
-    MalformedValue { message: String },
+    MalformedBytes {},
+
+    /// An error related to the [`ObjectId`](crate::oid::ObjectId) type occurred.
+    #[error("An ObjectId-related error occurred: {kind}")]
+    #[non_exhaustive]
+    ObjectId {
+        /// The kind of error that occurred.
+        kind: ObjectIdErrorKind,
+    },
 
     /// Invalid UTF-8 bytes were encountered.
     #[error("Invalid UTF-8")]
-    Utf8Encoding,
+    #[non_exhaustive]
+    Utf8Encoding {},
+
+    /// An error related to the [`Uuid`](crate::uuid::Uuid) type occurred.
+    #[error("A UUID-related error occurred: {kind}")]
+    #[non_exhaustive]
+    Uuid {
+        /// The kind of error that occurred.
+        kind: UuidErrorKind,
+    },
 
     /// An error occurred when attempting to access a value in a document.
     #[error("An error occurred when attempting to access a document value: {kind}")]
@@ -52,8 +104,9 @@ pub enum ErrorKind {
     },
 
     /// A [`std::io::Error`] occurred.
-    #[error("An IO error occurred: {0}")]
-    Io(std::io::Error),
+    #[error("An IO error occurred")]
+    #[non_exhaustive]
+    Io {},
 
     /// A wrapped deserialization error.
     /// TODO RUST-1406: collapse this
@@ -68,13 +121,14 @@ impl From<ErrorKind> for Error {
             kind,
             key: None,
             index: None,
+            message: None,
         }
     }
 }
 
 impl From<std::io::Error> for Error {
     fn from(value: std::io::Error) -> Self {
-        ErrorKind::Io(value).into()
+        Error::from(ErrorKind::Io {}).with_message(value)
     }
 }
 
@@ -85,31 +139,6 @@ impl From<crate::de::Error> for Error {
     }
 }
 
-/// The types of errors that can occur when attempting to access a value in a document.
-#[derive(Debug, Error)]
-#[non_exhaustive]
-pub enum ValueAccessErrorKind {
-    /// No value for the specified key was present in the document.
-    #[error("The key was not present in the document")]
-    NotPresent,
-
-    /// The type of the value in the document did not match the requested type.
-    #[error("Expected type {expected:?}, got type {actual:?}")]
-    #[non_exhaustive]
-    UnexpectedType {
-        /// The actual type of the value.
-        actual: ElementType,
-
-        /// The expected type of the value.
-        expected: ElementType,
-    },
-
-    /// An error occurred when attempting to parse the document's BSON bytes.
-    #[error("{message}")]
-    #[non_exhaustive]
-    InvalidBson { message: String },
-}
-
 impl Error {
     pub(crate) fn with_key(mut self, key: impl Into<String>) -> Self {
         self.key = Some(key.into());
@@ -121,58 +150,25 @@ impl Error {
         self
     }
 
-    pub(crate) fn value_access_not_present() -> Self {
-        ErrorKind::ValueAccess {
-            kind: ValueAccessErrorKind::NotPresent,
-        }
-        .into()
-    }
-
-    pub(crate) fn value_access_unexpected_type(actual: ElementType, expected: ElementType) -> Self {
-        ErrorKind::ValueAccess {
-            kind: ValueAccessErrorKind::UnexpectedType { actual, expected },
-        }
-        .into()
-    }
-
-    pub(crate) fn value_access_invalid_bson(message: String) -> Self {
-        ErrorKind::ValueAccess {
-            kind: ValueAccessErrorKind::InvalidBson { message },
-        }
-        .into()
+    pub(crate) fn with_message(mut self, message: impl ToString) -> Self {
+        self.message = Some(message.to_string());
+        self
     }
 
-    pub(crate) fn malformed_value(message: impl ToString) -> Self {
-        ErrorKind::MalformedValue {
-            message: message.to_string(),
-        }
-        .into()
+    pub(crate) fn binary(message: impl ToString) -> Self {
+        Self::from(ErrorKind::Binary {}).with_message(message)
     }
 
-    #[cfg(test)]
-    pub(crate) fn is_value_access_not_present(&self) -> bool {
-        matches!(
-            self.kind,
-            ErrorKind::ValueAccess {
-                kind: ValueAccessErrorKind::NotPresent,
-                ..
-            }
-        )
+    pub(crate) fn datetime(message: impl ToString) -> Self {
+        Self::from(ErrorKind::DateTime {}).with_message(message)
     }
 
-    #[cfg(test)]
-    pub(crate) fn is_value_access_unexpected_type(&self) -> bool {
-        matches!(
-            self.kind,
-            ErrorKind::ValueAccess {
-                kind: ValueAccessErrorKind::UnexpectedType { .. },
-                ..
-            }
-        )
+    pub(crate) fn malformed_bytes(message: impl ToString) -> Self {
+        Self::from(ErrorKind::MalformedBytes {}).with_message(message)
     }
 
     #[cfg(all(test, feature = "serde"))]
-    pub(crate) fn is_malformed_value(&self) -> bool {
-        matches!(self.kind, ErrorKind::MalformedValue { .. },)
+    pub(crate) fn is_malformed_bytes(&self) -> bool {
+        matches!(self.kind, ErrorKind::MalformedBytes { .. },)
     }
 }
diff --git a/src/error/decimal128.rs b/src/error/decimal128.rs
new file mode 100644
index 00000000..ab40eed1
--- /dev/null
+++ b/src/error/decimal128.rs
@@ -0,0 +1,59 @@
+use thiserror::Error as ThisError;
+
+use crate::error::{Error, ErrorKind};
+
+/// The kinds of errors that can occur when working with the [`Decimal128`](crate::Decimal128) type.
+#[derive(Clone, Debug, ThisError)]
+#[non_exhaustive]
+pub enum Decimal128ErrorKind {
+    /// Empty exponent.
+    #[error("empty exponent")]
+    #[non_exhaustive]
+    EmptyExponent {},
+
+    /// Invalid exponent.
+    #[error("invalid exponent")]
+    #[non_exhaustive]
+    InvalidExponent {},
+
+    /// Invalid coefficient.
+    #[error("invalid coefficient")]
+    #[non_exhaustive]
+    InvalidCoefficient {},
+
+    /// Overflow.
+    #[error("overflow")]
+    #[non_exhaustive]
+    Overflow {},
+
+    /// Underflow.
+    #[error("underflow")]
+    #[non_exhaustive]
+    Underflow {},
+
+    /// Inexact rounding.
+    #[error("inexact rounding")]
+    #[non_exhaustive]
+    InexactRounding {},
+
+    /// Unparseable.
+    #[error("unparseable")]
+    #[non_exhaustive]
+    Unparseable {},
+}
+
+impl Error {
+    pub(crate) fn decimal128(kind: Decimal128ErrorKind) -> Self {
+        ErrorKind::Decimal128 { kind }.into()
+    }
+
+    #[cfg(test)]
+    pub(crate) fn is_decimal128_unparseable(&self) -> bool {
+        matches!(
+            self.kind,
+            ErrorKind::Decimal128 {
+                kind: Decimal128ErrorKind::Unparseable {},
+            }
+        )
+    }
+}
diff --git a/src/error/oid.rs b/src/error/oid.rs
new file mode 100644
index 00000000..6c770d88
--- /dev/null
+++ b/src/error/oid.rs
@@ -0,0 +1,52 @@
+use hex::FromHexError;
+use thiserror::Error as ThisError;
+
+use crate::error::{Error, ErrorKind};
+
+/// The kinds of errors that can occur when working with the [`ObjectId`](crate::oid::ObjectId)
+/// type.
+#[derive(Clone, Debug, ThisError)]
+#[non_exhaustive]
+pub enum ObjectIdErrorKind {
+    /// An invalid character was found in the provided hex string. Valid characters are: `0...9`,
+    /// `a...f`, or `A...F`.
+    #[error("invalid character '{c}' encountered at index {index}")]
+    #[non_exhaustive]
+    InvalidHexStringCharacter {
+        /// The invalid character.
+        c: char,
+
+        /// The index at which the invalid character was encountered.
+        index: usize,
+    },
+
+    /// An `ObjectId` with an invalid length was encountered.
+    #[error("invalid hex string length {length}")]
+    #[non_exhaustive]
+    InvalidHexStringLength {
+        /// The length of the invalid hex string.
+        length: usize,
+    },
+}
+
+impl Error {
+    // This method is not a From implementation so that it is not part of the public API.
+    pub(crate) fn from_hex_error(error: FromHexError, length: usize) -> Self {
+        let kind = match error {
+            FromHexError::InvalidHexCharacter { c, index } => {
+                ObjectIdErrorKind::InvalidHexStringCharacter { c, index }
+            }
+            FromHexError::InvalidStringLength | FromHexError::OddLength => {
+                ObjectIdErrorKind::InvalidHexStringLength { length }
+            }
+        };
+        ErrorKind::ObjectId { kind }.into()
+    }
+
+    pub(crate) fn oid_invalid_length(length: usize) -> Self {
+        ErrorKind::ObjectId {
+            kind: ObjectIdErrorKind::InvalidHexStringLength { length },
+        }
+        .into()
+    }
+}
diff --git a/src/error/uuid.rs b/src/error/uuid.rs
new file mode 100644
index 00000000..323dbd18
--- /dev/null
+++ b/src/error/uuid.rs
@@ -0,0 +1,74 @@
+use thiserror::Error as ThisError;
+
+use crate::{
+    error::{Error, ErrorKind},
+    spec::BinarySubtype,
+    UuidRepresentation,
+};
+
+/// The kinds of errors that can occur when working with the [`Uuid`](crate::uuid::Uuid) type.
+#[derive(Clone, Debug, ThisError)]
+#[non_exhaustive]
+pub enum UuidErrorKind {
+    /// An invalid string was used to construct a UUID.
+    #[error("invalid UUID string")]
+    #[non_exhaustive]
+    InvalidString {},
+
+    /// The requested `UuidRepresentation` does not match the binary subtype of a `Binary`
+    /// value.
+    #[error(
+        "expected binary subtype {expected_binary_subtype:?} for representation \
+         {requested_representation:?}, got {actual_binary_subtype:?}"
+    )]
+    #[non_exhaustive]
+    RepresentationMismatch {
+        /// The subtype that was expected given the requested representation.
+        expected_binary_subtype: BinarySubtype,
+
+        /// The actual subtype of the binary value.
+        actual_binary_subtype: BinarySubtype,
+
+        /// The requested representation.
+        requested_representation: UuidRepresentation,
+    },
+
+    /// An invalid length of bytes was used to construct a UUID value.
+    #[error("expected length of 16 bytes, got {length}")]
+    #[non_exhaustive]
+    InvalidLength {
+        /// The actual length of the data.
+        length: usize,
+    },
+}
+
+impl Error {
+    pub(crate) fn invalid_uuid_string(message: impl ToString) -> Self {
+        Self::from(ErrorKind::Uuid {
+            kind: UuidErrorKind::InvalidString {},
+        })
+        .with_message(message)
+    }
+
+    pub(crate) fn uuid_representation_mismatch(
+        requested_representation: UuidRepresentation,
+        actual_binary_subtype: BinarySubtype,
+        expected_binary_subtype: BinarySubtype,
+    ) -> Self {
+        ErrorKind::Uuid {
+            kind: UuidErrorKind::RepresentationMismatch {
+                expected_binary_subtype,
+                actual_binary_subtype,
+                requested_representation,
+            },
+        }
+        .into()
+    }
+
+    pub(crate) fn invalid_uuid_length(length: usize) -> Self {
+        ErrorKind::Uuid {
+            kind: UuidErrorKind::InvalidLength { length },
+        }
+        .into()
+    }
+}
diff --git a/src/error/value_access.rs b/src/error/value_access.rs
new file mode 100644
index 00000000..ffc82f4d
--- /dev/null
+++ b/src/error/value_access.rs
@@ -0,0 +1,77 @@
+use thiserror::Error as ThisError;
+
+use crate::{
+    error::{Error, ErrorKind},
+    spec::ElementType,
+};
+
+/// The types of errors that can occur when attempting to access a value in a document.
+#[derive(Clone, Debug, ThisError)]
+#[non_exhaustive]
+pub enum ValueAccessErrorKind {
+    /// No value for the specified key was present in the document.
+    #[error("the key was not present in the document")]
+    #[non_exhaustive]
+    NotPresent {},
+
+    /// The type of the value in the document did not match the requested type.
+    #[error("expected type {expected:?}, got type {actual:?}")]
+    #[non_exhaustive]
+    UnexpectedType {
+        /// The actual type of the value.
+        actual: ElementType,
+
+        /// The expected type of the value.
+        expected: ElementType,
+    },
+
+    /// An error occurred when attempting to parse the document's BSON bytes.
+    #[error("invalid BSON bytes")]
+    #[non_exhaustive]
+    InvalidBson {},
+}
+
+impl Error {
+    pub(crate) fn value_access_not_present() -> Self {
+        ErrorKind::ValueAccess {
+            kind: ValueAccessErrorKind::NotPresent {},
+        }
+        .into()
+    }
+
+    pub(crate) fn value_access_unexpected_type(actual: ElementType, expected: ElementType) -> Self {
+        ErrorKind::ValueAccess {
+            kind: ValueAccessErrorKind::UnexpectedType { actual, expected },
+        }
+        .into()
+    }
+
+    pub(crate) fn value_access_invalid_bson(message: String) -> Self {
+        Self::from(ErrorKind::ValueAccess {
+            kind: ValueAccessErrorKind::InvalidBson {},
+        })
+        .with_message(message)
+    }
+
+    #[cfg(test)]
+    pub(crate) fn is_value_access_not_present(&self) -> bool {
+        matches!(
+            self.kind,
+            ErrorKind::ValueAccess {
+                kind: ValueAccessErrorKind::NotPresent {},
+                ..
+            }
+        )
+    }
+
+    #[cfg(test)]
+    pub(crate) fn is_value_access_unexpected_type(&self) -> bool {
+        matches!(
+            self.kind,
+            ErrorKind::ValueAccess {
+                kind: ValueAccessErrorKind::UnexpectedType { .. },
+                ..
+            }
+        )
+    }
+}
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
index 82b8fcde..f147ad43 100644
--- a/src/extjson/de.rs
+++ b/src/extjson/de.rs
@@ -25,14 +25,14 @@ use std::convert::{TryFrom, TryInto};
 
 use serde::de::{Error as _, Unexpected};
 
-use crate::{extjson::models, oid, Bson, Document};
+use crate::{extjson::models, Bson, Document};
 
 #[derive(Clone, Debug)]
 #[non_exhaustive]
 /// Error cases that can occur during deserialization from [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 pub enum Error {
     /// Errors that can occur during OID construction and generation from the input data.
-    InvalidObjectId(oid::Error),
+    InvalidObjectId(crate::error::Error),
 
     /// A general error encountered during deserialization.
     /// See: <https://docs.serde.rs/serde/de/trait.Error.html>
@@ -69,12 +69,6 @@ impl From<serde_json::Error> for Error {
     }
 }
 
-impl From<oid::Error> for Error {
-    fn from(err: oid::Error) -> Self {
-        Self::InvalidObjectId(err)
-    }
-}
-
 pub type Result<T> = std::result::Result<T, Error>;
 
 /// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 297b47d6..caccd12f 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -100,7 +100,8 @@ pub(crate) struct ObjectId {
 
 impl ObjectId {
     pub(crate) fn parse(self) -> extjson::de::Result<oid::ObjectId> {
-        let oid = oid::ObjectId::parse_str(self.oid.as_str())?;
+        let oid = oid::ObjectId::parse_str(self.oid.as_str())
+            .map_err(extjson::de::Error::InvalidObjectId)?;
         Ok(oid)
     }
 }
diff --git a/src/oid.rs b/src/oid.rs
index 074b4a06..bb409f5e 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -1,21 +1,19 @@
 //! Module containing functionality related to BSON ObjectIds.
 //! For more information, see the documentation for the [`ObjectId`] type.
 
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
+use std::{convert::TryInto, time::SystemTime};
 use std::{
-    error,
     fmt,
-    result,
     str::FromStr,
     sync::atomic::{AtomicUsize, Ordering},
 };
 
-#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
-use std::{convert::TryInto, time::SystemTime};
-
-use hex::{self, FromHexError};
 use once_cell::sync::Lazy;
 use rand::{random, rng, Rng};
 
+use crate::error::{Error, Result};
+
 const TIMESTAMP_SIZE: usize = 4;
 const PROCESS_ID_SIZE: usize = 5;
 const COUNTER_SIZE: usize = 3;
@@ -29,49 +27,6 @@ const MAX_U24: usize = 0xFF_FFFF;
 static OID_COUNTER: Lazy<AtomicUsize> =
     Lazy::new(|| AtomicUsize::new(rng().random_range(0..=MAX_U24)));
 
-/// Errors that can occur during [`ObjectId`] construction and generation.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Error {
-    /// An invalid character was found in the provided hex string. Valid characters are: `0...9`,
-    /// `a...f`, or `A...F`.
-    #[non_exhaustive]
-    InvalidHexStringCharacter { c: char, index: usize, hex: String },
-
-    /// An [`ObjectId`]'s hex string representation must be an exactly 12-byte (24-char)
-    /// hexadecimal string.
-    #[non_exhaustive]
-    InvalidHexStringLength { length: usize, hex: String },
-}
-
-/// Alias for Result<T, oid::Error>.
-pub type Result<T> = result::Result<T, Error>;
-
-impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::InvalidHexStringCharacter { c, index, hex } => {
-                write!(
-                    fmt,
-                    "invalid character '{}' was found at index {} in the provided hex string: \
-                     \"{}\"",
-                    c, index, hex
-                )
-            }
-            Error::InvalidHexStringLength { length, hex } => {
-                write!(
-                    fmt,
-                    "provided hex string representation must be exactly 12 bytes, instead got: \
-                     \"{}\", length {}",
-                    hex, length
-                )
-            }
-        }
-    }
-}
-
-impl error::Error for Error {}
-
 /// A wrapper around a raw 12-byte ObjectId.
 ///
 /// ## `serde` integration
@@ -198,24 +153,10 @@ impl ObjectId {
     pub fn parse_str(s: impl AsRef<str>) -> Result<ObjectId> {
         let s = s.as_ref();
 
-        let bytes: Vec<u8> = hex::decode(s.as_bytes()).map_err(|e| match e {
-            FromHexError::InvalidHexCharacter { c, index } => Error::InvalidHexStringCharacter {
-                c,
-                index,
-                hex: s.to_string(),
-            },
-            FromHexError::InvalidStringLength | FromHexError::OddLength => {
-                Error::InvalidHexStringLength {
-                    length: s.len(),
-                    hex: s.to_string(),
-                }
-            }
-        })?;
+        let bytes: Vec<u8> =
+            hex::decode(s.as_bytes()).map_err(|e| Error::from_hex_error(e, s.len()))?;
         if bytes.len() != 12 {
-            Err(Error::InvalidHexStringLength {
-                length: s.len(),
-                hex: s.to_string(),
-            })
+            Err(Error::oid_invalid_length(bytes.len()))
         } else {
             let mut byte_array: [u8; 12] = [0; 12];
             byte_array[..].copy_from_slice(&bytes[..]);
diff --git a/src/raw.rs b/src/raw.rs
index 9537e3da..b1a2c8be 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -173,7 +173,7 @@ fn f64_from_slice(val: &[u8]) -> Result<f64> {
         .get(0..8)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed_value(format!(
+            Error::malformed_bytes(format!(
                 "expected 8 bytes to read double, instead got {}",
                 val.len()
             ))
@@ -188,7 +188,7 @@ fn i32_from_slice(val: &[u8]) -> Result<i32> {
         .get(0..4)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed_value(format!(
+            Error::malformed_bytes(format!(
                 "expected 4 bytes to read i32, instead got {}",
                 val.len()
             ))
@@ -203,7 +203,7 @@ fn i64_from_slice(val: &[u8]) -> Result<i64> {
         .get(0..8)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed_value(format!(
+            Error::malformed_bytes(format!(
                 "expected 8 bytes to read i64, instead got {}",
                 val.len()
             ))
@@ -216,7 +216,7 @@ fn u8_from_slice(val: &[u8]) -> Result<u8> {
         .get(0..1)
         .and_then(|s| s.try_into().ok())
         .ok_or_else(|| {
-            Error::malformed_value(format!(
+            Error::malformed_bytes(format!(
                 "expected 1 byte to read u8, instead got {}",
                 val.len()
             ))
@@ -227,7 +227,7 @@ fn u8_from_slice(val: &[u8]) -> Result<u8> {
 pub(crate) fn bool_from_slice(val: &[u8]) -> Result<bool> {
     let val = u8_from_slice(val)?;
     if val > 1 {
-        return Err(Error::malformed_value(format!(
+        return Err(Error::malformed_bytes(format!(
             "boolean must be stored as 0 or 1, got {}",
             val
         )));
@@ -238,7 +238,7 @@ pub(crate) fn bool_from_slice(val: &[u8]) -> Result<bool> {
 
 fn read_len(buf: &[u8]) -> Result<usize> {
     if buf.len() < 4 {
-        return Err(Error::malformed_value(format!(
+        return Err(Error::malformed_bytes(format!(
             "expected buffer with string to contain at least 4 bytes, but it only has {}",
             buf.len()
         )));
@@ -248,14 +248,14 @@ fn read_len(buf: &[u8]) -> Result<usize> {
     let end = checked_add(usize_try_from_i32(length)?, 4)?;
 
     if end < MIN_BSON_STRING_SIZE as usize {
-        return Err(Error::malformed_value(format!(
+        return Err(Error::malformed_bytes(format!(
             "BSON length encoded string needs to be at least {} bytes, instead got {}",
             MIN_BSON_STRING_SIZE, end
         )));
     }
 
     if buf.len() < end {
-        return Err(Error::malformed_value(format!(
+        return Err(Error::malformed_bytes(format!(
             "expected buffer to contain at least {} bytes, but it only has {}",
             end,
             buf.len()
@@ -263,7 +263,7 @@ fn read_len(buf: &[u8]) -> Result<usize> {
     }
 
     if buf[end - 1] != 0 {
-        return Err(Error::malformed_value(
+        return Err(Error::malformed_bytes(
             "expected string to be null-terminated",
         ));
     }
@@ -283,16 +283,16 @@ fn read_lenencode(buf: &[u8]) -> Result<&str> {
 }
 
 fn try_to_str(data: &[u8]) -> Result<&str> {
-    simdutf8::basic::from_utf8(data).map_err(|_| ErrorKind::Utf8Encoding.into())
+    simdutf8::basic::from_utf8(data).map_err(|_| ErrorKind::Utf8Encoding {}.into())
 }
 
 fn usize_try_from_i32(i: i32) -> Result<usize> {
-    usize::try_from(i).map_err(Error::malformed_value)
+    usize::try_from(i).map_err(Error::malformed_bytes)
 }
 
 fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
     lhs.checked_add(rhs)
-        .ok_or_else(|| Error::malformed_value("attempted to add with overflow"))
+        .ok_or_else(|| Error::malformed_bytes("attempted to add with overflow"))
 }
 
 pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
@@ -301,7 +301,7 @@ pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
     let length = i32::from_le_bytes(buf);
 
     if length < MIN_BSON_DOCUMENT_SIZE {
-        return Err(Error::malformed_value("document size too small"));
+        return Err(Error::malformed_bytes("document size too small"));
     }
 
     let mut bytes = Vec::with_capacity(length as usize);
@@ -319,7 +319,7 @@ pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
 
 pub(crate) fn write_cstring(buf: &mut Vec<u8>, s: &str) -> Result<()> {
     if s.contains('\0') {
-        return Err(Error::malformed_value(format!(
+        return Err(Error::malformed_bytes(format!(
             "cstring with interior null: {:?}",
             s
         )));
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 262df7ec..4746d7c5 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -96,17 +96,17 @@ impl RawDocument {
         let data = data.as_ref();
 
         if data.len() < 5 {
-            return Err(Error::malformed_value("document too short"));
+            return Err(Error::malformed_bytes("document too short"));
         }
 
         let length = i32_from_slice(data)?;
 
         if data.len() as i32 != length {
-            return Err(Error::malformed_value("document length incorrect"));
+            return Err(Error::malformed_bytes("document length incorrect"));
         }
 
         if data[data.len() - 1] != 0 {
-            return Err(Error::malformed_value("document not null-terminated"));
+            return Err(Error::malformed_bytes("document not null-terminated"));
         }
 
         Ok(RawDocument::new_unchecked(data))
@@ -497,11 +497,11 @@ impl RawDocument {
         let mut splits = buf.splitn(2, |x| *x == 0);
         let value = splits
             .next()
-            .ok_or_else(|| RawError::malformed_value("no value"))?;
+            .ok_or_else(|| RawError::malformed_bytes("no value"))?;
         if splits.next().is_some() {
             Ok(value)
         } else {
-            Err(RawError::malformed_value("expected null terminator"))
+            Err(RawError::malformed_bytes("expected null terminator"))
         }
     }
 
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 6c3c640e..6355917e 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -80,7 +80,7 @@ impl<'a> RawIter<'a> {
     fn verify_enough_bytes(&self, start: usize, num_bytes: usize) -> Result<()> {
         let end = checked_add(start, num_bytes)?;
         if self.doc.as_bytes().get(start..end).is_none() {
-            return Err(Error::malformed_value(format!(
+            return Err(Error::malformed_bytes(format!(
                 "length exceeds remaining length of buffer: {} vs {}",
                 num_bytes,
                 self.doc.as_bytes().len() - start
@@ -94,7 +94,7 @@ impl<'a> RawIter<'a> {
         let size = i32_from_slice(&self.doc.as_bytes()[starting_at..])? as usize;
 
         if size < MIN_BSON_DOCUMENT_SIZE as usize {
-            return Err(Error::malformed_value(format!(
+            return Err(Error::malformed_bytes(format!(
                 "document too small: {} bytes",
                 size
             )));
@@ -103,7 +103,7 @@ impl<'a> RawIter<'a> {
         self.verify_enough_bytes(starting_at, size)?;
 
         if self.doc.as_bytes()[starting_at + size - 1] != 0 {
-            return Err(Error::malformed_value("not null terminated"));
+            return Err(Error::malformed_bytes("not null terminated"));
         }
         Ok(size)
     }
@@ -317,7 +317,7 @@ impl<'a> RawElement<'a> {
     }
 
     fn malformed_error(&self, e: impl ToString) -> Error {
-        Error::malformed_value(e).with_key(self.key)
+        Error::malformed_bytes(e).with_key(self.key)
     }
 
     pub(crate) fn slice(&self) -> &'a [u8] {
@@ -344,7 +344,7 @@ impl<'a> RawElement<'a> {
         Ok(ObjectId::from_bytes(
             self.doc.as_bytes()[start_at..(start_at + 12)]
                 .try_into()
-                .map_err(|e| Error::malformed_value(e).with_key(self.key))?,
+                .map_err(|e| Error::malformed_bytes(e).with_key(self.key))?,
         ))
     }
 }
@@ -353,7 +353,7 @@ impl RawIter<'_> {
     fn get_next_length_at(&self, start_at: usize) -> Result<usize> {
         let len = i32_from_slice(&self.doc.as_bytes()[start_at..])?;
         if len < 0 {
-            Err(Error::malformed_value("lengths can't be negative"))
+            Err(Error::malformed_bytes("lengths can't be negative"))
         } else {
             Ok(len as usize)
         }
@@ -363,7 +363,7 @@ impl RawIter<'_> {
         let element_type = match ElementType::from(self.doc.as_bytes()[self.offset]) {
             Some(et) => et,
             None => {
-                return Err(Error::malformed_value(format!(
+                return Err(Error::malformed_bytes(format!(
                     "invalid tag: {}",
                     self.doc.as_bytes()[self.offset]
                 )));
@@ -417,11 +417,11 @@ impl<'a> Iterator for RawIter<'a> {
                 return None;
             } else {
                 self.valid = false;
-                return Some(Err(Error::malformed_value("document not null terminated")));
+                return Some(Err(Error::malformed_bytes("document not null terminated")));
             }
         } else if self.offset >= self.doc.as_bytes().len() {
             self.valid = false;
-            return Some(Err(Error::malformed_value("iteration overflowed document")));
+            return Some(Err(Error::malformed_bytes("iteration overflowed document")));
         }
 
         let key = match self.doc.read_cstring_at(self.offset + 1) {
diff --git a/src/raw/test.rs b/src/raw/test.rs
index 0bc6db71..b651004d 100644
--- a/src/raw/test.rs
+++ b/src/raw/test.rs
@@ -16,13 +16,11 @@ use crate::{
 
 #[test]
 fn test_decimal128_doesnt_panic_on_bad_codepoint_boundary() {
-    use crate::decimal128::ParseError;
     use std::str::FromStr;
     // idx 34 (Coefficient::MAX_DIGITS) on this string isn't a valid codepoint boundary
-    assert!(matches!(
-        Decimal128::from_str("111111111111111111111111111111111❤"),
-        Err(ParseError::Unparseable)
-    ))
+    assert!(Decimal128::from_str("111111111111111111111111111111111❤")
+        .unwrap_err()
+        .is_decimal128_unparseable());
 }
 
 #[test]
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index 9eb839db..8e16f3b6 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -169,11 +169,11 @@ fn cstring_null_bytes_error() {
         let result = doc.encode_to_vec();
         assert!(result.is_err(), "unexpected success");
         let err = result.unwrap_err();
-        assert!(err.is_malformed_value(), "unexpected error: {:?}", err);
+        assert!(err.is_malformed_bytes(), "unexpected error: {:?}", err);
         let result = serialize_to_vec(&doc);
         assert!(result.is_err(), "unexpected success");
         match result.unwrap_err().strip_path() {
-            ser::Error::Crate(inner) if inner.is_malformed_value() => (),
+            ser::Error::Crate(inner) if inner.is_malformed_bytes() => (),
             err => panic!("unexpected error: {:?}", err),
         };
     }
diff --git a/src/uuid.rs b/src/uuid.rs
index 61897b2e..70560361 100644
--- a/src/uuid.rs
+++ b/src/uuid.rs
@@ -137,7 +137,12 @@ mod test;
 
 use std::fmt::{self, Display};
 
-use crate::{spec::BinarySubtype, Binary, Bson};
+use crate::{
+    error::{Error, Result},
+    spec::BinarySubtype,
+    Binary,
+    Bson,
+};
 
 /// Special type name used in the [`Uuid`] serialization implementation to indicate a BSON
 /// UUID is being serialized or deserialized. The BSON serializers/deserializers will handle this
@@ -185,9 +190,7 @@ impl Uuid {
 
     /// Creates a [`Uuid`] from the provided hex string.
     pub fn parse_str(input: impl AsRef<str>) -> Result<Self> {
-        let uuid = uuid::Uuid::parse_str(input.as_ref()).map_err(|e| Error::InvalidUuidString {
-            message: e.to_string(),
-        })?;
+        let uuid = uuid::Uuid::parse_str(input.as_ref()).map_err(Error::invalid_uuid_string)?;
         Ok(Self::from_external_uuid(uuid))
     }
 
@@ -393,25 +396,23 @@ impl Binary {
     pub fn to_uuid_with_representation(&self, rep: UuidRepresentation) -> Result<Uuid> {
         // If representation is non-standard, then its subtype must be UuidOld
         if rep != UuidRepresentation::Standard && self.subtype != BinarySubtype::UuidOld {
-            return Err(Error::RepresentationMismatch {
-                requested_representation: rep,
-                actual_binary_subtype: self.subtype,
-                expected_binary_subtype: BinarySubtype::UuidOld,
-            });
+            return Err(Error::uuid_representation_mismatch(
+                rep,
+                self.subtype,
+                BinarySubtype::UuidOld,
+            ));
         }
         // If representation is standard, then its subtype must be Uuid
         if rep == UuidRepresentation::Standard && self.subtype != BinarySubtype::Uuid {
-            return Err(Error::RepresentationMismatch {
-                requested_representation: rep,
-                actual_binary_subtype: self.subtype,
-                expected_binary_subtype: BinarySubtype::Uuid,
-            });
+            return Err(Error::uuid_representation_mismatch(
+                rep,
+                self.subtype,
+                BinarySubtype::UuidOld,
+            ));
         }
         // Must be 16 bytes long
         if self.bytes.len() != 16 {
-            return Err(Error::InvalidLength {
-                length: self.bytes.len(),
-            });
+            return Err(Error::invalid_uuid_length(self.bytes.len()));
         }
         let mut buf = [0u8; 16];
         buf.copy_from_slice(&self.bytes);
@@ -480,66 +481,3 @@ macro_rules! trait_impls {
     };
 }
 trait_impls!(feature = "uuid-1", uuid::Uuid);
-
-/// Errors that can occur during [`Uuid`] construction and generation.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Error {
-    /// Error returned when an invalid string is provided to [`Uuid::parse_str`].
-    #[non_exhaustive]
-    InvalidUuidString { message: String },
-
-    /// Error returned when the representation specified does not match the underlying
-    /// [`crate::Binary`] value in [`crate::Binary::to_uuid_with_representation`].
-    #[non_exhaustive]
-    RepresentationMismatch {
-        /// The subtype that was expected given the requested representation.
-        expected_binary_subtype: BinarySubtype,
-
-        /// The actual subtype of the binary value.
-        actual_binary_subtype: BinarySubtype,
-
-        /// The requested representation.
-        requested_representation: UuidRepresentation,
-    },
-
-    /// Error returned from [`crate::Binary::to_uuid`] if the underling data is not 16 bytes long.
-    #[non_exhaustive]
-    InvalidLength {
-        /// The actual length of the data.
-        length: usize,
-    },
-}
-
-/// Alias for `Result<T, bson::uuid::Error>`.
-pub type Result<T> = std::result::Result<T, Error>;
-
-impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::InvalidUuidString { message } => {
-                write!(fmt, "{}", message)
-            }
-            Error::RepresentationMismatch {
-                expected_binary_subtype,
-                actual_binary_subtype,
-                requested_representation,
-            } => {
-                write!(
-                    fmt,
-                    "expected {:?} when converting to UUID with {:?}, isntead got {:?}",
-                    expected_binary_subtype, requested_representation, actual_binary_subtype
-                )
-            }
-            Error::InvalidLength { length } => {
-                write!(
-                    fmt,
-                    "expected UUID to contain 16 bytes, instead got {}",
-                    length
-                )
-            }
-        }
-    }
-}
-
-impl std::error::Error for Error {}

From 2c00882180f2535a16127f41ad18e4e0da3085e1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 23 Jun 2025 10:24:28 -0400
Subject: [PATCH 125/156] Bump the rust-dependencies group with 6 updates
 (#558)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 64fbbcaa..21931cc5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -67,9 +67,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
 
 [[package]]
 name = "base64"
@@ -366,9 +366,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.12"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
 dependencies = [
  "libc",
  "windows-sys",
@@ -537,9 +537,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.173"
+version = "0.2.174"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
 
 [[package]]
 name = "linux-raw-sys"
@@ -696,9 +696,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
 
 [[package]]
 name = "radium"
@@ -1414,18 +1414,18 @@ dependencies = [
 
 [[package]]
 name = "zerocopy"
-version = "0.8.25"
+version = "0.8.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.8.25"
+version = "0.8.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
 dependencies = [
  "proc-macro2",
  "quote",

From 92364e9e6aa10b31dee64e272c1357f0c2f9c323 Mon Sep 17 00:00:00 2001
From: Asger Hautop Drewsen <asger@tyilo.com>
Date: Thu, 26 Jun 2025 16:29:10 +0200
Subject: [PATCH 126/156] Implement `FromStr` for `Uuid` (#561)

---
 src/uuid.rs | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/uuid.rs b/src/uuid.rs
index 70560361..c747fffb 100644
--- a/src/uuid.rs
+++ b/src/uuid.rs
@@ -135,7 +135,10 @@
 #[cfg(test)]
 mod test;
 
-use std::fmt::{self, Display};
+use std::{
+    fmt::{self, Display},
+    str::FromStr,
+};
 
 use crate::{
     error::{Error, Result},
@@ -210,6 +213,14 @@ impl Default for Uuid {
     }
 }
 
+impl FromStr for Uuid {
+    type Err = Error;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        Self::parse_str(s)
+    }
+}
+
 #[cfg(feature = "uuid-1")]
 #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
 impl Uuid {

From be2a10772e798a53b16938fb801d135c06c175bb Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 26 Jun 2025 11:50:52 -0400
Subject: [PATCH 127/156] RUST-1992 Consolidate binary encoding logic (#560)

---
 src/binary.rs                      |  7 +--
 src/de.rs                          |  2 -
 src/raw/bson_ref.rs                | 46 ++++++++++++++-
 src/raw/document_buf/raw_writer.rs | 73 +-----------------------
 src/raw/serde/seeded_visitor.rs    | 72 ++---------------------
 src/ser.rs                         | 53 -----------------
 src/ser/raw.rs                     | 55 ++++++++----------
 src/ser/raw/document_serializer.rs |  5 +-
 src/ser/raw/value_serializer.rs    | 92 ++++++++++++++++++------------
 9 files changed, 141 insertions(+), 264 deletions(-)

diff --git a/src/binary.rs b/src/binary.rs
index 58416ee1..9c874d96 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -1,10 +1,7 @@
 #! Module containing functionality related to BSON binary values.
 mod vector;
 
-use std::{
-    convert::TryFrom,
-    fmt::{self, Display},
-};
+use std::fmt::{self, Display};
 
 use crate::{
     base64,
@@ -65,6 +62,8 @@ impl Binary {
 
     #[cfg(feature = "serde")]
     pub(crate) fn from_extended_doc(doc: &crate::Document) -> Option<Self> {
+        use std::convert::TryFrom;
+
         let binary_doc = doc.get_document("$binary").ok()?;
 
         if let Ok(bytes) = binary_doc.get_str("base64") {
diff --git a/src/de.rs b/src/de.rs
index 821a4dca..76a9bcda 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -46,8 +46,6 @@ pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor};
 #[cfg(test)]
 pub(crate) use self::raw::Deserializer as RawDeserializer;
 
-pub(crate) const MAX_BSON_SIZE: i32 = i32::MAX;
-
 /// Hint provided to the deserializer via `deserialize_newtype_struct` as to the type of thing
 /// being deserialized.
 #[derive(Debug, Clone, Copy)]
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index 2edceaa7..8a72fed5 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -3,7 +3,7 @@ use std::convert::{TryFrom, TryInto};
 use super::{bson::RawBson, Error, RawArray, RawDocument, Result};
 use crate::{
     oid::{self, ObjectId},
-    raw::RawJavaScriptCodeWithScope,
+    raw::{write_cstring, write_string, RawJavaScriptCodeWithScope},
     spec::{BinarySubtype, ElementType},
     Binary,
     Bson,
@@ -285,6 +285,50 @@ impl<'a> RawBsonRef<'a> {
             }),
         }
     }
+
+    #[inline]
+    pub(crate) fn append_to(self, dest: &mut Vec<u8>) -> Result<()> {
+        match self {
+            Self::Int32(val) => dest.extend(val.to_le_bytes()),
+            Self::Int64(val) => dest.extend(val.to_le_bytes()),
+            Self::Double(val) => dest.extend(val.to_le_bytes()),
+            Self::Binary(b @ RawBinaryRef { subtype, bytes }) => {
+                let len = b.len();
+                dest.extend(len.to_le_bytes());
+                dest.push(subtype.into());
+                if let BinarySubtype::BinaryOld = subtype {
+                    dest.extend((len - 4).to_le_bytes())
+                }
+                dest.extend(bytes);
+            }
+            Self::String(s) => write_string(dest, s),
+            Self::Array(raw_array) => dest.extend(raw_array.as_bytes()),
+            Self::Document(raw_document) => dest.extend(raw_document.as_bytes()),
+            Self::Boolean(b) => dest.push(b as u8),
+            Self::RegularExpression(re) => {
+                write_cstring(dest, re.pattern)?;
+                write_cstring(dest, re.options)?;
+            }
+            Self::JavaScriptCode(js) => write_string(dest, js),
+            Self::JavaScriptCodeWithScope(code_w_scope) => {
+                let len = code_w_scope.len();
+                dest.extend(len.to_le_bytes());
+                write_string(dest, code_w_scope.code);
+                dest.extend(code_w_scope.scope.as_bytes());
+            }
+            Self::Timestamp(ts) => dest.extend(ts.to_le_bytes()),
+            Self::ObjectId(oid) => dest.extend(oid.bytes()),
+            Self::DateTime(dt) => dest.extend(dt.timestamp_millis().to_le_bytes()),
+            Self::Symbol(s) => write_string(dest, s),
+            Self::Decimal128(d) => dest.extend(d.bytes()),
+            Self::DbPointer(dbp) => {
+                write_string(dest, dbp.namespace);
+                dest.extend(dbp.id.bytes());
+            }
+            Self::Null | Self::Undefined | Self::MinKey | Self::MaxKey => {}
+        }
+        Ok(())
+    }
 }
 
 #[cfg(feature = "serde")]
diff --git a/src/raw/document_buf/raw_writer.rs b/src/raw/document_buf/raw_writer.rs
index 59edfc82..dc550dbc 100644
--- a/src/raw/document_buf/raw_writer.rs
+++ b/src/raw/document_buf/raw_writer.rs
@@ -1,8 +1,4 @@
-use crate::{
-    raw::{write_cstring, write_string},
-    spec::BinarySubtype,
-    RawBsonRef,
-};
+use crate::{raw::write_cstring, RawBsonRef};
 
 pub(super) struct RawWriter<'a> {
     data: &'a mut Vec<u8>,
@@ -18,72 +14,7 @@ impl<'a> RawWriter<'a> {
         self.data[original_len - 1] = value.element_type() as u8;
 
         write_cstring(self.data, key)?;
-
-        match value {
-            RawBsonRef::Int32(i) => {
-                self.data.extend(i.to_le_bytes());
-            }
-            RawBsonRef::String(s) => {
-                write_string(self.data, s);
-            }
-            RawBsonRef::Document(d) => {
-                self.data.extend(d.as_bytes());
-            }
-            RawBsonRef::Array(a) => {
-                self.data.extend(a.as_bytes());
-            }
-            RawBsonRef::Binary(b) => {
-                let len = b.len();
-                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(b.bytes);
-            }
-            RawBsonRef::Boolean(b) => {
-                self.data.push(b as u8);
-            }
-            RawBsonRef::DateTime(dt) => {
-                self.data.extend(dt.timestamp_millis().to_le_bytes());
-            }
-            RawBsonRef::DbPointer(dbp) => {
-                write_string(self.data, dbp.namespace);
-                self.data.extend(dbp.id.bytes());
-            }
-            RawBsonRef::Decimal128(d) => {
-                self.data.extend(d.bytes());
-            }
-            RawBsonRef::Double(d) => {
-                self.data.extend(d.to_le_bytes());
-            }
-            RawBsonRef::Int64(i) => {
-                self.data.extend(i.to_le_bytes());
-            }
-            RawBsonRef::RegularExpression(re) => {
-                write_cstring(self.data, re.pattern)?;
-                write_cstring(self.data, re.options)?;
-            }
-            RawBsonRef::JavaScriptCode(js) => {
-                write_string(self.data, js);
-            }
-            RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => {
-                let len = code_w_scope.len();
-                self.data.extend(len.to_le_bytes());
-                write_string(self.data, code_w_scope.code);
-                self.data.extend(code_w_scope.scope.as_bytes());
-            }
-            RawBsonRef::Timestamp(ts) => {
-                self.data.extend(ts.to_le_bytes());
-            }
-            RawBsonRef::ObjectId(oid) => {
-                self.data.extend(oid.bytes());
-            }
-            RawBsonRef::Symbol(s) => {
-                write_string(self.data, s);
-            }
-            RawBsonRef::Null | RawBsonRef::Undefined | RawBsonRef::MinKey | RawBsonRef::MaxKey => {}
-        }
+        value.append_to(self.data)?;
 
         // append trailing null byte
         self.data.push(0);
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
index 2b5034fa..8361421c 100644
--- a/src/raw/serde/seeded_visitor.rs
+++ b/src/raw/serde/seeded_visitor.rs
@@ -271,72 +271,12 @@ impl<'de> Visitor<'de> for SeededVisitor<'_, 'de> {
                         Ok(ElementType::Array)
                     }
                     // Cases that don't
-                    _ => match bson.as_ref() {
-                        RawBsonRef::ObjectId(oid) => {
-                            self.buffer.append_bytes(&oid.bytes());
-                            Ok(ElementType::ObjectId)
-                        }
-                        RawBsonRef::Symbol(s) => {
-                            self.append_string(s);
-                            Ok(ElementType::Symbol)
-                        }
-                        RawBsonRef::Decimal128(d) => {
-                            self.buffer.append_bytes(&d.bytes);
-                            Ok(ElementType::Decimal128)
-                        }
-                        RawBsonRef::RegularExpression(re) => {
-                            self.append_cstring(re.pattern)
-                                .map_err(SerdeError::custom)?;
-                            self.append_cstring(re.options)
-                                .map_err(SerdeError::custom)?;
-                            Ok(ElementType::RegularExpression)
-                        }
-                        RawBsonRef::Undefined => Ok(ElementType::Undefined),
-                        RawBsonRef::DateTime(dt) => {
-                            self.buffer
-                                .append_bytes(&dt.timestamp_millis().to_le_bytes());
-                            Ok(ElementType::DateTime)
-                        }
-                        RawBsonRef::Timestamp(ts) => {
-                            self.buffer.append_bytes(&ts.increment.to_le_bytes());
-                            self.buffer.append_bytes(&ts.time.to_le_bytes());
-                            Ok(ElementType::Timestamp)
-                        }
-                        RawBsonRef::MinKey => Ok(ElementType::MinKey),
-                        RawBsonRef::MaxKey => Ok(ElementType::MaxKey),
-                        RawBsonRef::JavaScriptCode(s) => {
-                            self.append_string(s);
-                            Ok(ElementType::JavaScriptCode)
-                        }
-                        RawBsonRef::JavaScriptCodeWithScope(jsc) => {
-                            let length_index = self.pad_document_length();
-                            self.append_string(jsc.code);
-                            self.buffer.append_bytes(jsc.scope.as_bytes());
-
-                            let length_bytes =
-                                ((self.buffer.len() - length_index) as i32).to_le_bytes();
-                            self.buffer
-                                .copy_from_slice(length_index..length_index + 4, &length_bytes);
-
-                            Ok(ElementType::JavaScriptCodeWithScope)
-                        }
-                        RawBsonRef::DbPointer(dbp) => {
-                            self.append_string(dbp.namespace);
-                            self.buffer.append_bytes(&dbp.id.bytes());
-                            Ok(ElementType::DbPointer)
-                        }
-                        RawBsonRef::Double(d) => self.visit_f64(d),
-                        RawBsonRef::String(s) => self.visit_str(s),
-                        RawBsonRef::Boolean(b) => self.visit_bool(b),
-                        RawBsonRef::Null => self.visit_none(),
-                        RawBsonRef::Int32(i) => self.visit_i32(i),
-                        RawBsonRef::Int64(i) => self.visit_i64(i),
-                        // These are always borrowed and are handled
-                        // at the top of the outer `match`.
-                        RawBsonRef::Array(_) | RawBsonRef::Document(_) | RawBsonRef::Binary(_) => {
-                            unreachable!()
-                        }
-                    },
+                    _ => {
+                        let bson = bson.as_ref();
+                        bson.append_to(self.buffer.get_owned_buffer())
+                            .map_err(A::Error::custom)?;
+                        Ok(bson.element_type())
+                    }
                 }
             }
             MapParse::Aggregate(first_key) => {
diff --git a/src/ser.rs b/src/ser.rs
index 43ead226..5d925ab6 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -30,68 +30,15 @@ pub use self::{
     serde::Serializer,
 };
 
-use std::io::Write;
-
 #[rustfmt::skip]
 use ::serde::{ser::Error as SerdeError, Serialize};
 
 use crate::{
     bson::{Bson, Document},
-    de::MAX_BSON_SIZE,
     ser::serde::SerializerOptions,
-    spec::BinarySubtype,
     RawDocumentBuf,
 };
 
-#[inline]
-pub(crate) fn write_i32<W: Write + ?Sized>(writer: &mut W, val: i32) -> Result<()> {
-    writer
-        .write_all(&val.to_le_bytes())
-        .map(|_| ())
-        .map_err(From::from)
-}
-
-#[inline]
-fn write_i64<W: Write + ?Sized>(writer: &mut W, val: i64) -> Result<()> {
-    writer
-        .write_all(&val.to_le_bytes())
-        .map(|_| ())
-        .map_err(From::from)
-}
-
-#[inline]
-fn write_f64<W: Write + ?Sized>(writer: &mut W, val: f64) -> Result<()> {
-    writer
-        .write_all(&val.to_le_bytes())
-        .map(|_| ())
-        .map_err(From::from)
-}
-
-#[inline]
-fn write_binary<W: Write>(mut writer: W, bytes: &[u8], subtype: BinarySubtype) -> Result<()> {
-    let len = if let BinarySubtype::BinaryOld = subtype {
-        bytes.len() + 4
-    } else {
-        bytes.len()
-    };
-
-    if len > MAX_BSON_SIZE as usize {
-        return Err(Error::custom(format!(
-            "binary length {} exceeded maximum size",
-            bytes.len()
-        )));
-    }
-
-    write_i32(&mut writer, len as i32)?;
-    writer.write_all(&[subtype.into()])?;
-
-    if let BinarySubtype::BinaryOld = subtype {
-        write_i32(&mut writer, len as i32 - 4)?;
-    };
-
-    writer.write_all(bytes).map_err(From::from)
-}
-
 /// Encode a `T` Serializable into a [`Bson`] value.
 ///
 /// The [`Serializer`] used by this function presents itself as human readable, whereas the
diff --git a/src/ser/raw.rs b/src/ser/raw.rs
index 480fdd46..6980423b 100644
--- a/src/ser/raw.rs
+++ b/src/ser/raw.rs
@@ -1,8 +1,6 @@
 mod document_serializer;
 mod value_serializer;
 
-use std::io::Write;
-
 use serde::{
     ser::{Error as SerdeError, SerializeMap, SerializeStruct},
     Serialize,
@@ -10,13 +8,16 @@ use serde::{
 
 use self::value_serializer::{ValueSerializer, ValueType};
 
-use super::{write_binary, write_f64, write_i32, write_i64};
 use crate::{
-    raw::{write_cstring, write_string, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    raw::{write_cstring, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     ser::{Error, Result},
     serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
     uuid::UUID_NEWTYPE_NAME,
+    RawArray,
+    RawBinaryRef,
+    RawBsonRef,
+    RawDocument,
 };
 use document_serializer::DocumentSerializer;
 
@@ -104,6 +105,12 @@ impl Serializer {
         let portion = &mut self.bytes[at..at + 4];
         portion.copy_from_slice(&with.to_le_bytes());
     }
+
+    fn serialize_raw(&mut self, v: RawBsonRef) -> Result<()> {
+        self.update_element_type(v.element_type())?;
+        v.append_to(&mut self.bytes)?;
+        Ok(())
+    }
 }
 
 impl<'a> serde::Serializer for &'a mut Serializer {
@@ -124,9 +131,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
 
     #[inline]
     fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
-        self.update_element_type(ElementType::Boolean)?;
-        self.bytes.push(v as u8);
-        Ok(())
+        self.serialize_raw(RawBsonRef::Boolean(v))
     }
 
     #[inline]
@@ -141,16 +146,12 @@ impl<'a> serde::Serializer for &'a mut Serializer {
 
     #[inline]
     fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
-        self.update_element_type(ElementType::Int32)?;
-        write_i32(&mut self.bytes, v)?;
-        Ok(())
+        self.serialize_raw(RawBsonRef::Int32(v))
     }
 
     #[inline]
     fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
-        self.update_element_type(ElementType::Int64)?;
-        write_i64(&mut self.bytes, v)?;
-        Ok(())
+        self.serialize_raw(RawBsonRef::Int64(v))
     }
 
     #[inline]
@@ -185,8 +186,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
 
     #[inline]
     fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
-        self.update_element_type(ElementType::Double)?;
-        write_f64(&mut self.bytes, v)
+        self.serialize_raw(RawBsonRef::Double(v))
     }
 
     #[inline]
@@ -198,32 +198,27 @@ impl<'a> serde::Serializer for &'a mut Serializer {
 
     #[inline]
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
-        self.update_element_type(ElementType::String)?;
-        write_string(&mut self.bytes, v);
-        Ok(())
+        self.serialize_raw(RawBsonRef::String(v))
     }
 
     #[inline]
     fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
         match self.hint.take() {
             SerializerHint::RawDocument => {
-                self.update_element_type(ElementType::EmbeddedDocument)?;
-                self.bytes.write_all(v)?;
+                self.serialize_raw(RawBsonRef::Document(RawDocument::new_unchecked(v)))?;
             }
             SerializerHint::RawArray => {
-                self.update_element_type(ElementType::Array)?;
-                self.bytes.write_all(v)?;
+                self.serialize_raw(RawBsonRef::Array(RawArray::from_doc(
+                    RawDocument::new_unchecked(v),
+                )))?;
             }
             hint => {
-                self.update_element_type(ElementType::Binary)?;
-
                 let subtype = if matches!(hint, SerializerHint::Uuid) {
                     BinarySubtype::Uuid
                 } else {
                     BinarySubtype::Generic
                 };
-
-                write_binary(&mut self.bytes, v, subtype)?;
+                self.serialize_raw(RawBsonRef::Binary(RawBinaryRef { subtype, bytes: v }))?;
             }
         };
         Ok(())
@@ -231,8 +226,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
 
     #[inline]
     fn serialize_none(self) -> Result<Self::Ok> {
-        self.update_element_type(ElementType::Null)?;
-        Ok(())
+        self.serialize_raw(RawBsonRef::Null)
     }
 
     #[inline]
@@ -444,7 +438,8 @@ impl<'a> VariantSerializer<'a> {
     ) -> Result<Self> {
         let doc_start = rs.bytes.len();
         // write placeholder length for document, will be updated at end
-        write_i32(&mut rs.bytes, 0)?;
+        static ZERO: RawBsonRef = RawBsonRef::Int32(0);
+        ZERO.append_to(&mut rs.bytes)?;
 
         let inner = match inner_type {
             VariantInnerType::Struct => ElementType::EmbeddedDocument,
@@ -454,7 +449,7 @@ impl<'a> VariantSerializer<'a> {
         write_cstring(&mut rs.bytes, variant)?;
         let inner_start = rs.bytes.len();
         // write placeholder length for inner, will be updated at end
-        write_i32(&mut rs.bytes, 0)?;
+        ZERO.append_to(&mut rs.bytes)?;
 
         Ok(Self {
             root_serializer: rs,
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index 10e3b93e..55da28d2 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -2,9 +2,10 @@ use serde::{ser::Impossible, Serialize};
 
 use crate::{
     raw::write_cstring,
-    ser::{write_i32, Error, Result},
+    ser::{Error, Result},
     serialize_to_bson,
     Bson,
+    RawBsonRef,
 };
 
 use super::Serializer;
@@ -23,7 +24,7 @@ pub(crate) struct DocumentSerializer<'a> {
 impl<'a> DocumentSerializer<'a> {
     pub(crate) fn start(rs: &'a mut Serializer) -> crate::ser::Result<Self> {
         let start = rs.bytes.len();
-        write_i32(&mut rs.bytes, 0)?;
+        RawBsonRef::Int32(0).append_to(&mut rs.bytes)?;
         Ok(Self {
             root_serializer: rs,
             num_keys_serialized: 0,
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 45a4ff6a..c57aa44f 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -1,4 +1,4 @@
-use std::{convert::TryFrom, io::Write};
+use std::convert::TryFrom;
 
 use serde::{
     ser::{Error as SerdeError, Impossible, SerializeMap, SerializeStruct},
@@ -8,9 +8,11 @@ use serde::{
 use crate::{
     base64,
     oid::ObjectId,
-    raw::{write_cstring, write_string, RAW_DOCUMENT_NEWTYPE},
-    ser::{write_binary, write_i32, write_i64, Error, Result},
+    raw::{write_string, RAW_DOCUMENT_NEWTYPE},
+    ser::{Error, Result},
     spec::{BinarySubtype, ElementType},
+    RawBinaryRef,
+    RawBsonRef,
     RawDocument,
     RawJavaScriptCodeWithScopeRef,
 };
@@ -48,7 +50,9 @@ enum SerializationStep {
 
     RegEx,
     RegExPattern,
-    RegExOptions,
+    RegExOptions {
+        pattern: String,
+    },
 
     Timestamp,
     TimestampTime,
@@ -58,7 +62,9 @@ enum SerializationStep {
 
     DbPointer,
     DbPointerRef,
-    DbPointerId,
+    DbPointerId {
+        ns: String,
+    },
 
     Code,
 
@@ -189,11 +195,12 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                 Ok(())
             }
             SerializationStep::TimestampIncrement { time } => {
-                let t = u32::try_from(time).map_err(Error::custom)?;
-                let i = u32::try_from(v).map_err(Error::custom)?;
+                let time = u32::try_from(time).map_err(Error::custom)?;
+                let increment = u32::try_from(v).map_err(Error::custom)?;
+
+                RawBsonRef::Timestamp(crate::Timestamp { time, increment })
+                    .append_to(&mut self.root_serializer.bytes)?;
 
-                write_i32(&mut self.root_serializer.bytes, i as i32)?;
-                write_i32(&mut self.root_serializer.bytes, t as i32)?;
                 Ok(())
             }
             _ => Err(self.invalid_step("i64")),
@@ -204,7 +211,11 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
         match self.state {
             SerializationStep::RawBinarySubType { ref bytes } => {
-                write_binary(&mut self.root_serializer.bytes, bytes.as_slice(), v.into())?;
+                let binary = RawBinaryRef {
+                    subtype: v.into(),
+                    bytes,
+                };
+                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes)?;
                 self.state = SerializationStep::Done;
                 Ok(())
             }
@@ -245,12 +256,13 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
         match &self.state {
             SerializationStep::DateTimeNumberLong => {
-                let millis: i64 = v.parse().map_err(Error::custom)?;
-                write_i64(&mut self.root_serializer.bytes, millis)?;
+                let millis = v.parse().map_err(Error::custom)?;
+                RawBsonRef::DateTime(crate::DateTime::from_millis(millis))
+                    .append_to(&mut self.root_serializer.bytes)?;
             }
             SerializationStep::Oid => {
                 let oid = ObjectId::parse_str(v).map_err(Error::custom)?;
-                self.root_serializer.bytes.write_all(&oid.bytes())?;
+                RawBsonRef::ObjectId(oid).append_to(&mut self.root_serializer.bytes)?;
             }
             SerializationStep::BinaryBytes => {
                 self.state = SerializationStep::BinarySubType {
@@ -260,26 +272,36 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::BinarySubType { base64 } => {
                 let subtype_byte = hex::decode(v).map_err(Error::custom)?;
                 let subtype: BinarySubtype = subtype_byte[0].into();
-
-                let bytes = base64::decode(base64.as_str()).map_err(Error::custom)?;
-
-                write_binary(&mut self.root_serializer.bytes, bytes.as_slice(), subtype)?;
+                let bytes = &base64::decode(base64.as_str()).map_err(Error::custom)?;
+                let binary = RawBinaryRef { subtype, bytes };
+                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes)?;
             }
-            SerializationStep::Symbol | SerializationStep::DbPointerRef => {
-                write_string(&mut self.root_serializer.bytes, v);
+            SerializationStep::Symbol => {
+                RawBsonRef::Symbol(v).append_to(&mut self.root_serializer.bytes)?;
+            }
+            SerializationStep::DbPointerRef => {
+                self.state = SerializationStep::DbPointerId { ns: v.to_owned() };
+            }
+            SerializationStep::DbPointerId { ns } => {
+                let id = ObjectId::parse_str(v).map_err(Error::custom)?;
+                RawBsonRef::DbPointer(crate::RawDbPointerRef { namespace: ns, id })
+                    .append_to(&mut self.root_serializer.bytes)?;
             }
             SerializationStep::RegExPattern => {
-                write_cstring(&mut self.root_serializer.bytes, v)?;
+                self.state = SerializationStep::RegExOptions {
+                    pattern: v.to_string(),
+                };
             }
-            SerializationStep::RegExOptions => {
+            SerializationStep::RegExOptions { pattern } => {
                 let mut chars: Vec<_> = v.chars().collect();
                 chars.sort_unstable();
 
-                let sorted = chars.into_iter().collect::<String>();
-                write_cstring(&mut self.root_serializer.bytes, sorted.as_str())?;
+                let options = &chars.into_iter().collect::<String>();
+                RawBsonRef::RegularExpression(crate::RawRegexRef { pattern, options })
+                    .append_to(&mut self.root_serializer.bytes)?;
             }
             SerializationStep::Code => {
-                write_string(&mut self.root_serializer.bytes, v);
+                RawBsonRef::JavaScriptCode(v).append_to(&mut self.root_serializer.bytes)?;
             }
             SerializationStep::CodeWithScopeCode => {
                 self.state = SerializationStep::CodeWithScopeScope {
@@ -301,7 +323,8 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
         match self.state {
             SerializationStep::Decimal128Value => {
-                self.root_serializer.bytes.write_all(v)?;
+                let dec = crate::Decimal128::from_bytes(v.try_into().map_err(Error::custom)?);
+                RawBsonRef::Decimal128(dec).append_to(&mut self.root_serializer.bytes)?;
                 Ok(())
             }
             SerializationStep::BinaryBytes => {
@@ -313,9 +336,8 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                     code,
                     scope: RawDocument::decode_from_bytes(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)?;
+                RawBsonRef::JavaScriptCodeWithScope(raw)
+                    .append_to(&mut self.root_serializer.bytes)?;
                 self.state = SerializationStep::Done;
                 Ok(())
             }
@@ -476,7 +498,7 @@ impl SerializeStruct for &mut ValueSerializer<'_> {
                 self.state = SerializationStep::BinaryBytes;
                 value.serialize(&mut **self)?;
             }
-            (SerializationStep::BinaryBytes, key) if key == "bytes" || key == "base64" => {
+            (SerializationStep::BinaryBytes, "bytes" | "base64") => {
                 // state is updated in serialize
                 value.serialize(&mut **self)?;
             }
@@ -497,10 +519,10 @@ impl SerializeStruct for &mut ValueSerializer<'_> {
                 value.serialize(&mut **self)?;
             }
             (SerializationStep::RegExPattern, "pattern") => {
+                // state is updated in serialize
                 value.serialize(&mut **self)?;
-                self.state = SerializationStep::RegExOptions;
             }
-            (SerializationStep::RegExOptions, "options") => {
+            (SerializationStep::RegExOptions { .. }, "options") => {
                 value.serialize(&mut **self)?;
                 self.state = SerializationStep::Done;
             }
@@ -521,12 +543,12 @@ impl SerializeStruct for &mut ValueSerializer<'_> {
                 value.serialize(&mut **self)?;
             }
             (SerializationStep::DbPointerRef, "$ref") => {
+                // state is updated in serialize
                 value.serialize(&mut **self)?;
-                self.state = SerializationStep::DbPointerId;
             }
-            (SerializationStep::DbPointerId, "$id") => {
-                self.state = SerializationStep::Oid;
+            (SerializationStep::DbPointerId { .. }, "$oid" | "$id") => {
                 value.serialize(&mut **self)?;
+                self.state = SerializationStep::Done;
             }
             (SerializationStep::Code, "$code") => {
                 value.serialize(&mut **self)?;
@@ -590,7 +612,7 @@ impl<'a> CodeWithScopeSerializer<'a> {
     #[inline]
     fn start(code: &str, rs: &'a mut Serializer) -> Result<Self> {
         let start = rs.bytes.len();
-        write_i32(&mut rs.bytes, 0)?; // placeholder length
+        RawBsonRef::Int32(0).append_to(&mut rs.bytes)?; // placeholder length
         write_string(&mut rs.bytes, code);
 
         let doc = DocumentSerializer::start(rs)?;

From 3ee9858b81f0f682cd7db928a9f097e2c1301136 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 30 Jun 2025 10:09:23 -0400
Subject: [PATCH 128/156] Bump the rust-dependencies group with 2 updates
 (#564)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 21931cc5..14501d59 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -129,7 +129,7 @@ dependencies = [
  "getrandom 0.2.16",
  "getrandom 0.3.2",
  "hex",
- "indexmap 2.9.0",
+ "indexmap 2.10.0",
  "js-sys",
  "once_cell",
  "pretty_assertions",
@@ -148,9 +148,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.18.1"
+version = "3.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
 
 [[package]]
 name = "cast"
@@ -495,9 +495,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
 dependencies = [
  "equivalent",
  "hashbrown 0.15.3",
@@ -916,7 +916,7 @@ version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 dependencies = [
- "indexmap 2.9.0",
+ "indexmap 2.10.0",
  "itoa",
  "memchr",
  "ryu",
@@ -943,7 +943,7 @@ dependencies = [
  "chrono",
  "hex",
  "indexmap 1.9.3",
- "indexmap 2.9.0",
+ "indexmap 2.10.0",
  "schemars",
  "serde",
  "serde_derive",

From 431d4483856b18d1b8885d0b46a60be7f2eb2dee Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 30 Jun 2025 11:44:04 -0400
Subject: [PATCH 129/156] RUST-1406 Convert serde errors to standard error type
 (#562)

---
 src/bson.rs                                  |  30 +++
 src/datetime.rs                              |   2 +-
 src/de.rs                                    |   7 +-
 src/de/error.rs                              | 152 -----------
 src/de/raw.rs                                |   8 +-
 src/de/serde.rs                              | 256 +++++++++----------
 src/document.rs                              |   2 +-
 src/error.rs                                 |  98 ++++++-
 src/extjson/de.rs                            |  49 +---
 src/extjson/models.rs                        |  92 +++----
 src/lib.rs                                   |   2 +-
 src/ser.rs                                   |  17 +-
 src/ser/error.rs                             | 115 ---------
 src/ser/raw.rs                               |   2 +-
 src/ser/raw/document_serializer.rs           | 106 ++++----
 src/ser/serde.rs                             |  29 ++-
 src/spec.rs                                  |  27 ++
 src/tests/modules/ser.rs                     |  14 +-
 src/tests/modules/serializer_deserializer.rs |  12 +-
 src/tests/serde.rs                           |  32 +--
 20 files changed, 419 insertions(+), 633 deletions(-)
 delete mode 100644 src/de/error.rs
 delete mode 100644 src/ser/error.rs

diff --git a/src/bson.rs b/src/bson.rs
index 8f35899d..ab778734 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -911,6 +911,36 @@ impl Bson {
                 .collect(),
         )
     }
+
+    /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error
+    /// reporting.
+    #[cfg(feature = "serde")]
+    pub(crate) fn as_unexpected(&self) -> serde::de::Unexpected {
+        use serde::de::Unexpected;
+        match self {
+            Bson::Array(_) => Unexpected::Seq,
+            Bson::Binary(b) => Unexpected::Bytes(b.bytes.as_slice()),
+            Bson::Boolean(b) => Unexpected::Bool(*b),
+            Bson::DbPointer(_) => Unexpected::Other("dbpointer"),
+            Bson::Document(_) => Unexpected::Map,
+            Bson::Double(f) => Unexpected::Float(*f),
+            Bson::Int32(i) => Unexpected::Signed(*i as i64),
+            Bson::Int64(i) => Unexpected::Signed(*i),
+            Bson::JavaScriptCode(_) => Unexpected::Other("javascript code"),
+            Bson::JavaScriptCodeWithScope(_) => Unexpected::Other("javascript code with scope"),
+            Bson::MaxKey => Unexpected::Other("maxkey"),
+            Bson::MinKey => Unexpected::Other("minkey"),
+            Bson::Null => Unexpected::Unit,
+            Bson::Undefined => Unexpected::Other("undefined"),
+            Bson::ObjectId(_) => Unexpected::Other("objectid"),
+            Bson::RegularExpression(_) => Unexpected::Other("regex"),
+            Bson::String(s) => Unexpected::Str(s.as_str()),
+            Bson::Symbol(_) => Unexpected::Other("symbol"),
+            Bson::Timestamp(_) => Unexpected::Other("timestamp"),
+            Bson::DateTime(_) => Unexpected::Other("datetime"),
+            Bson::Decimal128(_) => Unexpected::Other("decimal128"),
+        }
+    }
 }
 
 /// Value helpers
diff --git a/src/datetime.rs b/src/datetime.rs
index e87e342b..6ed887f1 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -70,7 +70,7 @@ use crate::error::{Error, Result};
 ///     chrono_datetime: chrono::DateTime<chrono::Utc>,
 /// }
 ///
-/// # fn main() -> bson::ser::Result<()> {
+/// # fn main() -> bson::error::Result<()> {
 /// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() };
 /// println!("{:?}", bson::serialize_to_document(&f)?);
 /// # Ok(())
diff --git a/src/de.rs b/src/de.rs
index 76a9bcda..969e6a50 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -21,19 +21,16 @@
 
 //! Deserializer
 
-mod error;
 mod raw;
 mod serde;
 
-pub use self::{
-    error::{Error, Result},
-    serde::Deserializer,
-};
+pub use self::serde::Deserializer;
 
 use std::io::Read;
 
 use crate::{
     bson::{Bson, Document},
+    error::{Error, Result},
     raw::reader_to_vec,
     spec::BinarySubtype,
 };
diff --git a/src/de/error.rs b/src/de/error.rs
deleted file mode 100644
index 1d6eed0d..00000000
--- a/src/de/error.rs
+++ /dev/null
@@ -1,152 +0,0 @@
-use std::{error, fmt, fmt::Display, io, string, sync::Arc};
-
-use serde::de::{self, Unexpected};
-
-use crate::Bson;
-
-/// Possible errors that can arise during decoding.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Error {
-    /// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while deserializing.
-    Io(Arc<io::Error>),
-
-    /// A [`std::string::FromUtf8Error`](https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html) encountered
-    /// while decoding a UTF-8 String from the input data.
-    InvalidUtf8String(string::FromUtf8Error),
-
-    /// While decoding a [`Document`](crate::Document) from bytes, an unexpected or unsupported
-    /// element type was encountered.
-    #[non_exhaustive]
-    UnrecognizedDocumentElementType {
-        /// The key at which an unexpected/unsupported element type was encountered.
-        key: String,
-
-        /// The encountered element type.
-        element_type: u8,
-    },
-
-    /// The end of the BSON input was reached too soon.
-    EndOfStream,
-
-    /// A general error encountered during deserialization.
-    /// See: <https://docs.serde.rs/serde/de/trait.Error.html>
-    #[non_exhaustive]
-    DeserializationError {
-        /// A message describing the error.
-        message: String,
-    },
-
-    #[cfg(feature = "serde_path_to_error")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "serde_path_to_error")))]
-    #[non_exhaustive]
-    WithPath {
-        /// The path to the error.
-        path: serde_path_to_error::Path,
-
-        /// The original error.
-        source: Box<Error>,
-    },
-}
-
-impl Error {
-    pub(crate) fn deserialization(msg: impl ToString) -> Self {
-        Self::DeserializationError {
-            message: msg.to_string(),
-        }
-    }
-
-    #[cfg(feature = "serde_path_to_error")]
-    pub(crate) fn with_path(err: serde_path_to_error::Error<Error>) -> Self {
-        let path = err.path().clone();
-        let source = Box::new(err.into_inner());
-        Self::WithPath { path, source }
-    }
-}
-
-impl From<io::Error> for Error {
-    fn from(err: io::Error) -> Error {
-        Error::Io(Arc::new(err))
-    }
-}
-
-impl From<string::FromUtf8Error> for Error {
-    fn from(err: string::FromUtf8Error) -> Error {
-        Error::InvalidUtf8String(err)
-    }
-}
-
-impl From<crate::error::Error> for Error {
-    fn from(error: crate::error::Error) -> Self {
-        Self::deserialization(error.to_string())
-    }
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::Io(inner) => inner.fmt(fmt),
-            Error::InvalidUtf8String(inner) => inner.fmt(fmt),
-            Error::UnrecognizedDocumentElementType { key, element_type } => write!(
-                fmt,
-                "unrecognized element type for key \"{}\": `{:#x}`",
-                key, element_type
-            ),
-            Error::EndOfStream => fmt.write_str("end of stream"),
-            Error::DeserializationError { message } => message.fmt(fmt),
-            #[cfg(feature = "serde_path_to_error")]
-            Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source),
-        }
-    }
-}
-
-impl error::Error for Error {
-    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
-        match *self {
-            Error::Io(ref inner) => Some(inner.as_ref()),
-            Error::InvalidUtf8String(ref inner) => Some(inner),
-            _ => None,
-        }
-    }
-}
-
-impl de::Error for Error {
-    fn custom<T: Display>(msg: T) -> Error {
-        Error::DeserializationError {
-            message: msg.to_string(),
-        }
-    }
-}
-
-/// Alias for `Result<T, Error>`.
-pub type Result<T> = std::result::Result<T, Error>;
-
-impl Bson {
-    /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error
-    /// reporting.
-    pub(crate) fn as_unexpected(&self) -> Unexpected {
-        match self {
-            Bson::Array(_) => Unexpected::Seq,
-            Bson::Binary(b) => Unexpected::Bytes(b.bytes.as_slice()),
-            Bson::Boolean(b) => Unexpected::Bool(*b),
-            Bson::DbPointer(_) => Unexpected::Other("dbpointer"),
-            Bson::Document(_) => Unexpected::Map,
-            Bson::Double(f) => Unexpected::Float(*f),
-            Bson::Int32(i) => Unexpected::Signed(*i as i64),
-            Bson::Int64(i) => Unexpected::Signed(*i),
-            Bson::JavaScriptCode(_) => Unexpected::Other("javascript code"),
-            Bson::JavaScriptCodeWithScope(_) => Unexpected::Other("javascript code with scope"),
-            Bson::MaxKey => Unexpected::Other("maxkey"),
-            Bson::MinKey => Unexpected::Other("minkey"),
-            Bson::Null => Unexpected::Unit,
-            Bson::Undefined => Unexpected::Other("undefined"),
-            Bson::ObjectId(_) => Unexpected::Other("objectid"),
-            Bson::RegularExpression(_) => Unexpected::Other("regex"),
-            Bson::String(s) => Unexpected::Str(s.as_str()),
-            Bson::Symbol(_) => Unexpected::Other("symbol"),
-            Bson::Timestamp(_) => Unexpected::Other("timestamp"),
-            Bson::DateTime(_) => Unexpected::Other("datetime"),
-            Bson::Decimal128(_) => Unexpected::Other("decimal128"),
-        }
-    }
-}
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 4f809df1..1739cbc1 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -61,7 +61,7 @@ impl<'de> Deserializer<'de> {
     }
 
     fn value(&self) -> Result<RawBsonRef<'de>> {
-        Ok(self.element.value()?)
+        self.element.value()
     }
 
     /// Deserialize the element, using the type of the element along with the
@@ -419,7 +419,7 @@ impl<'de> serde::de::EnumAccess<'de> for DocumentAccess<'de> {
         self.advance()?;
         let elem = match &self.elem {
             Some(e) => e,
-            None => return Err(Error::EndOfStream),
+            None => return Err(Error::end_of_stream()),
         };
         let de: BorrowedStrDeserializer<'_, Error> = BorrowedStrDeserializer::new(elem.key());
         let key = seed.deserialize(de)?;
@@ -1077,7 +1077,7 @@ impl<'de> serde::de::MapAccess<'de> for CodeWithScopeAccess<'de> {
         self.stage = match self.stage {
             CodeWithScopeDeserializationStage::Code => CodeWithScopeDeserializationStage::Scope,
             CodeWithScopeDeserializationStage::Scope => CodeWithScopeDeserializationStage::Done,
-            CodeWithScopeDeserializationStage::Done => return Err(Error::EndOfStream),
+            CodeWithScopeDeserializationStage::Done => return Err(Error::end_of_stream()),
         };
         Ok(value)
     }
@@ -1105,7 +1105,7 @@ impl<'de> serde::de::Deserializer<'de> for &CodeWithScopeAccess<'de> {
                     _ => visitor.visit_map(DocumentAccess::new(scope, self.options.clone())?),
                 }
             }
-            CodeWithScopeDeserializationStage::Done => Err(Error::EndOfStream),
+            CodeWithScopeDeserializationStage::Done => Err(Error::end_of_stream()),
         }
     }
 
diff --git a/src/de/serde.rs b/src/de/serde.rs
index bba415a4..88f3769c 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -11,7 +11,7 @@ use serde::de::{
     DeserializeSeed,
     Deserializer as _,
     EnumAccess,
-    Error,
+    Error as _,
     MapAccess,
     SeqAccess,
     Unexpected,
@@ -24,6 +24,7 @@ use crate::{
     bson::{Bson, DbPointer, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
     document::{Document, IntoIter},
+    error::{Error, Result},
     oid::ObjectId,
     raw::{RawBsonRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     serde_helpers::HUMAN_READABLE_NEWTYPE,
@@ -71,7 +72,7 @@ impl<'de> Visitor<'de> for ObjectIdVisitor {
     }
 
     #[inline]
-    fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
+    fn visit_map<V>(self, mut visitor: V) -> std::result::Result<Self::Value, V::Error>
     where
         V: MapAccess<'de>,
     {
@@ -82,7 +83,7 @@ impl<'de> Visitor<'de> for ObjectIdVisitor {
                     "expected map containing extended-JSON formatted ObjectId, instead found {}",
                     bson
                 );
-                Err(de::Error::custom(err))
+                Err(serde::de::Error::custom(err))
             }
         }
     }
@@ -103,7 +104,7 @@ impl<'de> Deserialize<'de> for ObjectId {
 
 impl<'de> Deserialize<'de> for Document {
     /// Deserialize this value given this [`Deserializer`].
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
@@ -112,7 +113,7 @@ impl<'de> Deserialize<'de> for Document {
                 Ok(doc)
             } else {
                 let err = format!("expected document, found extended JSON data type: {}", bson);
-                Err(de::Error::invalid_type(Unexpected::Map, &&err[..]))
+                Err(serde::de::Error::invalid_type(Unexpected::Map, &&err[..]))
             }
         })
     }
@@ -120,7 +121,7 @@ impl<'de> Deserialize<'de> for Document {
 
 impl<'de> Deserialize<'de> for Bson {
     #[inline]
-    fn deserialize<D>(deserializer: D) -> Result<Bson, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Bson, D::Error>
     where
         D: de::Deserializer<'de>,
     {
@@ -136,102 +137,102 @@ impl<'de> Visitor<'de> for BsonVisitor {
     }
 
     #[inline]
-    fn visit_bool<E>(self, value: bool) -> Result<Bson, E>
+    fn visit_bool<E>(self, value: bool) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Boolean(value))
     }
 
     #[inline]
-    fn visit_i8<E>(self, value: i8) -> Result<Bson, E>
+    fn visit_i8<E>(self, value: i8) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Int32(value as i32))
     }
 
     #[inline]
-    fn visit_u8<E>(self, value: u8) -> Result<Bson, E>
+    fn visit_u8<E>(self, value: u8) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         convert_unsigned_to_signed(value as u64)
     }
 
     #[inline]
-    fn visit_i16<E>(self, value: i16) -> Result<Bson, E>
+    fn visit_i16<E>(self, value: i16) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Int32(value as i32))
     }
 
     #[inline]
-    fn visit_u16<E>(self, value: u16) -> Result<Bson, E>
+    fn visit_u16<E>(self, value: u16) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         convert_unsigned_to_signed(value as u64)
     }
 
     #[inline]
-    fn visit_i32<E>(self, value: i32) -> Result<Bson, E>
+    fn visit_i32<E>(self, value: i32) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Int32(value))
     }
 
     #[inline]
-    fn visit_u32<E>(self, value: u32) -> Result<Bson, E>
+    fn visit_u32<E>(self, value: u32) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         convert_unsigned_to_signed(value as u64)
     }
 
     #[inline]
-    fn visit_i64<E>(self, value: i64) -> Result<Bson, E>
+    fn visit_i64<E>(self, value: i64) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Int64(value))
     }
 
     #[inline]
-    fn visit_u64<E>(self, value: u64) -> Result<Bson, E>
+    fn visit_u64<E>(self, value: u64) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         convert_unsigned_to_signed(value)
     }
 
     #[inline]
-    fn visit_f64<E>(self, value: f64) -> Result<Bson, E> {
+    fn visit_f64<E>(self, value: f64) -> std::result::Result<Bson, E> {
         Ok(Bson::Double(value))
     }
 
     #[inline]
-    fn visit_str<E>(self, value: &str) -> Result<Bson, E>
+    fn visit_str<E>(self, value: &str) -> std::result::Result<Bson, E>
     where
-        E: de::Error,
+        E: serde::de::Error,
     {
         self.visit_string(String::from(value))
     }
 
     #[inline]
-    fn visit_string<E>(self, value: String) -> Result<Bson, E> {
+    fn visit_string<E>(self, value: String) -> std::result::Result<Bson, E> {
         Ok(Bson::String(value))
     }
 
     #[inline]
-    fn visit_none<E>(self) -> Result<Bson, E> {
+    fn visit_none<E>(self) -> std::result::Result<Bson, E> {
         Ok(Bson::Null)
     }
 
     #[inline]
-    fn visit_some<D>(self, deserializer: D) -> Result<Bson, D::Error>
+    fn visit_some<D>(self, deserializer: D) -> std::result::Result<Bson, D::Error>
     where
         D: de::Deserializer<'de>,
     {
@@ -239,12 +240,12 @@ impl<'de> Visitor<'de> for BsonVisitor {
     }
 
     #[inline]
-    fn visit_unit<E>(self) -> Result<Bson, E> {
+    fn visit_unit<E>(self) -> std::result::Result<Bson, E> {
         Ok(Bson::Null)
     }
 
     #[inline]
-    fn visit_seq<V>(self, mut visitor: V) -> Result<Bson, V::Error>
+    fn visit_seq<V>(self, mut visitor: V) -> std::result::Result<Bson, V::Error>
     where
         V: SeqAccess<'de>,
     {
@@ -257,7 +258,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
         Ok(Bson::Array(values))
     }
 
-    fn visit_map<V>(self, mut visitor: V) -> Result<Bson, V::Error>
+    fn visit_map<V>(self, mut visitor: V) -> std::result::Result<Bson, V::Error>
     where
         V: MapAccess<'de>,
     {
@@ -274,7 +275,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                     }
 
                     impl<'a, 'de: 'a> Deserialize<'de> for BytesOrHex<'a> {
-                        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+                        fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
                         where
                             D: serde::Deserializer<'de>,
                         {
@@ -287,9 +288,12 @@ impl<'de> Visitor<'de> for BsonVisitor {
                                     write!(formatter, "hexstring or byte array")
                                 }
 
-                                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+                                fn visit_str<E>(
+                                    self,
+                                    v: &str,
+                                ) -> std::result::Result<Self::Value, E>
                                 where
-                                    E: Error,
+                                    E: serde::de::Error,
                                 {
                                     Ok(BytesOrHex::Hex(Cow::Owned(v.to_string())))
                                 }
@@ -297,18 +301,23 @@ impl<'de> Visitor<'de> for BsonVisitor {
                                 fn visit_borrowed_str<E>(
                                     self,
                                     v: &'de str,
-                                ) -> Result<Self::Value, E>
+                                ) -> std::result::Result<Self::Value, E>
                                 where
-                                    E: Error,
+                                    E: serde::de::Error,
                                 {
                                     Ok(BytesOrHex::Hex(Cow::Borrowed(v)))
                                 }
 
-                                fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+                                fn visit_bytes<E>(
+                                    self,
+                                    v: &[u8],
+                                ) -> std::result::Result<Self::Value, E>
                                 where
-                                    E: Error,
+                                    E: serde::de::Error,
                                 {
-                                    Ok(BytesOrHex::Bytes(v.try_into().map_err(Error::custom)?))
+                                    Ok(BytesOrHex::Bytes(
+                                        v.try_into().map_err(serde::de::Error::custom)?,
+                                    ))
                                 }
                             }
 
@@ -377,7 +386,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                     return Ok(Bson::Binary(
                         extjson::models::Binary { body: v }
                             .parse()
-                            .map_err(Error::custom)?,
+                            .map_err(serde::de::Error::custom)?,
                     ));
                 }
 
@@ -385,7 +394,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                     let v: String = visitor.next_value()?;
                     let uuid = extjson::models::Uuid { value: v }
                         .parse()
-                        .map_err(Error::custom)?;
+                        .map_err(serde::de::Error::custom)?;
                     return Ok(Bson::Binary(uuid));
                 }
 
@@ -399,7 +408,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                                 scope,
                             }));
                         } else {
-                            return Err(Error::unknown_field(key.as_str(), &["$scope"]));
+                            return Err(serde::de::Error::unknown_field(key.as_str(), &["$scope"]));
                         }
                     } else {
                         return Ok(Bson::JavaScriptCode(code));
@@ -416,10 +425,10 @@ impl<'de> Visitor<'de> for BsonVisitor {
                                 scope,
                             }));
                         } else {
-                            return Err(Error::unknown_field(key.as_str(), &["$code"]));
+                            return Err(serde::de::Error::unknown_field(key.as_str(), &["$code"]));
                         }
                     } else {
-                        return Err(Error::missing_field("$code"));
+                        return Err(serde::de::Error::missing_field("$code"));
                     }
                 }
 
@@ -439,7 +448,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                 "$dbPointer" => {
                     let dbp = visitor.next_value::<extjson::models::DbPointerBody>()?;
                     return Ok(Bson::DbPointer(DbPointer {
-                        id: dbp.id.parse().map_err(Error::custom)?,
+                        id: dbp.id.parse().map_err(serde::de::Error::custom)?,
                         namespace: dbp.ref_ns,
                     }));
                 }
@@ -449,7 +458,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
                     return Ok(Bson::DateTime(
                         extjson::models::DateTime { body: dt }
                             .parse()
-                            .map_err(Error::custom)?,
+                            .map_err(serde::de::Error::custom)?,
                     ));
                 }
 
@@ -457,21 +466,21 @@ impl<'de> Visitor<'de> for BsonVisitor {
                     let i = visitor.next_value::<u8>()?;
                     return extjson::models::MaxKey { value: i }
                         .parse()
-                        .map_err(Error::custom);
+                        .map_err(serde::de::Error::custom);
                 }
 
                 "$minKey" => {
                     let i = visitor.next_value::<u8>()?;
                     return extjson::models::MinKey { value: i }
                         .parse()
-                        .map_err(Error::custom);
+                        .map_err(serde::de::Error::custom);
                 }
 
                 "$undefined" => {
                     let b = visitor.next_value::<bool>()?;
                     return extjson::models::Undefined { value: b }
                         .parse()
-                        .map_err(Error::custom);
+                        .map_err(serde::de::Error::custom);
                 }
 
                 "$numberDecimal" => {
@@ -504,9 +513,9 @@ impl<'de> Visitor<'de> for BsonVisitor {
     }
 
     #[inline]
-    fn visit_bytes<E>(self, v: &[u8]) -> Result<Bson, E>
+    fn visit_bytes<E>(self, v: &[u8]) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Binary(Binary {
             subtype: BinarySubtype::Generic,
@@ -515,9 +524,9 @@ impl<'de> Visitor<'de> for BsonVisitor {
     }
 
     #[inline]
-    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Bson, E>
+    fn visit_byte_buf<E>(self, v: Vec<u8>) -> std::result::Result<Bson, E>
     where
-        E: Error,
+        E: serde::de::Error,
     {
         Ok(Bson::Binary(Binary {
             subtype: BinarySubtype::Generic,
@@ -526,7 +535,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
     }
 
     #[inline]
-    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    fn visit_newtype_struct<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
@@ -539,35 +548,37 @@ enum BsonInteger {
     Int64(i64),
 }
 
-fn _convert_unsigned<E: Error>(value: u64) -> Result<BsonInteger, E> {
+fn convert_unsigned<E: serde::de::Error>(value: u64) -> std::result::Result<BsonInteger, E> {
     if let Ok(int32) = i32::try_from(value) {
         Ok(BsonInteger::Int32(int32))
     } else if let Ok(int64) = i64::try_from(value) {
         Ok(BsonInteger::Int64(int64))
     } else {
-        Err(Error::custom(format!(
+        Err(serde::de::Error::custom(format!(
             "cannot represent {} as a signed number",
             value
         )))
     }
 }
 
-fn convert_unsigned_to_signed<E>(value: u64) -> Result<Bson, E>
+fn convert_unsigned_to_signed<E>(value: u64) -> std::result::Result<Bson, E>
 where
-    E: Error,
+    E: serde::de::Error,
 {
-    let bi = _convert_unsigned(value)?;
+    let bi = convert_unsigned(value)?;
     match bi {
         BsonInteger::Int32(i) => Ok(Bson::Int32(i)),
         BsonInteger::Int64(i) => Ok(Bson::Int64(i)),
     }
 }
 
-pub(crate) fn convert_unsigned_to_signed_raw<'a, E>(value: u64) -> Result<RawBsonRef<'a>, E>
+pub(crate) fn convert_unsigned_to_signed_raw<'a, E>(
+    value: u64,
+) -> std::result::Result<RawBsonRef<'a>, E>
 where
-    E: Error,
+    E: serde::de::Error,
 {
-    let bi = _convert_unsigned(value)?;
+    let bi = convert_unsigned(value)?;
     match bi {
         BsonInteger::Int32(i) => Ok(RawBsonRef::Int32(i)),
         BsonInteger::Int64(i) => Ok(RawBsonRef::Int64(i)),
@@ -603,17 +614,13 @@ impl Deserializer {
         }
     }
 
-    fn deserialize_next<'de, V>(
-        mut self,
-        visitor: V,
-        hint: DeserializerHint,
-    ) -> Result<V::Value, crate::de::Error>
+    fn deserialize_next<'de, V>(mut self, visitor: V, hint: DeserializerHint) -> Result<V::Value>
     where
         V: serde::de::Visitor<'de>,
     {
         let value = match self.value.take() {
             Some(value) => value,
-            None => return Err(crate::de::Error::EndOfStream),
+            None => return Err(Error::end_of_stream()),
         };
 
         let is_rawbson = matches!(hint, DeserializerHint::RawBson);
@@ -621,7 +628,7 @@ impl Deserializer {
         if let DeserializerHint::BinarySubtype(expected_subtype) = hint {
             if let Bson::Binary(ref binary) = value {
                 if binary.subtype != expected_subtype {
-                    return Err(Error::custom(format!(
+                    return Err(serde::de::Error::custom(format!(
                         "expected Binary with subtype {:?}, instead got subtype {:?}",
                         expected_subtype, binary.subtype
                     )));
@@ -695,7 +702,7 @@ macro_rules! forward_to_deserialize {
 }
 
 impl<'de> de::Deserializer<'de> for Deserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
 
     #[allow(deprecated)]
     fn is_human_readable(&self) -> bool {
@@ -703,7 +710,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
     }
 
     #[inline]
-    fn deserialize_any<V>(self, visitor: V) -> crate::de::Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
@@ -711,7 +718,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
     }
 
     #[inline]
-    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    fn deserialize_bytes<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
     {
@@ -724,14 +731,14 @@ impl<'de> de::Deserializer<'de> for Deserializer {
     }
 
     #[inline]
-    fn deserialize_option<V>(self, visitor: V) -> crate::de::Result<V::Value>
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
         match self.value {
             Some(Bson::Null) => visitor.visit_none(),
             Some(_) => visitor.visit_some(self),
-            None => Err(crate::de::Error::EndOfStream),
+            None => Err(Error::end_of_stream()),
         }
     }
 
@@ -741,7 +748,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
         _name: &str,
         _variants: &'static [&'static str],
         visitor: V,
-    ) -> crate::de::Result<V::Value>
+    ) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
@@ -757,13 +764,10 @@ impl<'de> de::Deserializer<'de> for Deserializer {
                 });
             }
             Some(v) => {
-                return Err(crate::de::Error::invalid_type(
-                    v.as_unexpected(),
-                    &"expected an enum",
-                ));
+                return Err(Error::invalid_type(v.as_unexpected(), &"expected an enum"));
             }
             None => {
-                return Err(crate::de::Error::EndOfStream);
+                return Err(Error::end_of_stream());
             }
         };
 
@@ -772,7 +776,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
         let (variant, value) = match iter.next() {
             Some(v) => v,
             None => {
-                return Err(crate::de::Error::invalid_value(
+                return Err(Error::invalid_value(
                     Unexpected::Other("empty document"),
                     &"variant name",
                 ))
@@ -781,7 +785,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
 
         // enums are encoded in json as maps with a single key:value pair
         match iter.next() {
-            Some((k, _)) => Err(crate::de::Error::invalid_value(
+            Some((k, _)) => Err(Error::invalid_value(
                 Unexpected::Map,
                 &format!("expected map with a single key, got extra key \"{}\"", k).as_str(),
             )),
@@ -796,11 +800,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
     }
 
     #[inline]
-    fn deserialize_newtype_struct<V>(
-        mut self,
-        name: &'static str,
-        visitor: V,
-    ) -> crate::de::Result<V::Value>
+    fn deserialize_newtype_struct<V>(mut self, name: &'static str, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
@@ -873,9 +873,9 @@ struct EnumDeserializer {
 }
 
 impl<'de> EnumAccess<'de> for EnumDeserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
     type Variant = VariantDeserializer;
-    fn variant_seed<V>(self, seed: V) -> crate::de::Result<(V::Value, Self::Variant)>
+    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
     where
         V: DeserializeSeed<'de>,
     {
@@ -891,9 +891,9 @@ struct VariantDeserializer {
 }
 
 impl<'de> VariantAccess<'de> for VariantDeserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
 
-    fn unit_variant(mut self) -> crate::de::Result<()> {
+    fn unit_variant(mut self) -> Result<()> {
         match self.val.take() {
             None => Ok(()),
             Some(val) => {
@@ -902,22 +902,22 @@ impl<'de> VariantAccess<'de> for VariantDeserializer {
         }
     }
 
-    fn newtype_variant_seed<T>(mut self, seed: T) -> crate::de::Result<T::Value>
+    fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value>
     where
         T: DeserializeSeed<'de>,
     {
         let dec = Deserializer::new_with_options(
-            self.val.take().ok_or(crate::de::Error::EndOfStream)?,
+            self.val.take().ok_or_else(Error::end_of_stream)?,
             self.options,
         );
         seed.deserialize(dec)
     }
 
-    fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> crate::de::Result<V::Value>
+    fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
-        match self.val.take().ok_or(crate::de::Error::EndOfStream)? {
+        match self.val.take().ok_or_else(Error::end_of_stream)? {
             Bson::Array(fields) => {
                 let de = SeqDeserializer {
                     len: fields.len(),
@@ -926,22 +926,18 @@ impl<'de> VariantAccess<'de> for VariantDeserializer {
                 };
                 de.deserialize_any(visitor)
             }
-            other => Err(crate::de::Error::invalid_type(
+            other => Err(Error::invalid_type(
                 other.as_unexpected(),
                 &"expected a tuple",
             )),
         }
     }
 
-    fn struct_variant<V>(
-        mut self,
-        _fields: &'static [&'static str],
-        visitor: V,
-    ) -> crate::de::Result<V::Value>
+    fn struct_variant<V>(mut self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
-        match self.val.take().ok_or(crate::de::Error::EndOfStream)? {
+        match self.val.take().ok_or_else(Error::end_of_stream)? {
             Bson::Document(fields) => {
                 let de = MapDeserializer {
                     len: fields.len(),
@@ -951,7 +947,7 @@ impl<'de> VariantAccess<'de> for VariantDeserializer {
                 };
                 de.deserialize_any(visitor)
             }
-            ref other => Err(crate::de::Error::invalid_type(
+            ref other => Err(Error::invalid_type(
                 other.as_unexpected(),
                 &"expected a struct",
             )),
@@ -966,10 +962,10 @@ struct SeqDeserializer {
 }
 
 impl<'de> de::Deserializer<'de> for SeqDeserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
 
     #[inline]
-    fn deserialize_any<V>(self, visitor: V) -> crate::de::Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
@@ -1013,9 +1009,9 @@ impl<'de> de::Deserializer<'de> for SeqDeserializer {
 }
 
 impl<'de> SeqAccess<'de> for SeqDeserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
 
-    fn next_element_seed<T>(&mut self, seed: T) -> crate::de::Result<Option<T::Value>>
+    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
     where
         T: DeserializeSeed<'de>,
     {
@@ -1057,9 +1053,9 @@ impl MapDeserializer {
 }
 
 impl<'de> MapAccess<'de> for MapDeserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
 
-    fn next_key_seed<K>(&mut self, seed: K) -> crate::de::Result<Option<K::Value>>
+    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
     where
         K: DeserializeSeed<'de>,
     {
@@ -1078,11 +1074,11 @@ impl<'de> MapAccess<'de> for MapDeserializer {
         }
     }
 
-    fn next_value_seed<V>(&mut self, seed: V) -> crate::de::Result<V::Value>
+    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
     where
         V: DeserializeSeed<'de>,
     {
-        let value = self.value.take().ok_or(crate::de::Error::EndOfStream)?;
+        let value = self.value.take().ok_or_else(Error::end_of_stream)?;
         let de = Deserializer::new_with_options(value, self.options.clone());
         seed.deserialize(de)
     }
@@ -1093,10 +1089,10 @@ impl<'de> MapAccess<'de> for MapDeserializer {
 }
 
 impl<'de> de::Deserializer<'de> for MapDeserializer {
-    type Error = crate::de::Error;
+    type Error = Error;
 
     #[inline]
-    fn deserialize_any<V>(self, visitor: V) -> crate::de::Result<V::Value>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'de>,
     {
@@ -1136,49 +1132,51 @@ impl<'de> de::Deserializer<'de> for MapDeserializer {
 }
 
 impl<'de> Deserialize<'de> for Timestamp {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::Timestamp(timestamp) => Ok(timestamp),
-            _ => Err(D::Error::custom("expecting Timestamp")),
+            _ => Err(serde::de::Error::custom("expecting Timestamp")),
         }
     }
 }
 
 impl<'de> Deserialize<'de> for Regex {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::RegularExpression(regex) => Ok(regex),
-            _ => Err(D::Error::custom("expecting Regex")),
+            _ => Err(serde::de::Error::custom("expecting Regex")),
         }
     }
 }
 
 impl<'de> Deserialize<'de> for JavaScriptCodeWithScope {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::JavaScriptCodeWithScope(code_with_scope) => Ok(code_with_scope),
-            _ => Err(D::Error::custom("expecting JavaScriptCodeWithScope")),
+            _ => Err(serde::de::Error::custom(
+                "expecting JavaScriptCodeWithScope",
+            )),
         }
     }
 }
 
 impl<'de> Deserialize<'de> for Binary {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::Binary(binary) => Ok(binary),
-            d => Err(D::Error::custom(format!(
+            d => Err(serde::de::Error::custom(format!(
                 "expecting Binary but got {:?} instead",
                 d
             ))),
@@ -1187,13 +1185,13 @@ impl<'de> Deserialize<'de> for Binary {
 }
 
 impl<'de> Deserialize<'de> for Decimal128 {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::Decimal128(d128) => Ok(d128),
-            o => Err(D::Error::custom(format!(
+            o => Err(serde::de::Error::custom(format!(
                 "expecting Decimal128, got {:?}",
                 o
             ))),
@@ -1202,25 +1200,25 @@ impl<'de> Deserialize<'de> for Decimal128 {
 }
 
 impl<'de> Deserialize<'de> for DateTime {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::DateTime(dt) => Ok(dt),
-            _ => Err(D::Error::custom("expecting DateTime")),
+            _ => Err(serde::de::Error::custom("expecting DateTime")),
         }
     }
 }
 
 impl<'de> Deserialize<'de> for DbPointer {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
     where
         D: de::Deserializer<'de>,
     {
         match Bson::deserialize(deserializer)? {
             Bson::DbPointer(db_pointer) => Ok(db_pointer),
-            _ => Err(D::Error::custom("expecting DbPointer")),
+            _ => Err(serde::de::Error::custom("expecting DbPointer")),
         }
     }
 }
diff --git a/src/document.rs b/src/document.rs
index 5af4026b..6069f8d7 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -685,7 +685,7 @@ impl Document {
     /// library.
     ///
     /// ```
-    /// # fn main() -> bson::ser::Result<()> {
+    /// # fn main() -> bson::error::Result<()> {
     /// use bson::doc;
     ///
     /// let mut v: Vec<u8> = Vec::new();
diff --git a/src/error.rs b/src/error.rs
index d3ed5740..7b9d5918 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -27,6 +27,10 @@ pub struct Error {
 
     /// The array index associated with the error, if any.
     pub index: Option<usize>,
+
+    /// The path to a deserialization error, if any.
+    #[cfg(feature = "serde_path_to_error")]
+    pub path: Option<serde_path_to_error::Path>,
 }
 
 impl std::fmt::Display for Error {
@@ -43,6 +47,11 @@ impl std::fmt::Display for Error {
         if let Some(ref message) = self.message {
             write!(f, ". Message: {}", message)?;
         }
+        #[cfg(feature = "serde_path_to_error")]
+        if let Some(ref path) = self.path {
+            write!(f, ". Path: {}", path)?;
+        }
+
         write!(f, ".")
     }
 }
@@ -69,6 +78,18 @@ pub enum ErrorKind {
         kind: Decimal128ErrorKind,
     },
 
+    /// A general error occurred during deserialization. This variant is constructed in the
+    /// [`serde::de::Error`] implementation for the [`Error`](struct@Error) type.
+    #[cfg(feature = "serde")]
+    #[error("A deserialization-related error occurred")]
+    #[non_exhaustive]
+    Deserialization {},
+
+    /// The end of the BSON input was reached too soon.
+    #[error("End of stream")]
+    #[non_exhaustive]
+    EndOfStream {},
+
     /// Malformed BSON bytes were encountered.
     #[error("Malformed BSON bytes")]
     #[non_exhaustive]
@@ -82,6 +103,21 @@ pub enum ErrorKind {
         kind: ObjectIdErrorKind,
     },
 
+    /// A general error occurred during serialization. This variant is constructed in the
+    /// [`serde::ser::Error`] implementation for the [`Error`](struct@Error) type.
+    #[cfg(feature = "serde")]
+    #[error("A serialization error occurred")]
+    #[non_exhaustive]
+    Serialization {},
+
+    /// An unsigned integer could not fit into a BSON integer type.
+    #[error("Unsigned integer {n} cannot fit into BSON")]
+    #[non_exhaustive]
+    TooLargeUnsignedInteger {
+        /// The too-large unsigned integer.
+        n: u64,
+    },
+
     /// Invalid UTF-8 bytes were encountered.
     #[error("Invalid UTF-8")]
     #[non_exhaustive]
@@ -103,16 +139,10 @@ pub enum ErrorKind {
         kind: ValueAccessErrorKind,
     },
 
-    /// A [`std::io::Error`] occurred.
+    /// An IO error occurred.
     #[error("An IO error occurred")]
     #[non_exhaustive]
     Io {},
-
-    /// A wrapped deserialization error.
-    /// TODO RUST-1406: collapse this
-    #[cfg(feature = "serde")]
-    #[error("Deserialization error: {0}")]
-    DeError(crate::de::Error),
 }
 
 impl From<ErrorKind> for Error {
@@ -122,6 +152,8 @@ impl From<ErrorKind> for Error {
             key: None,
             index: None,
             message: None,
+            #[cfg(feature = "serde_path_to_error")]
+            path: None,
         }
     }
 }
@@ -133,9 +165,22 @@ impl From<std::io::Error> for Error {
 }
 
 #[cfg(feature = "serde")]
-impl From<crate::de::Error> for Error {
-    fn from(value: crate::de::Error) -> Self {
-        ErrorKind::DeError(value).into()
+impl serde::de::Error for Error {
+    fn custom<T>(message: T) -> Self
+    where
+        T: std::fmt::Display,
+    {
+        Self::deserialization(message)
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::ser::Error for Error {
+    fn custom<T>(message: T) -> Self
+    where
+        T: std::fmt::Display,
+    {
+        Self::serialization(message)
     }
 }
 
@@ -155,6 +200,14 @@ impl Error {
         self
     }
 
+    #[cfg(feature = "serde_path_to_error")]
+    pub(crate) fn with_path(error: serde_path_to_error::Error<Self>) -> Self {
+        let path = error.path().clone();
+        let mut error = error.into_inner();
+        error.path = Some(path);
+        error
+    }
+
     pub(crate) fn binary(message: impl ToString) -> Self {
         Self::from(ErrorKind::Binary {}).with_message(message)
     }
@@ -163,6 +216,26 @@ impl Error {
         Self::from(ErrorKind::DateTime {}).with_message(message)
     }
 
+    #[cfg(feature = "serde")]
+    pub(crate) fn serialization(message: impl ToString) -> Self {
+        Self::from(ErrorKind::Serialization {}).with_message(message)
+    }
+
+    #[cfg(feature = "serde")]
+    pub(crate) fn invalid_key_type(key: impl AsRef<str>) -> Self {
+        Self::serialization(format!("invalid document key type: {}", key.as_ref()))
+    }
+
+    #[cfg(feature = "serde")]
+    pub(crate) fn deserialization(message: impl ToString) -> Self {
+        Self::from(ErrorKind::Deserialization {}).with_message(message)
+    }
+
+    #[cfg(feature = "serde")]
+    pub(crate) fn end_of_stream() -> Self {
+        ErrorKind::EndOfStream {}.into()
+    }
+
     pub(crate) fn malformed_bytes(message: impl ToString) -> Self {
         Self::from(ErrorKind::MalformedBytes {}).with_message(message)
     }
@@ -171,4 +244,9 @@ impl Error {
     pub(crate) fn is_malformed_bytes(&self) -> bool {
         matches!(self.kind, ErrorKind::MalformedBytes { .. },)
     }
+
+    #[cfg(feature = "serde")]
+    pub(crate) fn too_large_integer(n: u64) -> Self {
+        Self::from(ErrorKind::TooLargeUnsignedInteger { n })
+    }
 }
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
index f147ad43..df5bbd4a 100644
--- a/src/extjson/de.rs
+++ b/src/extjson/de.rs
@@ -25,52 +25,19 @@ use std::convert::{TryFrom, TryInto};
 
 use serde::de::{Error as _, Unexpected};
 
-use crate::{extjson::models, Bson, Document};
-
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-/// Error cases that can occur during deserialization from [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-pub enum Error {
-    /// Errors that can occur during OID construction and generation from the input data.
-    InvalidObjectId(crate::error::Error),
-
-    /// A general error encountered during deserialization.
-    /// See: <https://docs.serde.rs/serde/de/trait.Error.html>
-    DeserializationError { message: String },
-}
-
-impl std::fmt::Display for Error {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
-        match *self {
-            Self::InvalidObjectId(ref err) => err.fmt(fmt),
-            Self::DeserializationError { ref message } => message.fmt(fmt),
-        }
-    }
-}
-
-impl std::error::Error for Error {}
-
-impl serde::de::Error for Error {
-    fn custom<T>(msg: T) -> Self
-    where
-        T: std::fmt::Display,
-    {
-        Self::DeserializationError {
-            message: format!("{}", msg),
-        }
-    }
-}
+use crate::{
+    error::{Error, Result},
+    extjson::models,
+    Bson,
+    Document,
+};
 
 impl From<serde_json::Error> for Error {
-    fn from(err: serde_json::Error) -> Self {
-        Self::DeserializationError {
-            message: err.to_string(),
-        }
+    fn from(error: serde_json::Error) -> Self {
+        Self::deserialization(error)
     }
 }
 
-pub type Result<T> = std::result::Result<T, Error>;
-
 /// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
 impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
     type Error = Error;
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index caccd12f..31c137c7 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -1,13 +1,20 @@
 //! A module defining serde models for the extended JSON representations of the various BSON types.
 
 use serde::{
-    de::{Error, Unexpected},
+    de::{Error as _, Unexpected},
     Deserialize,
     Serialize,
 };
 use std::borrow::Cow;
 
-use crate::{base64, extjson, oid, raw::serde::CowStr, spec::BinarySubtype, Bson};
+use crate::{
+    base64,
+    error::{Error, Result},
+    oid,
+    raw::serde::CowStr,
+    spec::BinarySubtype,
+    Bson,
+};
 
 #[derive(Deserialize)]
 #[serde(deny_unknown_fields)]
@@ -17,14 +24,10 @@ pub(crate) struct Int32 {
 }
 
 impl Int32 {
-    pub(crate) fn parse(self) -> extjson::de::Result<i32> {
-        let i: i32 = self.value.parse().map_err(|_| {
-            extjson::de::Error::invalid_value(
-                Unexpected::Str(self.value.as_str()),
-                &"i32 as a string",
-            )
-        })?;
-        Ok(i)
+    pub(crate) fn parse(self) -> Result<i32> {
+        self.value.parse().map_err(|_| {
+            Error::invalid_value(Unexpected::Str(self.value.as_str()), &"i32 as a string")
+        })
     }
 }
 
@@ -36,14 +39,10 @@ pub(crate) struct Int64 {
 }
 
 impl Int64 {
-    pub(crate) fn parse(self) -> extjson::de::Result<i64> {
-        let i: i64 = self.value.parse().map_err(|_| {
-            extjson::de::Error::invalid_value(
-                Unexpected::Str(self.value.as_str()),
-                &"i64 as a string",
-            )
-        })?;
-        Ok(i)
+    pub(crate) fn parse(self) -> Result<i64> {
+        self.value.parse().map_err(|_| {
+            Error::invalid_value(Unexpected::Str(self.value.as_str()), &"i64 as a string")
+        })
     }
 }
 
@@ -55,20 +54,14 @@ pub(crate) struct Double {
 }
 
 impl Double {
-    pub(crate) fn parse(self) -> extjson::de::Result<f64> {
+    pub(crate) fn parse(self) -> Result<f64> {
         match self.value.as_str() {
             "Infinity" => Ok(f64::INFINITY),
             "-Infinity" => Ok(f64::NEG_INFINITY),
             "NaN" => Ok(f64::NAN),
-            other => {
-                let d: f64 = other.parse().map_err(|_| {
-                    extjson::de::Error::invalid_value(
-                        Unexpected::Str(other),
-                        &"bson double as string",
-                    )
-                })?;
-                Ok(d)
-            }
+            other => other.parse().map_err(|_| {
+                Error::invalid_value(Unexpected::Str(other), &"bson double as string")
+            }),
         }
     }
 }
@@ -81,12 +74,9 @@ pub(crate) struct Decimal128 {
 }
 
 impl Decimal128 {
-    pub(crate) fn parse(self) -> extjson::de::Result<crate::Decimal128> {
+    pub(crate) fn parse(self) -> Result<crate::Decimal128> {
         self.value.parse().map_err(|_| {
-            extjson::de::Error::invalid_value(
-                Unexpected::Str(&self.value),
-                &"bson decimal128 as string",
-            )
+            Error::invalid_value(Unexpected::Str(&self.value), &"bson decimal128 as string")
         })
     }
 }
@@ -99,10 +89,8 @@ pub(crate) struct ObjectId {
 }
 
 impl ObjectId {
-    pub(crate) fn parse(self) -> extjson::de::Result<oid::ObjectId> {
-        let oid = oid::ObjectId::parse_str(self.oid.as_str())
-            .map_err(extjson::de::Error::InvalidObjectId)?;
-        Ok(oid)
+    pub(crate) fn parse(self) -> Result<oid::ObjectId> {
+        oid::ObjectId::parse_str(self.oid.as_str())
     }
 }
 
@@ -156,16 +144,16 @@ pub(crate) struct BinaryBody {
 }
 
 impl Binary {
-    pub(crate) fn parse(self) -> extjson::de::Result<crate::Binary> {
+    pub(crate) fn parse(self) -> Result<crate::Binary> {
         let bytes = base64::decode(self.body.base64.as_str()).map_err(|_| {
-            extjson::de::Error::invalid_value(
+            Error::invalid_value(
                 Unexpected::Str(self.body.base64.as_str()),
                 &"base64 encoded bytes",
             )
         })?;
 
         let subtype = hex::decode(self.body.subtype.as_str()).map_err(|_| {
-            extjson::de::Error::invalid_value(
+            Error::invalid_value(
                 Unexpected::Str(self.body.subtype.as_str()),
                 &"hexadecimal number as a string",
             )
@@ -177,7 +165,7 @@ impl Binary {
                 subtype: subtype[0].into(),
             })
         } else {
-            Err(extjson::de::Error::invalid_value(
+            Err(Error::invalid_value(
                 Unexpected::Bytes(subtype.as_slice()),
                 &"one byte subtype",
             ))
@@ -193,9 +181,9 @@ pub(crate) struct Uuid {
 }
 
 impl Uuid {
-    pub(crate) fn parse(self) -> extjson::de::Result<crate::Binary> {
+    pub(crate) fn parse(self) -> Result<crate::Binary> {
         let uuid = uuid::Uuid::parse_str(&self.value).map_err(|_| {
-            extjson::de::Error::invalid_value(
+            Error::invalid_value(
                 Unexpected::Str(&self.value),
                 &"$uuid value does not follow RFC 4122 format regarding length and hyphens",
             )
@@ -269,7 +257,7 @@ impl DateTimeBody {
 }
 
 impl DateTime {
-    pub(crate) fn parse(self) -> extjson::de::Result<crate::DateTime> {
+    pub(crate) fn parse(self) -> Result<crate::DateTime> {
         match self.body {
             DateTimeBody::Canonical(date) => {
                 let date = date.parse()?;
@@ -277,7 +265,7 @@ impl DateTime {
             }
             DateTimeBody::Relaxed(date) => {
                 let datetime = crate::DateTime::parse_rfc3339_str(date.as_str()).map_err(|_| {
-                    extjson::de::Error::invalid_value(
+                    Error::invalid_value(
                         Unexpected::Str(date.as_str()),
                         &"rfc3339 formatted utc datetime",
                     )
@@ -297,11 +285,11 @@ pub(crate) struct MinKey {
 }
 
 impl MinKey {
-    pub(crate) fn parse(self) -> extjson::de::Result<Bson> {
+    pub(crate) fn parse(self) -> Result<Bson> {
         if self.value == 1 {
             Ok(Bson::MinKey)
         } else {
-            Err(extjson::de::Error::invalid_value(
+            Err(Error::invalid_value(
                 Unexpected::Unsigned(self.value as u64),
                 &"value of $minKey should always be 1",
             ))
@@ -317,11 +305,11 @@ pub(crate) struct MaxKey {
 }
 
 impl MaxKey {
-    pub(crate) fn parse(self) -> extjson::de::Result<Bson> {
+    pub(crate) fn parse(self) -> Result<Bson> {
         if self.value == 1 {
             Ok(Bson::MaxKey)
         } else {
-            Err(extjson::de::Error::invalid_value(
+            Err(Error::invalid_value(
                 Unexpected::Unsigned(self.value as u64),
                 &"value of $maxKey should always be 1",
             ))
@@ -347,7 +335,7 @@ pub(crate) struct DbPointerBody {
 }
 
 impl DbPointer {
-    pub(crate) fn parse(self) -> extjson::de::Result<crate::DbPointer> {
+    pub(crate) fn parse(self) -> Result<crate::DbPointer> {
         Ok(crate::DbPointer {
             namespace: self.body.ref_ns,
             id: self.body.id.parse()?,
@@ -363,11 +351,11 @@ pub(crate) struct Undefined {
 }
 
 impl Undefined {
-    pub(crate) fn parse(self) -> extjson::de::Result<Bson> {
+    pub(crate) fn parse(self) -> Result<Bson> {
         if self.value {
             Ok(Bson::Undefined)
         } else {
-            Err(extjson::de::Error::invalid_value(
+            Err(Error::invalid_value(
                 Unexpected::Bool(false),
                 &"$undefined should always be true",
             ))
diff --git a/src/lib.rs b/src/lib.rs
index c5572c5d..98b791d4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -218,7 +218,7 @@
 //! When serializing values that cannot be represented in BSON, or deserialzing from BSON that does
 //! not match the format expected by the type, the default error will only report the specific field
 //! that failed. To aid debugging, enabling the `serde_path_to_error` feature will
-//! [augment errors](crate::de::Error::WithPath) with the full field path from root object to
+//! [augment errors](crate::error::Error::path) with the full field path from root object to
 //! failing field.  This feature does incur a small CPU and memory overhead during (de)serialization
 //! and should be enabled with care in performance-sensitive environments.
 //!
diff --git a/src/ser.rs b/src/ser.rs
index 5d925ab6..4100d40e 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -21,20 +21,17 @@
 
 //! Serializer
 
-mod error;
 mod raw;
 mod serde;
 
-pub use self::{
-    error::{Error, Result},
-    serde::Serializer,
-};
+pub use self::serde::Serializer;
 
 #[rustfmt::skip]
 use ::serde::{ser::Error as SerdeError, Serialize};
 
 use crate::{
     bson::{Bson, Document},
+    error::{Error, Result},
     ser::serde::SerializerOptions,
     RawDocumentBuf,
 };
@@ -79,12 +76,10 @@ where
 {
     match serialize_to_bson(value)? {
         Bson::Document(doc) => Ok(doc),
-        bson => Err(Error::SerializationError {
-            message: format!(
-                "Could not be serialized to Document, got {:?} instead",
-                bson.element_type()
-            ),
-        }),
+        bson => Err(Error::serialization(format!(
+            "expected to serialize document, got type {:?} instead",
+            bson.element_type()
+        ))),
     }
 }
 
diff --git a/src/ser/error.rs b/src/ser/error.rs
deleted file mode 100644
index 1bddb7df..00000000
--- a/src/ser/error.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-use std::{error, fmt, fmt::Display, io, sync::Arc};
-
-use serde::ser;
-
-use crate::bson::Bson;
-
-/// Possible errors that can arise during encoding.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Error {
-    /// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while serializing.
-    Io(Arc<io::Error>),
-
-    /// A key could not be serialized to a BSON string.
-    InvalidDocumentKey(Bson),
-
-    /// A general error that occurred during serialization.
-    /// See: <https://docs.rs/serde/1.0.110/serde/ser/trait.Error.html#tymethod.custom>
-    #[non_exhaustive]
-    SerializationError {
-        /// A message describing the error.
-        message: String,
-    },
-
-    /// An unsigned integer type could not fit into a signed integer type.
-    UnsignedIntegerExceededRange(u64),
-
-    #[cfg(feature = "serde_path_to_error")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "serde_path_to_error")))]
-    #[non_exhaustive]
-    WithPath {
-        /// The path to the error.
-        path: serde_path_to_error::Path,
-
-        /// The original error.
-        source: Box<Error>,
-    },
-
-    /// TODO RUST-1406 remove this
-    Crate(Arc<crate::error::Error>),
-}
-
-impl Error {
-    #[cfg(feature = "serde_path_to_error")]
-    pub(crate) fn with_path(err: serde_path_to_error::Error<Error>) -> Self {
-        let path = err.path().clone();
-        let source = Box::new(err.into_inner());
-        Self::WithPath { path, source }
-    }
-
-    #[cfg(test)]
-    pub(crate) fn strip_path(self) -> Self {
-        #[cfg(feature = "serde_path_to_error")]
-        match self {
-            Self::WithPath { path: _, source } => *source,
-            _ => self,
-        }
-        #[cfg(not(feature = "serde_path_to_error"))]
-        {
-            self
-        }
-    }
-}
-
-impl From<io::Error> for Error {
-    fn from(err: io::Error) -> Error {
-        Error::Io(Arc::new(err))
-    }
-}
-
-impl From<crate::error::Error> for Error {
-    fn from(err: crate::error::Error) -> Error {
-        Error::Crate(Arc::new(err))
-    }
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::Io(inner) => inner.fmt(fmt),
-            Error::InvalidDocumentKey(key) => write!(fmt, "Invalid map key type: {}", key),
-            Error::SerializationError { message } => message.fmt(fmt),
-            Error::UnsignedIntegerExceededRange(value) => write!(
-                fmt,
-                "BSON does not support unsigned integers.
-                 An attempt to serialize the value: {} in a signed type failed due to the value's \
-                 size.",
-                value
-            ),
-            #[cfg(feature = "serde_path_to_error")]
-            Error::WithPath { path, source } => write!(fmt, "error at {}: {}", path, source),
-            Error::Crate(inner) => inner.fmt(fmt),
-        }
-    }
-}
-
-impl error::Error for Error {
-    fn cause(&self) -> Option<&dyn error::Error> {
-        match *self {
-            Error::Io(ref inner) => Some(inner.as_ref()),
-            _ => None,
-        }
-    }
-}
-
-impl ser::Error for Error {
-    fn custom<T: Display>(msg: T) -> Error {
-        Error::SerializationError {
-            message: msg.to_string(),
-        }
-    }
-}
-
-/// Alias for `Result<T, Error>`.
-pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/ser/raw.rs b/src/ser/raw.rs
index 6980423b..c376c479 100644
--- a/src/ser/raw.rs
+++ b/src/ser/raw.rs
@@ -175,7 +175,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
 
         match i64::try_from(v) {
             Ok(ivalue) => self.serialize_i64(ivalue),
-            Err(_) => Err(Error::UnsignedIntegerExceededRange(v)),
+            Err(_) => Err(Error::too_large_integer(v)),
         }
     }
 
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index 55da28d2..21587da6 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -1,10 +1,8 @@
 use serde::{ser::Impossible, Serialize};
 
 use crate::{
+    error::{Error, Result},
     raw::write_cstring,
-    ser::{Error, Result},
-    serialize_to_bson,
-    Bson,
     RawBsonRef,
 };
 
@@ -185,12 +183,6 @@ struct KeySerializer<'a> {
     root_serializer: &'a mut Serializer,
 }
 
-impl KeySerializer<'_> {
-    fn invalid_key<T: Serialize>(v: T) -> Error {
-        Error::InvalidDocumentKey(serialize_to_bson(&v).unwrap_or(Bson::Null))
-    }
-}
-
 impl serde::Serializer for KeySerializer<'_> {
     type Ok = ();
 
@@ -205,78 +197,78 @@ impl serde::Serializer for KeySerializer<'_> {
     type SerializeStructVariant = Impossible<(), Error>;
 
     #[inline]
-    fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_bool(self, _v: bool) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("bool"))
     }
 
     #[inline]
-    fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_i8(self, _v: i8) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("i8"))
     }
 
     #[inline]
-    fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_i16(self, _v: i16) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("i16"))
     }
 
     #[inline]
-    fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_i32(self, _v: i32) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("i32"))
     }
 
     #[inline]
-    fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_i64(self, _v: i64) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("i64"))
     }
 
     #[inline]
-    fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_u8(self, _v: u8) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("u8"))
     }
 
     #[inline]
-    fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_u16(self, _v: u16) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("u16"))
     }
 
     #[inline]
-    fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_u32(self, _v: u32) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("u32"))
     }
 
     #[inline]
-    fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_u64(self, _v: u64) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("u64"))
     }
 
     #[inline]
-    fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_f32(self, _v: f32) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("f32"))
     }
 
     #[inline]
-    fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_f64(self, _v: f64) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("f64"))
     }
 
     #[inline]
-    fn serialize_char(self, v: char) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_char(self, _v: char) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("char"))
     }
 
     #[inline]
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
-        Ok(write_cstring(&mut self.root_serializer.bytes, v)?)
+        write_cstring(&mut self.root_serializer.bytes, v)
     }
 
     #[inline]
-    fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
-        Err(Self::invalid_key(v))
+    fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type("bytes"))
     }
 
     #[inline]
     fn serialize_none(self) -> Result<Self::Ok> {
-        Err(Self::invalid_key(Bson::Null))
+        Err(Error::invalid_key_type("none"))
     }
 
     #[inline]
@@ -289,12 +281,12 @@ impl serde::Serializer for KeySerializer<'_> {
 
     #[inline]
     fn serialize_unit(self) -> Result<Self::Ok> {
-        Err(Self::invalid_key(Bson::Null))
+        Err(Error::invalid_key_type("unit"))
     }
 
     #[inline]
-    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
-        Err(Self::invalid_key(Bson::Null))
+    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
+        Err(Error::invalid_key_type(name))
     }
 
     #[inline]
@@ -318,65 +310,65 @@ impl serde::Serializer for KeySerializer<'_> {
     #[inline]
     fn serialize_newtype_variant<T>(
         self,
-        _name: &'static str,
+        name: &'static str,
         _variant_index: u32,
-        _variant: &'static str,
-        value: &T,
+        variant: &'static str,
+        _value: &T,
     ) -> Result<Self::Ok>
     where
         T: Serialize + ?Sized,
     {
-        Err(Self::invalid_key(value))
+        Err(Error::invalid_key_type(format!("{}::{}", name, variant)))
     }
 
     #[inline]
     fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
-        Err(Self::invalid_key(Bson::Array(vec![])))
+        Err(Error::invalid_key_type("sequence"))
     }
 
     #[inline]
     fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
-        Err(Self::invalid_key(Bson::Array(vec![])))
+        Err(Error::invalid_key_type("tuple"))
     }
 
     #[inline]
     fn serialize_tuple_struct(
         self,
-        _name: &'static str,
+        name: &'static str,
         _len: usize,
     ) -> Result<Self::SerializeTupleStruct> {
-        Err(Self::invalid_key(Bson::Document(doc! {})))
+        Err(Error::invalid_key_type(name))
     }
 
     #[inline]
     fn serialize_tuple_variant(
         self,
-        _name: &'static str,
+        name: &'static str,
         _variant_index: u32,
-        _variant: &'static str,
+        variant: &'static str,
         _len: usize,
     ) -> Result<Self::SerializeTupleVariant> {
-        Err(Self::invalid_key(Bson::Array(vec![])))
+        Err(Error::invalid_key_type(format!("{}::{}", name, variant)))
     }
 
     #[inline]
     fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
-        Err(Self::invalid_key(Bson::Document(doc! {})))
+        Err(Error::invalid_key_type("map"))
     }
 
     #[inline]
-    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
-        Err(Self::invalid_key(Bson::Document(doc! {})))
+    fn serialize_struct(self, name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
+        Err(Error::invalid_key_type(name))
     }
 
     #[inline]
     fn serialize_struct_variant(
         self,
-        _name: &'static str,
+        name: &'static str,
         _variant_index: u32,
-        _variant: &'static str,
+        variant: &'static str,
         _len: usize,
     ) -> Result<Self::SerializeStructVariant> {
-        Err(Self::invalid_key(Bson::Document(doc! {})))
+        Err(Error::invalid_key_type(format!("{}::{}", name, variant)))
     }
 }
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index 99abc7c9..b7cb203b 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -15,6 +15,7 @@ use crate::{
     base64,
     bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp},
     datetime::DateTime,
+    error::{Error, Result},
     extjson,
     oid::ObjectId,
     raw::{RawDbPointerRef, RawRegexRef, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
@@ -25,11 +26,11 @@ use crate::{
     Decimal128,
 };
 
-use super::{to_bson_with_options, Error};
+use super::to_bson_with_options;
 
 impl Serialize for ObjectId {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: serde::ser::Serializer,
     {
@@ -41,7 +42,7 @@ impl Serialize for ObjectId {
 
 impl Serialize for Document {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -55,7 +56,7 @@ impl Serialize for Document {
 
 impl Serialize for Bson {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -193,7 +194,7 @@ impl ser::Serializer for Serializer {
 
         match i64::try_from(value) {
             Ok(ivalue) => Ok(Bson::Int64(ivalue)),
-            Err(_) => Err(Error::UnsignedIntegerExceededRange(value)),
+            Err(_) => Err(Error::too_large_integer(value)),
         }
     }
 
@@ -525,10 +526,10 @@ impl SerializeMap for MapSerializer {
     type Ok = Bson;
     type Error = Error;
 
-    fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> crate::ser::Result<()> {
+    fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<()> {
         self.next_key = match to_bson_with_options(&key, self.options.clone())? {
             Bson::String(s) => Some(s),
-            other => return Err(Error::InvalidDocumentKey(other)),
+            other => return Err(Error::invalid_key_type(other.element_type().name())),
         };
         Ok(())
     }
@@ -603,7 +604,7 @@ impl SerializeStructVariant for StructVariantSerializer {
 
 impl Serialize for Timestamp {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -619,7 +620,7 @@ impl Serialize for Timestamp {
 
 impl Serialize for Regex {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -633,7 +634,7 @@ impl Serialize for Regex {
 
 impl Serialize for JavaScriptCodeWithScope {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -646,7 +647,7 @@ impl Serialize for JavaScriptCodeWithScope {
 
 impl Serialize for Binary {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -666,7 +667,7 @@ impl Serialize for Binary {
 
 impl Serialize for Decimal128 {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -683,7 +684,7 @@ impl Serialize for Decimal128 {
 
 impl Serialize for DateTime {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
@@ -696,7 +697,7 @@ impl Serialize for DateTime {
 
 impl Serialize for DbPointer {
     #[inline]
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
     where
         S: ser::Serializer,
     {
diff --git a/src/spec.rs b/src/spec.rs
index dc082ff7..a7b07200 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -148,6 +148,33 @@ impl ElementType {
             _ => return None,
         })
     }
+
+    #[cfg(feature = "serde")]
+    pub(crate) fn name(&self) -> &'static str {
+        match self {
+            Self::Double => "double",
+            Self::String => "string",
+            Self::EmbeddedDocument => "document",
+            Self::Array => "array",
+            Self::Binary => "binary",
+            Self::Undefined => "undefined",
+            Self::ObjectId => "object ID",
+            Self::Boolean => "boolean",
+            Self::DateTime => "datetime",
+            Self::Null => "null",
+            Self::RegularExpression => "regular expression",
+            Self::DbPointer => "DB pointer",
+            Self::JavaScriptCode => "javascript code",
+            Self::Symbol => "symbol",
+            Self::JavaScriptCodeWithScope => "javascript code with scope",
+            Self::Int32 => "int32",
+            Self::Timestamp => "timestamp",
+            Self::Int64 => "int64",
+            Self::Decimal128 => "decimal128",
+            Self::MaxKey => "max key",
+            Self::MinKey => "min key",
+        }
+    }
 }
 
 /// The available binary subtypes, plus a user-defined slot.
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index 8e16f3b6..bca4defe 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -4,8 +4,8 @@ use assert_matches::assert_matches;
 
 use crate::{
     deserialize_from_bson,
+    error::ErrorKind,
     oid::ObjectId,
-    ser,
     serialize_to_bson,
     serialize_to_vec,
     tests::LOCK,
@@ -119,8 +119,11 @@ fn uint64_u2i() {
     let deser_min: u64 = deserialize_from_bson(obj_min).unwrap();
     assert_eq!(deser_min, u64::MIN);
 
-    let err: ser::Error = serialize_to_bson(&u64::MAX).unwrap_err().strip_path();
-    assert_matches!(err, ser::Error::UnsignedIntegerExceededRange(u64::MAX));
+    let error = serialize_to_bson(&u64::MAX).unwrap_err();
+    assert_matches!(
+        error.kind,
+        ErrorKind::TooLargeUnsignedInteger { n: u64::MAX }
+    );
 }
 
 #[test]
@@ -172,9 +175,6 @@ fn cstring_null_bytes_error() {
         assert!(err.is_malformed_bytes(), "unexpected error: {:?}", err);
         let result = serialize_to_vec(&doc);
         assert!(result.is_err(), "unexpected success");
-        match result.unwrap_err().strip_path() {
-            ser::Error::Crate(inner) if inner.is_malformed_bytes() => (),
-            err => panic!("unexpected error: {:?}", err),
-        };
+        assert!(result.unwrap_err().is_malformed_bytes());
     }
 }
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 2afc6a73..67bc6d09 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -9,7 +9,6 @@ use crate::{
     de::deserialize_from_document,
     doc,
     oid::ObjectId,
-    ser::Error,
     serialize_to_document,
     spec::BinarySubtype,
     tests::LOCK,
@@ -542,15 +541,12 @@ fn test_serialize_deserialize_document() {
 
     let x = 1;
     let err = serialize_to_document(&x).unwrap_err();
-    match err {
-        Error::SerializationError { message } => {
-            assert!(message.contains("Could not be serialized to Document"));
-        }
-        e => panic!("expected SerializationError, got {}", e),
-    }
+    assert!(err
+        .message
+        .is_some_and(|message| message.contains("expected to serialize document")));
 
     let bad_point = doc! { "x": "one", "y": "two" };
-    let bad_point: Result<Point, crate::de::Error> = deserialize_from_document(bad_point);
+    let bad_point = deserialize_from_document::<Point>(bad_point);
     assert!(bad_point.is_err());
 }
 
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index aedc739d..17a308ba 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -1075,12 +1075,8 @@ mod serde_path_to_error {
         };
         let result: Result<Foo, _> = crate::deserialize_from_document(src);
         assert!(result.is_err());
-        match result.unwrap_err() {
-            crate::de::Error::WithPath { source: _, path } => {
-                assert_eq!("two.value", path.to_string())
-            }
-            e => panic!("unexpected error: {:?}", e),
-        }
+        let path = result.unwrap_err().path.unwrap();
+        assert_eq!(path.to_string(), "two.value");
     }
 
     #[test]
@@ -1096,12 +1092,8 @@ mod serde_path_to_error {
         .into_bytes();
         let result: Result<Foo, _> = crate::deserialize_from_slice(&src);
         assert!(result.is_err());
-        match result.unwrap_err() {
-            crate::de::Error::WithPath { source: _, path } => {
-                assert_eq!("two.value", path.to_string())
-            }
-            e => panic!("unexpected error: {:?}", e),
-        }
+        let path = result.unwrap_err().path.unwrap();
+        assert_eq!(path.to_string(), "two.value");
     }
 
     #[test]
@@ -1112,12 +1104,8 @@ mod serde_path_to_error {
         };
         let result = crate::serialize_to_bson(&src);
         assert!(result.is_err());
-        match result.unwrap_err() {
-            crate::ser::Error::WithPath { source: _, path } => {
-                assert_eq!("two.value", path.to_string())
-            }
-            e => panic!("unexpected error: {:?}", e),
-        }
+        let path = result.unwrap_err().path.unwrap();
+        assert_eq!(path.to_string(), "two.value");
     }
 
     #[test]
@@ -1128,11 +1116,7 @@ mod serde_path_to_error {
         };
         let result = crate::serialize_to_vec(&src);
         assert!(result.is_err());
-        match result.unwrap_err() {
-            crate::ser::Error::WithPath { source: _, path } => {
-                assert_eq!("two.value", path.to_string())
-            }
-            e => panic!("unexpected error: {:?}", e),
-        }
+        let path = result.unwrap_err().path.unwrap();
+        assert_eq!(path.to_string(), "two.value");
     }
 }

From 59c347f4e6ec5e7c18d43337ee06ecc5c94cc508 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 2 Jul 2025 12:54:04 -0400
Subject: [PATCH 130/156] RUST-1887 Make BindRawBsonRef a little more
 user-friendly (#565)

---
 src/raw.rs              |  2 +-
 src/raw/bson_ref.rs     |  6 ++++
 src/raw/document_buf.rs | 73 +++++++++++++++++++++++++++--------------
 3 files changed, 56 insertions(+), 25 deletions(-)

diff --git a/src/raw.rs b/src/raw.rs
index b1a2c8be..3444a61d 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -143,7 +143,7 @@ pub use self::{
         RawRegexRef,
     },
     document::RawDocument,
-    document_buf::{BindRawBsonRef, RawDocumentBuf},
+    document_buf::{BindRawBsonRef, BindValue, RawDocumentBuf},
     iter::{RawElement, RawIter},
 };
 
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index 8a72fed5..a2847734 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -489,6 +489,12 @@ impl From<Decimal128> for RawBsonRef<'_> {
     }
 }
 
+impl<'a> From<&'a RawBson> for RawBsonRef<'a> {
+    fn from(value: &'a RawBson) -> Self {
+        value.as_raw_bson_ref()
+    }
+}
+
 /// A BSON binary value referencing raw bytes stored elsewhere.
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct RawBinaryRef<'a> {
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 2f5c22b9..8c8ee3f4 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -325,52 +325,77 @@ impl Borrow<RawDocument> for RawDocumentBuf {
 
 /// Types that can be consumed to produce raw bson references valid for a limited lifetime.
 /// Conceptually a union between `T: Into<RawBson>` and `T: Into<RawBsonRef>`; if your type
-/// implements `Into<RawBsonRef>` it will automatically implement this, but if it only
-/// implements `Into<RawBson>` it will need to manually define the trivial impl.
-pub trait BindRawBsonRef {
-    fn bind<F, R>(self, f: F) -> R
-    where
-        F: for<'a> FnOnce(RawBsonRef<'a>) -> R;
-}
+/// implements `Into<RawBsonRef>` it will automatically implement this, but if it
+/// implements `Into<RawBson>` it will need to also define an impl of `BindRawBsonRef`:
+/// ```
+/// # use bson::raw::{BindRawBsonRef, BindValue, RawBson};
+/// # struct MyType;
+/// # impl Into<RawBson> for MyType {
+/// #  fn into(self: Self) -> RawBson { todo!() }
+/// # }
+/// impl BindRawBsonRef for MyType {
+///   type Target = BindValue<Self>;
+/// }
+/// ```
+pub trait BindRawBsonRef: Sized {
+    type Target: BindHelper<Target = Self>;
 
-impl<'a, T: Into<RawBsonRef<'a>>> BindRawBsonRef for T {
     fn bind<F, R>(self, f: F) -> R
     where
-        F: for<'b> FnOnce(RawBsonRef<'b>) -> R,
+        F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
     {
-        f(self.into())
+        <Self::Target as BindHelper>::bind(self, f)
     }
 }
 
-impl BindRawBsonRef for RawBson {
-    fn bind<F, R>(self, f: F) -> R
+#[doc(hidden)]
+pub trait BindHelper {
+    type Target;
+    fn bind<F, R>(target: Self::Target, f: F) -> R
+    where
+        F: for<'b> FnOnce(RawBsonRef<'b>) -> R;
+}
+
+/// A struct to use as the `Target` of a [`BindRawBsonRef`] impl for custom types.
+pub struct BindValue<A>(std::marker::PhantomData<A>);
+#[doc(hidden)]
+pub struct BindRef<A>(std::marker::PhantomData<A>);
+
+impl<A: Into<RawBson>> BindHelper for BindValue<A> {
+    type Target = A;
+
+    fn bind<F, R>(target: Self::Target, f: F) -> R
     where
         F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
     {
-        f(self.as_raw_bson_ref())
+        f(target.into().as_raw_bson_ref())
     }
 }
 
-impl BindRawBsonRef for &RawBson {
-    fn bind<F, R>(self, f: F) -> R
+impl<'a, A: Into<RawBsonRef<'a>> + 'a> BindHelper for BindRef<A> {
+    type Target = A;
+
+    fn bind<F, R>(target: Self::Target, f: F) -> R
     where
-        F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
+        F: for<'b> FnOnce(RawBsonRef<'a>) -> R,
     {
-        f(self.as_raw_bson_ref())
+        f(target.into())
     }
 }
 
+impl<'a, T: Into<RawBsonRef<'a>> + 'a> BindRawBsonRef for T {
+    type Target = BindRef<T>;
+}
+
+impl BindRawBsonRef for RawBson {
+    type Target = BindValue<Self>;
+}
+
 macro_rules! raw_bson_from_impls {
     ($($t:ty),+$(,)?) => {
         $(
             impl BindRawBsonRef for $t {
-                fn bind<F, R>(self, f: F) -> R
-                where
-                    F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
-                {
-                    let tmp: RawBson = self.into();
-                    f(tmp.as_raw_bson_ref())
-                }
+                type Target = BindValue<Self>;
             }
         )+
     };

From 95774f9f6fc401637813308eec60c1212d52ec1e Mon Sep 17 00:00:00 2001
From: Jamie Tsai <49384456+JamieTsai1024@users.noreply.github.com>
Date: Thu, 3 Jul 2025 11:01:30 -0400
Subject: [PATCH 131/156] RUST-1748 Convert serde helpers to
 serde_with::(De)SerializeAs implementations for some converters between
 ObjectId, String, and DateTime  (#559)

---
 Cargo.toml           |   2 +-
 README.md            |   6 +-
 src/datetime.rs      |  16 +-
 src/lib.rs           |   7 +-
 src/oid.rs           |   7 +-
 src/serde_helpers.rs | 434 +++++++++++++++--------------
 src/tests/serde.rs   | 647 +++++++++++++++++++++++++++++++++++--------
 7 files changed, 766 insertions(+), 353 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index abff6263..1e7e43db 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -46,7 +46,7 @@ time-0_3 = []
 serde_path_to_error = ["dep:serde_path_to_error"]
 # if enabled, include serde_with interop.
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
-serde_with-3 = ["dep:serde_with"]
+serde_with-3 = ["dep:serde_with", "dep:serde"]
 serde = ["dep:serde"]
 
 [lib]
diff --git a/README.md b/README.md
index fffa70bf..e9d98592 100644
--- a/README.md
+++ b/README.md
@@ -229,7 +229,7 @@ provides a `DateTime` type, but its `Serialize` and `Deserialize` implementation
 instead, so when using it with BSON, the BSON datetime type is not used. To work around this, the
 `chrono-0_4` feature flag can be enabled. This flag exposes a number of convenient conversions
 between `bson::DateTime` and `chrono::DateTime`, including the
-[`chrono_datetime_as_bson_datetime`](https://docs.rs/bson/latest/bson/serde_helpers/chrono_datetime_as_bson_datetime/index.html)
+[`bson_datetime::FromChronoDateTime`](https://docs.rs/bson/latest/bson/serde_helpers/bson_datetime/struct.FromChronoDateTime/index.html)
 serde helper, which can be used to (de)serialize `chrono::DateTime`s to/from BSON datetimes, and the
 `From<chrono::DateTime>` implementation for `Bson`, which allows `chrono::DateTime` values to be
 used in the `doc!` and `bson!` macros.
@@ -237,7 +237,9 @@ used in the `doc!` and `bson!` macros.
 e.g.
 ``` rust
 use serde::{Serialize, Deserialize};
+use serde_with::serde_as;
 
+#[serde_as]
 #[derive(Serialize, Deserialize)]
 struct Foo {
     // serializes as a BSON datetime.
@@ -248,7 +250,7 @@ struct Foo {
 
     // serializes as a BSON datetime.
     // this requires the "chrono-0_4" feature flag
-    #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
+    #[serde_as(as = "bson::serde_helpers::bson_datetime::FromChronoDateTime")]
     chrono_as_bson: chrono::DateTime<chrono::Utc>,
 }
 
diff --git a/src/datetime.rs b/src/datetime.rs
index 6ed887f1..81e46a3d 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -110,16 +110,20 @@ use crate::error::{Error, Result};
 /// The `bson` crate provides a number of useful helpers for serializing and deserializing
 /// various datetime types to and from different formats. For example, to serialize a
 /// [`chrono::DateTime`] as a BSON datetime, you can use
-/// [`crate::serde_helpers::chrono_datetime_as_bson_datetime`]. Similarly, to serialize a BSON
-/// [`DateTime`] to a string, you can use [`crate::serde_helpers::bson_datetime_as_rfc3339_string`].
-/// Check out the [`crate::serde_helpers`] module documentation for a list of all of the helpers
-/// offered by the crate.
+/// [`crate::serde_helpers::bson_datetime::FromChronoDateTime`].
+/// Similarly, to serialize a BSON [`DateTime`] to a string, you can use
+/// [`crate::serde_helpers::bson_datetime::AsRfc3339String`]. Check out the
+/// [`crate::serde_helpers`] module documentation for a list of all of the helpers offered by the
+/// crate.
 ///
 /// ```rust
 /// # #[cfg(feature = "chrono-0_4")]
 /// # {
 /// use serde::{Serialize, Deserialize};
+/// use serde_with::serde_as;
+/// use bson::serde_helpers::bson_datetime;
 ///
+/// #[serde_as]
 /// #[derive(Serialize, Deserialize)]
 /// struct Foo {
 ///     // serializes as a BSON datetime.
@@ -130,11 +134,11 @@ use crate::error::{Error, Result};
 ///
 ///     // serializes as a BSON datetime.
 ///     // this requires the "chrono-0_4" feature flag
-///     #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
+///     #[serde_as(as = "bson_datetime::FromChronoDateTime")]
 ///     chrono_as_bson: chrono::DateTime<chrono::Utc>,
 ///
 ///     // serializes as an RFC 3339 / ISO-8601 string.
-///     #[serde(with = "bson::serde_helpers::bson_datetime_as_rfc3339_string")]
+///     #[serde_as(as = "bson_datetime::AsRfc3339String")]
 ///     bson_as_string: bson::DateTime,
 /// }
 /// # }
diff --git a/src/lib.rs b/src/lib.rs
index 98b791d4..a4972cc4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -233,7 +233,7 @@
 //! on strings instead, so when using it with BSON, the BSON datetime type is not used. To work
 //! around this, the `chrono-0_4` feature flag can be enabled. This flag exposes a number of
 //! convenient conversions between [`bson::DateTime`](crate::DateTime) and [`chrono::DateTime`],
-//! including the [`serde_helpers::chrono_datetime_as_bson_datetime`]
+//! including the [`serde_helpers::bson_datetime::FromChronoDateTime`]
 //! serde helper, which can be used to (de)serialize [`chrono::DateTime`]s to/from BSON datetimes,
 //! and the `From<chrono::DateTime>` implementation for [`Bson`], which allows [`chrono::DateTime`]
 //! values to be used in the `doc!` and `bson!` macros.
@@ -243,8 +243,11 @@
 //! # #[cfg(feature = "chrono-0_4")]
 //! # {
 //! use serde::{Serialize, Deserialize};
+//! use serde_with::serde_as;
 //! use bson::doc;
+//! use bson::serde_helpers::bson_datetime;
 //!
+//! #[serde_as]
 //! #[derive(Serialize, Deserialize)]
 //! struct Foo {
 //!     // serializes as a BSON datetime.
@@ -255,7 +258,7 @@
 //!
 //!     // serializes as a BSON datetime.
 //!     // this requires the "chrono-0_4" feature flag
-//!     #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
+//!     #[serde_as(as = "bson_datetime::FromChronoDateTime")]
 //!     chrono_as_bson: chrono::DateTime<chrono::Utc>,
 //! }
 //!
diff --git a/src/oid.rs b/src/oid.rs
index bb409f5e..bb2b479a 100644
--- a/src/oid.rs
+++ b/src/oid.rs
@@ -62,22 +62,25 @@ static OID_COUNTER: Lazy<AtomicUsize> =
 /// The `bson` crate provides a number of useful helpers for serializing and deserializing
 /// various types to and from different formats. For example, to serialize an
 /// [`ObjectId`] as a hex string, you can use
-/// [`crate::serde_helpers::serialize_object_id_as_hex_string`].
+/// [`crate::serde_helpers::object_id::AsHexString`].
 /// Check out the [`crate::serde_helpers`] module documentation for a list of all of the helpers
 /// offered by the crate.
 ///
 /// e.g.
 /// ```rust
 /// use serde::{Serialize, Deserialize};
+/// use serde_with::serde_as;
 /// use bson::oid::ObjectId;
+/// use bson::serde_helpers::object_id;
 ///
+/// #[serde_as]
 /// #[derive(Serialize, Deserialize)]
 /// struct Foo {
 ///     // Serializes as a BSON ObjectId or extJSON in non-BSON formats
 ///     oid: ObjectId,
 ///
 ///     // Serializes as a hex string in all formats
-///     #[serde(serialize_with = "bson::serde_helpers::serialize_object_id_as_hex_string")]
+///     #[serde_as(as = "object_id::AsHexString")]
 ///     oid_as_hex: ObjectId,
 /// }
 /// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 6cd1bb25..52e11579 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -9,40 +9,11 @@ use std::{
 
 use serde::{de::Visitor, ser, Deserialize, Serialize, Serializer};
 
-use crate::oid::ObjectId;
-
-#[doc(inline)]
-pub use bson_datetime_as_rfc3339_string::{
-    deserialize as deserialize_bson_datetime_from_rfc3339_string,
-    serialize as serialize_bson_datetime_as_rfc3339_string,
-};
-#[cfg(feature = "chrono-0_4")]
-#[doc(inline)]
-pub use chrono_datetime_as_bson_datetime::{
-    deserialize as deserialize_chrono_datetime_from_bson_datetime,
-    serialize as serialize_chrono_datetime_as_bson_datetime,
-};
-#[cfg(feature = "chrono-0_4")]
-#[doc(inline)]
-pub use chrono_datetime_as_bson_datetime_optional::{
-    deserialize as deserialize_chrono_datetime_from_bson_datetime_optional,
-    serialize as serialize_chrono_datetime_as_bson_datetime_optional,
-};
-#[doc(inline)]
-pub use hex_string_as_object_id::{
-    deserialize as deserialize_hex_string_from_object_id,
-    serialize as serialize_hex_string_as_object_id,
-};
 #[doc(inline)]
 pub use i64_as_bson_datetime::{
     deserialize as deserialize_i64_from_bson_datetime,
     serialize as serialize_i64_as_bson_datetime,
 };
-#[doc(inline)]
-pub use rfc3339_string_as_bson_datetime::{
-    deserialize as deserialize_rfc3339_string_from_bson_datetime,
-    serialize as serialize_rfc3339_string_as_bson_datetime,
-};
 #[cfg(feature = "time-0_3")]
 #[doc(inline)]
 pub use time_0_3_offsetdatetime_as_bson_datetime::{
@@ -118,12 +89,92 @@ pub fn serialize_u64_as_i64<S: Serializer>(val: &u64, serializer: S) -> Result<S
     }
 }
 
-/// Serializes an [`ObjectId`] as a hex string.
-pub fn serialize_object_id_as_hex_string<S: Serializer>(
-    val: &ObjectId,
-    serializer: S,
-) -> Result<S::Ok, S::Error> {
-    val.to_hex().serialize(serializer)
+#[cfg(feature = "serde_with-3")]
+pub mod object_id {
+    use crate::oid::ObjectId;
+    use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
+    use serde_with::{DeserializeAs, SerializeAs};
+
+    /// Contains functions to serialize an ObjectId as a hex string and deserialize an
+    /// ObjectId from a hex string
+    /// ```rust
+    /// # #[cfg(feature = "serde_with-3")]
+    /// {
+    /// # use serde::{Serialize, Deserialize};
+    /// # use bson::serde_helpers::object_id;
+    /// # use serde_with::serde_as;
+    /// # use bson::oid::ObjectId;
+    /// #[serde_as]
+    /// #[derive(Serialize, Deserialize)]
+    /// struct Item {
+    ///     #[serde_as(as = "object_id::AsHexString")]
+    ///     pub id: ObjectId,
+    /// }
+    /// # }
+    /// ```
+    pub struct AsHexString;
+
+    impl SerializeAs<ObjectId> for AsHexString {
+        fn serialize_as<S>(val: &ObjectId, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            val.to_hex().serialize(serializer)
+        }
+    }
+
+    impl<'de> DeserializeAs<'de, ObjectId> for AsHexString {
+        fn deserialize_as<D>(deserializer: D) -> Result<ObjectId, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let hex_string = String::deserialize(deserializer)?;
+            ObjectId::parse_str(&hex_string).map_err(serde::de::Error::custom)
+        }
+    }
+
+    /// Contains functions to serialize a hex string as an ObjectId and deserialize a
+    /// hex string from an ObjectId
+    /// ```rust
+    /// # #[cfg(feature = "serde_with-3")]
+    /// {
+    /// # use serde::{Serialize, Deserialize};
+    /// # use bson::serde_helpers::object_id;
+    /// # use serde_with::serde_as;
+    /// #[serde_as]
+    /// #[derive(Serialize, Deserialize)]
+    /// struct Item {
+    ///     #[serde_as(as = "object_id::FromHexString")]
+    ///     pub id: String,
+    /// }
+    /// # }
+    /// ```
+    pub struct FromHexString;
+
+    impl SerializeAs<String> for FromHexString {
+        fn serialize_as<S>(val: &String, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            match ObjectId::parse_str(val) {
+                Ok(oid) => oid.serialize(serializer),
+                Err(e) => Err(ser::Error::custom(format!(
+                    "cannot convert {} to ObjectId: {}",
+                    val, e
+                ))),
+            }
+        }
+    }
+
+    impl<'de> DeserializeAs<'de, String> for FromHexString {
+        fn deserialize_as<D>(deserializer: D) -> Result<String, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let object_id = ObjectId::deserialize(deserializer)?;
+            Ok(object_id.to_hex())
+        }
+    }
 }
 
 /// Contains functions to serialize a u32 as an f64 (BSON double) and deserialize a
@@ -250,207 +301,154 @@ pub mod time_0_3_offsetdatetime_as_bson_datetime {
     }
 }
 
-/// Contains functions to serialize a [`chrono::DateTime`] as a [`crate::DateTime`] and deserialize
-/// a [`chrono::DateTime`] from a [`crate::DateTime`].
-///
-/// ```rust
-/// # #[cfg(feature = "chrono-0_4")]
-/// # {
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::chrono_datetime_as_bson_datetime;
-/// #[derive(Serialize, Deserialize)]
-/// struct Event {
-///     #[serde(with = "chrono_datetime_as_bson_datetime")]
-///     pub date: chrono::DateTime<chrono::Utc>,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "chrono-0_4")]
-#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
-pub mod chrono_datetime_as_bson_datetime {
-    use crate::DateTime;
-    use chrono::Utc;
-    use serde::{Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-
-    /// Deserializes a [`chrono::DateTime`] from a [`crate::DateTime`].
-    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<chrono::DateTime<Utc>, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let datetime = DateTime::deserialize(deserializer)?;
-        Ok(datetime.to_chrono())
-    }
-
-    /// Serializes a [`chrono::DateTime`] as a [`crate::DateTime`].
-    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
-    pub fn serialize<S: Serializer>(
-        val: &chrono::DateTime<Utc>,
-        serializer: S,
-    ) -> Result<S::Ok, S::Error> {
-        let datetime = DateTime::from_chrono(val.to_owned());
-        datetime.serialize(serializer)
-    }
-}
-
-/// Contains functions to serialize an [`Option<chrono::DateTime>`] as an
-/// [`Option<crate::DateTime>`] and deserialize an [`Option<chrono::DateTime>`] from an
-/// [`Option<crate::DateTime>`].
-///
-/// ```rust
-/// # #[cfg(feature = "chrono-0_4")]
-/// # {
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::chrono_datetime_as_bson_datetime_optional;
-/// #[derive(Serialize, Deserialize)]
-/// struct Event {
-///     #[serde(with = "chrono_datetime_as_bson_datetime_optional")]
-///     pub date: Option<chrono::DateTime<chrono::Utc>>,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "chrono-0_4")]
-#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
-pub mod chrono_datetime_as_bson_datetime_optional {
-    use crate::DateTime;
-    use chrono::Utc;
-    use serde::{Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-
-    /// Deserializes a [`chrono::DateTime`] from a [`crate::DateTime`].
-    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<chrono::DateTime<Utc>>, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let val = Option::deserialize(deserializer)?.map(|datetime: DateTime| datetime.to_chrono());
-        Ok(val)
-    }
-
-    /// Serializes a [`Option<chrono::DateTime>`] as a [`Option<crate::DateTime>`].
-    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
-    pub fn serialize<S: Serializer>(
-        val: &Option<chrono::DateTime<Utc>>,
-        serializer: S,
-    ) -> Result<S::Ok, S::Error> {
-        let datetime = val.map(DateTime::from_chrono);
-        datetime.serialize(serializer)
-    }
-}
-
-/// Contains functions to serialize an RFC 3339 (ISO 8601) formatted string as a [`crate::DateTime`]
-/// and deserialize an RFC 3339 (ISO 8601) formatted string from a [`crate::DateTime`].
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::rfc3339_string_as_bson_datetime;
-/// #[derive(Serialize, Deserialize)]
-/// struct Event {
-///     #[serde(with = "rfc3339_string_as_bson_datetime")]
-///     pub date: String,
-/// }
-/// ```
-pub mod rfc3339_string_as_bson_datetime {
+#[cfg(feature = "serde_with-3")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
+pub mod bson_datetime {
     use crate::{Bson, DateTime};
+    use chrono::Utc;
     use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
+    use serde_with::{DeserializeAs, SerializeAs};
     use std::result::Result;
 
-    /// Deserializes an ISO string from a DateTime.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let date = DateTime::deserialize(deserializer)?;
-        date.try_to_rfc3339_string()
-            .map_err(|e| de::Error::custom(format!("cannot format {} as RFC 3339: {}", date, e)))
+    /// Contains functions to serialize a [`crate::DateTime`] as an RFC 3339 (ISO 8601) formatted
+    /// string and deserialize a [`crate::DateTime`] from an RFC 3339 (ISO 8601) formatted
+    /// string.
+    ///
+    /// ```rust
+    /// # #[cfg(feature = "serde_with-3")]
+    /// {
+    /// # use serde::{Serialize, Deserialize};
+    /// # use bson::serde_helpers::bson_datetime;
+    /// # use serde_with::serde_as;
+    /// #[serde_as]
+    /// #[derive(Serialize, Deserialize)]
+    /// struct Event {
+    ///     #[serde_as(as = "bson_datetime::AsRfc3339String")]
+    ///     pub date: bson::DateTime,
+    /// }
+    /// # }
+    /// ```
+    pub struct AsRfc3339String;
+
+    impl SerializeAs<crate::DateTime> for AsRfc3339String {
+        fn serialize_as<S>(val: &crate::DateTime, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            let formatted = val.try_to_rfc3339_string().map_err(|e| {
+                ser::Error::custom(format!("cannot format {} as RFC 3339: {}", val, e))
+            })?;
+            serializer.serialize_str(&formatted)
+        }
     }
 
-    /// Serializes an ISO string as a DateTime.
-    pub fn serialize<S: Serializer>(val: &str, serializer: S) -> Result<S::Ok, S::Error> {
-        let date = crate::DateTime::parse_rfc3339_str(val)
-            .map_err(|_| ser::Error::custom(format!("cannot convert {} to DateTime", val)))?;
-        Bson::DateTime(date).serialize(serializer)
+    impl<'de> DeserializeAs<'de, crate::DateTime> for AsRfc3339String {
+        fn deserialize_as<D>(deserializer: D) -> Result<crate::DateTime, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let iso = String::deserialize(deserializer)?;
+            let date = crate::DateTime::parse_rfc3339_str(&iso).map_err(|e| {
+                de::Error::custom(format!(
+                    "cannot parse RFC 3339 datetime from \"{}\": {}",
+                    iso, e
+                ))
+            })?;
+            Ok(date)
+        }
     }
-}
-
-/// Contains functions to serialize a [`crate::DateTime`] as an RFC 3339 (ISO 8601) formatted string
-/// and deserialize a [`crate::DateTime`] from an RFC 3339 (ISO 8601) formatted string.
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::bson_datetime_as_rfc3339_string;
-/// #[derive(Serialize, Deserialize)]
-/// struct Event {
-///     #[serde(with = "bson_datetime_as_rfc3339_string")]
-///     pub date: bson::DateTime,
-/// }
-/// ```
-pub mod bson_datetime_as_rfc3339_string {
-    use crate::DateTime;
-    use serde::{de, ser, Deserialize, Deserializer, Serializer};
-    use std::result::Result;
 
-    /// Deserializes a [`crate::DateTime`] from an RFC 3339 formatted string.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let iso = String::deserialize(deserializer)?;
-        let date = crate::DateTime::parse_rfc3339_str(&iso).map_err(|_| {
-            de::Error::custom(format!("cannot parse RFC 3339 datetime from \"{}\"", iso))
-        })?;
-        Ok(date)
+    /// Contains functions to serialize an RFC 3339 (ISO 8601) formatted string as a
+    /// [`crate::DateTime`] and deserialize an RFC 3339 (ISO 8601) formatted string from a
+    /// [`crate::DateTime`].
+    ///
+    /// ```rust
+    /// # #[cfg(feature = "serde_with-3")]
+    /// {
+    /// # use serde::{Serialize, Deserialize};
+    /// # use bson::serde_helpers::bson_datetime;
+    /// # use serde_with::serde_as;
+    /// #[serde_as]
+    /// #[derive(Serialize, Deserialize)]
+    /// struct Event {
+    ///     #[serde_as(as = "bson_datetime::FromRfc3339String")]
+    ///     pub date: String,
+    /// }
+    /// # }
+    /// ```
+    pub struct FromRfc3339String;
+
+    impl SerializeAs<String> for FromRfc3339String {
+        fn serialize_as<S>(val: &String, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            let date = DateTime::parse_rfc3339_str(val).map_err(|e| {
+                ser::Error::custom(format!("cannot convert {} to DateTime: {}", val, e))
+            })?;
+            Bson::DateTime(date).serialize(serializer)
+        }
     }
 
-    /// Serializes a [`crate::DateTime`] as an RFC 3339 (ISO 8601) formatted string.
-    pub fn serialize<S: Serializer>(val: &DateTime, serializer: S) -> Result<S::Ok, S::Error> {
-        let formatted = val
-            .try_to_rfc3339_string()
-            .map_err(|e| ser::Error::custom(format!("cannot format {} as RFC 3339: {}", val, e)))?;
-        serializer.serialize_str(&formatted)
+    impl<'de> DeserializeAs<'de, String> for FromRfc3339String {
+        fn deserialize_as<D>(deserializer: D) -> Result<String, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let date = DateTime::deserialize(deserializer)?;
+            date.try_to_rfc3339_string().map_err(|e| {
+                de::Error::custom(format!("cannot format {} as RFC 3339: {}", date, e))
+            })
+        }
     }
-}
 
-/// Contains functions to serialize a hex string as an ObjectId and deserialize a
-/// hex string from an ObjectId
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::hex_string_as_object_id;
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "hex_string_as_object_id")]
-///     pub id: String,
-/// }
-/// ```
-pub mod hex_string_as_object_id {
-    use crate::oid::ObjectId;
-    use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
-
-    /// Deserializes a hex string from an ObjectId.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let object_id = ObjectId::deserialize(deserializer)?;
-        Ok(object_id.to_hex())
+    #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
+    #[cfg_attr(
+        docsrs,
+        doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3")))
+    )]
+    /// Contains functions to serialize a [`chrono::DateTime`] as a [`crate::DateTime`] and
+    /// deserialize a [`chrono::DateTime`] from a [`crate::DateTime`].
+    ///
+    /// ```rust
+    /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
+    /// # {
+    /// # use serde::{Serialize, Deserialize};
+    /// # use bson::serde_helpers::bson_datetime;
+    /// # use serde_with::serde_as;
+    /// #[serde_as]
+    /// #[derive(Serialize, Deserialize)]
+    /// struct Event {
+    ///     #[serde_as(as = "bson_datetime::FromChronoDateTime")]
+    ///     pub date: chrono::DateTime<chrono::Utc>,
+    /// }
+    /// # }
+    /// ```
+    pub struct FromChronoDateTime;
+
+    impl SerializeAs<chrono::DateTime<Utc>> for FromChronoDateTime {
+        fn serialize_as<S>(val: &chrono::DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            let datetime = DateTime::from_chrono(val.to_owned());
+            datetime.serialize(serializer)
+        }
     }
 
-    /// Serializes a hex string as an ObjectId.
-    pub fn serialize<S: Serializer>(val: &str, serializer: S) -> Result<S::Ok, S::Error> {
-        match ObjectId::parse_str(val) {
-            Ok(oid) => oid.serialize(serializer),
-            Err(_) => Err(ser::Error::custom(format!(
-                "cannot convert {} to ObjectId",
-                val
-            ))),
+    impl<'de> DeserializeAs<'de, chrono::DateTime<Utc>> for FromChronoDateTime {
+        fn deserialize_as<D>(deserializer: D) -> Result<chrono::DateTime<Utc>, D::Error>
+        where
+            D: Deserializer<'de>,
+        {
+            let datetime = DateTime::deserialize(deserializer)?;
+            Ok(datetime.to_chrono())
         }
     }
 }
 
-/// Contains functions to `serialize` a `i64` integer as [`DateTime`](crate::DateTime) and
-/// `deserialize` a `i64` integer from [`DateTime`](crate::DateTime).
+/// Contains functions to `serialize` a `i64` integer as [`crate::DateTime`] and
+/// `deserialize` a `i64` integer from [`crate::DateTime`].
 ///
 /// ### The i64 should represent seconds `(DateTime::timestamp_millis(..))`.
 ///
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 17a308ba..091df19c 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -6,13 +6,11 @@ use crate::{
     deserialize_from_document,
     doc,
     oid::ObjectId,
-    serde_helpers,
     serde_helpers::{
-        bson_datetime_as_rfc3339_string,
-        hex_string_as_object_id,
+        self,
+        bson_datetime,
         i64_as_bson_datetime,
-        rfc3339_string_as_bson_datetime,
-        serialize_object_id_as_hex_string,
+        object_id,
         timestamp_as_u32,
         u32_as_timestamp,
     },
@@ -31,6 +29,7 @@ use crate::{
 
 use serde::{Deserialize, Serialize};
 use serde_json::json;
+use serde_with::serde_as;
 
 use std::{
     collections::BTreeMap,
@@ -753,21 +752,117 @@ fn test_datetime_helpers() {
 
     let _guard = LOCK.run_concurrently();
 
-    #[derive(Deserialize, Serialize)]
-    struct A {
-        #[serde(with = "bson_datetime_as_rfc3339_string")]
-        pub date: DateTime,
-    }
+    #[cfg(feature = "serde_with-3")]
+    {
+        #[serde_as]
+        #[derive(Deserialize, Serialize, Debug)]
+        struct A {
+            #[serde_as(as = "bson_datetime::AsRfc3339String")]
+            pub date: DateTime,
 
-    let iso = "1996-12-20T00:39:57Z";
-    let date = OffsetDateTime::parse(iso, &Rfc3339).unwrap();
-    let a = A {
-        date: crate::DateTime::from_time_0_3(date),
-    };
-    let doc = serialize_to_document(&a).unwrap();
-    assert_eq!(doc.get_str("date").unwrap(), iso);
-    let a: A = deserialize_from_document(doc).unwrap();
-    assert_eq!(a.date.to_time_0_3(), date);
+            #[serde_as(as = "Option<bson_datetime::AsRfc3339String>")]
+            pub date_optional_none: Option<DateTime>,
+
+            #[serde_as(as = "Option<bson_datetime::AsRfc3339String>")]
+            pub date_optional_some: Option<DateTime>,
+
+            #[serde_as(as = "Vec<bson_datetime::AsRfc3339String>")]
+            pub date_vector: Vec<DateTime>,
+        }
+
+        let iso = "1996-12-20T00:39:57Z";
+        let date = DateTime::parse_rfc3339_str(iso).unwrap();
+        let a = A {
+            date,
+            date_optional_none: None,
+            date_optional_some: Some(date),
+            date_vector: vec![date],
+        };
+
+        // Serialize the struct to BSON
+        let doc = serialize_to_document(&a).unwrap();
+
+        // Validate serialized data
+        assert_eq!(
+            doc.get_str("date").unwrap(),
+            iso,
+            "Expected serialized date to match original date from RFC 3339 string."
+        );
+
+        assert_eq!(
+            doc.get("date_optional_none"),
+            Some(&Bson::Null),
+            "Expected serialized date_optional_none to be None."
+        );
+
+        match doc.get("date_optional_some") {
+            Some(Bson::String(value)) => {
+                assert_eq!(
+                    value, iso,
+                    "Expected serialized date_optional_some to match original date."
+                )
+            }
+            _ => panic!("Expected serialized date_optional_some to be a BSON String."),
+        }
+
+        let date_vector = doc
+            .get_array("date_vector")
+            .expect("Expected serialized date_vector to be a BSON array.");
+        let expected_date_vector: Vec<Bson> = a
+            .date_vector
+            .iter()
+            .map(|dt| Bson::String(dt.try_to_rfc3339_string().unwrap()))
+            .collect();
+        assert_eq!(
+            date_vector, &expected_date_vector,
+            "Expected each serialized element in date_vector to match the original."
+        );
+
+        // Deserialize the BSON back to the struct
+        let a_deserialized: A = deserialize_from_document(doc).unwrap();
+
+        // Validate deserialized data
+        assert_eq!(
+            a_deserialized.date, date,
+            "Expected deserialized date to match the original."
+        );
+
+        assert_eq!(
+            a_deserialized.date_optional_none, None,
+            "Expected deserialized date_optional_none to be None."
+        );
+
+        assert_eq!(
+            a_deserialized.date_optional_some,
+            Some(date),
+            "Expected deserialized date_optional_some to match the original."
+        );
+
+        assert_eq!(
+            a_deserialized.date_vector,
+            vec![date],
+            "Expected deserialized date_vector to match the original."
+        );
+
+        // Validate deserializing error case with an invalid DateTime string
+        let invalid_doc = doc! {
+            "date": "not_a_valid_date",
+            "date_optional_none": Bson::Null,
+            "date_optional_some": "also_invalid_date",
+            "date_vector": ["bad1", "bad2"]
+        };
+        let result: Result<A, _> = deserialize_from_document(invalid_doc);
+        assert!(
+            result.is_err(),
+            "Deserialization should fail for invalid DateTime strings"
+        );
+        let err_string = format!("{:?}", result.unwrap_err());
+        assert!(
+            err_string.contains("BSON error"),
+            "Expected error message to mention BSON error: {}",
+            err_string
+        );
+    }
 
     #[cfg(feature = "time-0_3")]
     {
@@ -797,121 +892,445 @@ fn test_datetime_helpers() {
         assert_eq!(b.date, expected);
     }
 
-    #[cfg(feature = "chrono-0_4")]
+    #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
     {
         use std::str::FromStr;
+
+        #[serde_as]
         #[derive(Deserialize, Serialize)]
-        struct B {
-            #[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime")]
+        struct A {
+            #[serde_as(as = "bson_datetime::FromChronoDateTime")]
             pub date: chrono::DateTime<chrono::Utc>,
+
+            #[serde_as(as = "Option<bson_datetime::FromChronoDateTime>")]
+            pub date_optional_none: Option<chrono::DateTime<chrono::Utc>>,
+
+            #[serde_as(as = "Option<bson_datetime::FromChronoDateTime>")]
+            pub date_optional_some: Option<chrono::DateTime<chrono::Utc>>,
+
+            #[serde_as(as = "Vec<bson_datetime::FromChronoDateTime>")]
+            pub date_vector: Vec<chrono::DateTime<chrono::Utc>>,
         }
 
-        let date = r#"
-    {
-        "date": {
-                "$date": {
-                    "$numberLong": "1591700287095"
-                }
+        let iso = "1996-12-20T00:39:57Z";
+        let date: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_str(iso).unwrap();
+        let a: A = A {
+            date,
+            date_optional_none: None,
+            date_optional_some: Some(date),
+            date_vector: vec![date],
+        };
+
+        // Serialize the struct to BSON
+        let doc = serialize_to_document(&a).unwrap();
+
+        // Validate serialized data
+        assert_eq!(
+            doc.get_datetime("date").unwrap().to_chrono(),
+            date,
+            "Expected serialized date to match original date."
+        );
+
+        assert_eq!(
+            doc.get("date_optional_none"),
+            Some(&Bson::Null),
+            "Expected serialized date_optional_none to be None."
+        );
+
+        match doc.get("date_optional_some") {
+            Some(Bson::DateTime(value)) => {
+                assert_eq!(
+                    *value,
+                    DateTime::from_chrono(date),
+                    "Expected serialized date_optional_some to match original."
+                )
+            }
+            _ => panic!("Expected serialized date_optional_some to be a BSON DateTime."),
         }
-    }"#;
-        let json: serde_json::Value = serde_json::from_str(date).unwrap();
-        let b: B = serde_json::from_value(json).unwrap();
-        let expected: chrono::DateTime<chrono::Utc> =
-            chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap();
-        assert_eq!(b.date, expected);
-        let doc = serialize_to_document(&b).unwrap();
-        assert_eq!(doc.get_datetime("date").unwrap().to_chrono(), expected);
-        let b: B = deserialize_from_document(doc).unwrap();
-        assert_eq!(b.date, expected);
+
+        let date_vector = doc
+            .get_array("date_vector")
+            .expect("Expected serialized date_vector to be a BSON array.");
+        let expected_date_vector: Vec<Bson> = a
+            .date_vector
+            .into_iter()
+            .map(|dt| Bson::DateTime(dt.into()))
+            .collect();
+        assert_eq!(
+            date_vector, &expected_date_vector,
+            "Expected each serialized element in date_vector to be a BSON DateTime matching the \
+             original."
+        );
+
+        // Deserialize the BSON back to the struct
+        let a_deserialized: A = deserialize_from_document(doc).unwrap();
+
+        // Validate deserialized data
+        assert_eq!(
+            a_deserialized.date, date,
+            "Expected deserialized date to match original."
+        );
+
+        assert_eq!(
+            a_deserialized.date_optional_none, None,
+            "Expected deserialized date_optional_none to be None."
+        );
+
+        assert_eq!(
+            a_deserialized.date_optional_some,
+            Some(date),
+            "Expected deserialized date_optional_some to match the original."
+        );
+
+        assert_eq!(
+            a_deserialized.date_vector,
+            vec![date],
+            "Expected deserialized date_vector to match original."
+        );
     }
 
-    #[cfg(feature = "chrono-0_4")]
+    #[cfg(feature = "serde_with-3")]
     {
-        use std::str::FromStr;
+        #[serde_as]
         #[derive(Deserialize, Serialize)]
-        struct B {
-            #[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime_optional")]
-            pub date: Option<chrono::DateTime<chrono::Utc>>,
+        struct C {
+            #[serde_as(as = "bson_datetime::FromRfc3339String")]
+            pub date: String,
+
+            #[serde_as(as = "Option<bson_datetime::FromRfc3339String>")]
+            pub date_optional_none: Option<String>,
+
+            #[serde_as(as = "Option<bson_datetime::FromRfc3339String>")]
+            pub date_optional_some: Option<String>,
+
+            #[serde_as(as = "Vec<bson_datetime::FromRfc3339String>")]
+            pub date_vector: Vec<String>,
         }
 
-        let date = r#"
-    {
-        "date": {
-                "$date": {
-                    "$numberLong": "1591700287095"
-                }
+        let date = "2020-06-09T10:58:07.095Z";
+        let c = C {
+            date: date.to_string(),
+            date_optional_none: None,
+            date_optional_some: Some(date.to_string()),
+            date_vector: vec![date.to_string()],
+        };
+
+        // Serialize the struct to BSON
+        let doc = serialize_to_document(&c).unwrap();
+
+        // Validate serialized data
+        assert!(
+            doc.get_datetime("date").is_ok(),
+            "Expected serialized date to be a BSON DateTime."
+        );
+
+        assert_eq!(
+            doc.get("date_optional_none"),
+            Some(&Bson::Null),
+            "Expected serialized date_optional_none to be None."
+        );
+
+        let expected_date = DateTime::from_time_0_3(
+            OffsetDateTime::parse(date, &Rfc3339)
+                .expect("Failed to parse date string into DateTime."),
+        );
+
+        match doc.get("date_optional_some") {
+            Some(Bson::DateTime(value)) => {
+                assert_eq!(
+                    *value, expected_date,
+                    "Expected serialized date_optional_some to match original."
+                )
+            }
+            _ => panic!("Expected serialized date_optional_some to be a BSON String."),
         }
-    }"#;
-        let json: serde_json::Value = serde_json::from_str(date).unwrap();
-        let b: B = serde_json::from_value(json).unwrap();
-        let expected: Option<chrono::DateTime<chrono::Utc>> =
-            Some(chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap());
-        assert_eq!(b.date, expected);
-        let doc = serialize_to_document(&b).unwrap();
+
+        let date_vector = doc
+            .get_array("date_vector")
+            .expect("Expected serialized date_vector to be a BSON array.");
+        let expected_date_vector: Vec<Bson> = c
+            .date_vector
+            .into_iter()
+            .map(|dt| Bson::DateTime(DateTime::parse_rfc3339_str(dt).unwrap()))
+            .collect();
         assert_eq!(
-            Some(doc.get_datetime("date").unwrap().to_chrono()),
-            expected
+            date_vector, &expected_date_vector,
+            "Expected each serialized element in date_vector match the original."
+        );
+
+        // Deserialize the BSON back to the struct
+        let c_deserialized: C = deserialize_from_document(doc).unwrap();
+
+        // Validate deserialized data
+        assert_eq!(
+            c_deserialized.date,
+            date.to_string(),
+            "Expected deserialized date to match original."
+        );
+
+        assert_eq!(
+            c_deserialized.date_optional_none, None,
+            "Expected deserialized date_optional_none to be None."
+        );
+
+        assert_eq!(
+            c_deserialized.date_optional_some,
+            Some(date.to_string()),
+            "Expected deserialized date_optional_some to match original."
+        );
+
+        assert_eq!(
+            c_deserialized.date_vector,
+            vec![date.to_string()],
+            "Expected deserialized date_vector to match original."
+        );
+
+        // Validate serializing error case with an invalid DateTime string
+        let invalid_date = "invalid_date";
+        let bad_c = C {
+            date: invalid_date.to_string(),
+            date_optional_none: None,
+            date_optional_some: Some(invalid_date.to_string()),
+            date_vector: vec![invalid_date.to_string()],
+        };
+        let result = serialize_to_document(&bad_c);
+        assert!(
+            result.is_err(),
+            "Deserialization should fail for invalid DateTime strings"
+        );
+        let err_string = format!("{:?}", result.unwrap_err());
+        assert!(
+            err_string.contains("BSON error"),
+            "Expected error message to mention BSON error: {}",
+            err_string
         );
-        let b: B = deserialize_from_document(doc).unwrap();
-        assert_eq!(b.date, expected);
     }
+}
 
-    #[cfg(feature = "chrono-0_4")]
+#[test]
+fn test_oid_helpers() {
+    let _guard = LOCK.run_concurrently();
+
+    #[cfg(feature = "serde_with-3")]
     {
-        #[derive(Deserialize, Serialize)]
+        #[serde_as]
+        #[derive(Serialize, Deserialize)]
+        struct A {
+            #[serde_as(as = "object_id::FromHexString")]
+            oid: String,
+
+            #[serde_as(as = "Option<object_id::FromHexString>")]
+            oid_optional_none: Option<String>,
+
+            #[serde_as(as = "Option<object_id::FromHexString>")]
+            oid_optional_some: Option<String>,
+
+            #[serde_as(as = "Vec<object_id::FromHexString>")]
+            oid_vector: Vec<String>,
+        }
+
+        let oid = ObjectId::new();
+        let a = A {
+            oid: oid.to_string(),
+            oid_optional_none: None,
+            oid_optional_some: Some(oid.to_string()),
+            oid_vector: vec![oid.to_string()],
+        };
+
+        // Serialize the struct to BSON
+        let doc = serialize_to_document(&a).unwrap();
+
+        // Validate serialized data
+        assert_eq!(
+            doc.get_object_id("oid").unwrap(),
+            oid,
+            "Expected serialized oid to match original ObjectId."
+        );
+
+        assert_eq!(
+            doc.get("oid_optional_none"),
+            Some(&Bson::Null),
+            "Expected serialized oid_optional_none to be None."
+        );
+
+        match doc.get("oid_optional_some") {
+            Some(Bson::ObjectId(value)) => {
+                assert_eq!(
+                    *value, oid,
+                    "Expected serialized oid_optional_some to match original ObjectId."
+                )
+            }
+            _ => {
+                panic!("Expected serialized oid_optional_some to be a BSON ObjectId.")
+            }
+        }
+
+        let oid_vector = doc
+            .get_array("oid_vector")
+            .expect("Expected serialized oid_vector to be a BSON array.");
+        let expected_oid_vector: Vec<Bson> = a
+            .oid_vector
+            .into_iter()
+            .map(|oid| Bson::ObjectId(ObjectId::parse_str(oid).unwrap()))
+            .collect();
+        assert_eq!(
+            oid_vector, &expected_oid_vector,
+            "Expected each serialized element in oid_vector match the original."
+        );
+
+        // Deserialize the BSON back to the struct
+        let a_deserialized: A = deserialize_from_document(doc).unwrap();
+
+        // Validate deserialized data
+        assert_eq!(
+            a_deserialized.oid,
+            oid.to_string(),
+            "Expected deserialized oid to match the original."
+        );
+
+        assert_eq!(
+            a_deserialized.oid_optional_some,
+            Some(oid.to_string()),
+            "Expected deserialized oid_optional_some to match the original."
+        );
+
+        assert_eq!(
+            a_deserialized.oid_vector,
+            vec![oid.to_string()],
+            "Expected deserialized oid_vector to match the original."
+        );
+
+        // Validate serializing error case with an invalid ObjectId string
+        let invalid_oid = "invalid_oid";
+        let bad_a = A {
+            oid: invalid_oid.to_string(),
+            oid_optional_none: None,
+            oid_optional_some: Some(invalid_oid.to_string()),
+            oid_vector: vec![invalid_oid.to_string()],
+        };
+        let result = serialize_to_document(&bad_a);
+        assert!(
+            result.is_err(),
+            "Deserialization should fail for invalid ObjectId strings"
+        );
+        let err_string = format!("{:?}", result.unwrap_err());
+        assert!(
+            err_string.contains("BSON error"),
+            "Expected error message to mention BSON error: {}",
+            err_string
+        );
+
+        #[serde_as]
+        #[derive(Serialize, Deserialize, Debug)]
         struct B {
-            #[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime_optional")]
-            pub date: Option<chrono::DateTime<chrono::Utc>>,
+            #[serde_as(as = "object_id::AsHexString")]
+            oid: ObjectId,
+
+            #[serde_as(as = "Option<object_id::AsHexString>")]
+            oid_optional_none: Option<ObjectId>,
+
+            #[serde_as(as = "Option<object_id::AsHexString>")]
+            oid_optional_some: Option<ObjectId>,
+
+            #[serde_as(as = "Vec<object_id::AsHexString>")]
+            oid_vector: Vec<ObjectId>,
         }
 
-        let date = r#"
-    {
-        "date": null
-    }"#;
-        let json: serde_json::Value = serde_json::from_str(date).unwrap();
-        let b: B = serde_json::from_value(json).unwrap();
-        let expected = None;
-        assert_eq!(b.date, expected);
+        let oid = ObjectId::new();
+        let b = B {
+            oid,
+            oid_optional_none: None,
+            oid_optional_some: Some(oid),
+            oid_vector: vec![oid],
+        };
+
+        // Serialize the struct to BSON
         let doc = serialize_to_document(&b).unwrap();
-        assert_eq!(None, expected);
-        let b: B = deserialize_from_document(doc).unwrap();
-        assert_eq!(b.date, expected);
-    }
 
-    #[derive(Deserialize, Serialize)]
-    struct C {
-        #[serde(with = "rfc3339_string_as_bson_datetime")]
-        pub date: String,
-    }
+        // Validate serialized data
+        assert_eq!(
+            doc.get_str("oid").unwrap(),
+            oid.to_hex(),
+            "Expected serialized oid to match original ObjectId as hex string."
+        );
 
-    let date = "2020-06-09T10:58:07.095Z";
-    let c = C {
-        date: date.to_string(),
-    };
-    let doc = serialize_to_document(&c).unwrap();
-    assert!(doc.get_datetime("date").is_ok());
-    let c: C = deserialize_from_document(doc).unwrap();
-    assert_eq!(c.date.as_str(), date);
-}
+        assert_eq!(
+            doc.get("oid_optional_none"),
+            Some(&Bson::Null),
+            "Expected serialized oid_optional_none to be None."
+        );
 
-#[test]
-fn test_oid_helpers() {
-    let _guard = LOCK.run_concurrently();
+        match doc.get("oid_optional_some") {
+            Some(Bson::String(value)) => {
+                assert_eq!(
+                    *value,
+                    oid.to_hex(),
+                    "Expected serialized oid_optional_some to match original ObjectId."
+                )
+            }
+            _ => {
+                panic!("Expected serialized oid_optional_some to be a BSON String.")
+            }
+        }
 
-    #[derive(Serialize, Deserialize)]
-    struct A {
-        #[serde(with = "hex_string_as_object_id")]
-        oid: String,
-    }
+        let oid_vector = doc
+            .get_array("oid_vector")
+            .expect("Expected serialized oid_vector to be a BSON array.");
+        let expected_oid_vector: Vec<Bson> = b
+            .oid_vector
+            .into_iter()
+            .map(|oid| Bson::String(oid.to_hex()))
+            .collect();
+        assert_eq!(
+            oid_vector, &expected_oid_vector,
+            "Expected each serialized element in oid_vector match the original."
+        );
 
-    let oid = ObjectId::new();
-    let a = A {
-        oid: oid.to_string(),
-    };
-    let doc = serialize_to_document(&a).unwrap();
-    assert_eq!(doc.get_object_id("oid").unwrap(), oid);
-    let a: A = deserialize_from_document(doc).unwrap();
-    assert_eq!(a.oid, oid.to_string());
+        // Deserialize the BSON back to the struct
+        let b_deserialized: B = deserialize_from_document(doc).unwrap();
+
+        // Validate deserialized data
+        assert_eq!(
+            b_deserialized.oid, oid,
+            "Expected deserialized oid to match the original."
+        );
+
+        assert_eq!(
+            b_deserialized.oid_optional_none, None,
+            "Expected deserialized oid_optional_none to be None."
+        );
+
+        assert_eq!(
+            b_deserialized.oid_optional_some,
+            Some(oid),
+            "Expected deserialized oid_optional_some to match the original."
+        );
+
+        assert_eq!(
+            b_deserialized.oid_vector,
+            vec![oid],
+            "Expected deserialized oid_vector to match the original.."
+        );
+
+        // Validate deserializing error case with an invalid ObjectId string
+        let invalid_doc = doc! {
+            "oid": "not_a_valid_oid",
+            "oid_optional_none": Bson::Null,
+            "oid_optional_some": "also_invalid_oid",
+            "oid_vector": ["bad1", "bad2"]
+        };
+        let result: Result<B, _> = deserialize_from_document(invalid_doc);
+        assert!(
+            result.is_err(),
+            "Deserialization should fail for invalid ObjectId strings"
+        );
+        let err_string = format!("{:?}", result.unwrap_err());
+        assert!(
+            err_string.contains("BSON error"),
+            "Expected error message to mention BSON error: {}",
+            err_string
+        );
+    }
 }
 
 #[test]
@@ -1026,22 +1445,6 @@ fn large_dates() {
     );
 }
 
-#[test]
-fn oid_as_hex_string() {
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Serialize)]
-    struct Foo {
-        #[serde(serialize_with = "serialize_object_id_as_hex_string")]
-        oid: ObjectId,
-    }
-
-    let oid = ObjectId::new();
-    let foo = Foo { oid };
-    let doc = serialize_to_document(&foo).unwrap();
-    assert_eq!(doc.get_str("oid").unwrap(), oid.to_hex());
-}
-
 #[test]
 fn fuzz_regression_00() {
     let buf: &[u8] = &[227, 0, 35, 4, 2, 0, 255, 255, 255, 127, 255, 255, 255, 47];

From 25ac200c59d66fa813134d0c9c2b8b2f9401968f Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 3 Jul 2025 12:27:59 -0400
Subject: [PATCH 132/156] RUST-1992 Introduce the `&CStr` and `CString` types
 for keys and regular expressions (#563)

---
 fuzz/generate_corpus.rs                      |   4 +-
 serde-tests/json.rs                          |  18 +-
 serde-tests/test.rs                          |  29 +--
 src/bson.rs                                  |  36 ++-
 src/de/raw.rs                                |   8 +-
 src/de/serde.rs                              |   5 +-
 src/extjson/de.rs                            |   2 +-
 src/extjson/models.rs                        |   4 +-
 src/macros.rs                                |  25 +-
 src/raw.rs                                   |  14 +-
 src/raw/array_buf.rs                         |  37 ++-
 src/raw/bson.rs                              |   8 +-
 src/raw/bson_ref.rs                          |  25 +-
 src/raw/cstr.rs                              | 258 +++++++++++++++++++
 src/raw/document.rs                          |  16 +-
 src/raw/document_buf.rs                      |  60 ++---
 src/raw/document_buf/raw_writer.rs           |  10 +-
 src/raw/iter.rs                              |  23 +-
 src/raw/serde/bson_visitor.rs                |   8 +-
 src/raw/serde/seeded_visitor.rs              |  10 +-
 src/raw/test.rs                              |  10 +-
 src/raw/test/append.rs                       | 200 +++++++-------
 src/raw/test/props.rs                        |   2 +-
 src/ser/raw.rs                               |  42 +--
 src/ser/raw/document_serializer.rs           |  12 +-
 src/ser/raw/value_serializer.rs              |  48 ++--
 src/ser/serde.rs                             |   4 +-
 src/tests/modules/bson.rs                    |  13 +-
 src/tests/modules/macros.rs                  |   5 +-
 src/tests/modules/ser.rs                     |   7 -
 src/tests/modules/serializer_deserializer.rs |   5 +-
 src/tests/serde.rs                           |   9 +-
 src/tests/spec/corpus.rs                     |   5 +-
 33 files changed, 614 insertions(+), 348 deletions(-)
 create mode 100644 src/raw/cstr.rs

diff --git a/fuzz/generate_corpus.rs b/fuzz/generate_corpus.rs
index 06b16f02..fe5d70b0 100644
--- a/fuzz/generate_corpus.rs
+++ b/fuzz/generate_corpus.rs
@@ -1,4 +1,4 @@
-use bson::{doc, Bson, Decimal128};
+use bson::{cstr, doc, Bson, Decimal128};
 use std::{
     fs,
     io::{Error, ErrorKind},
@@ -64,7 +64,7 @@ fn generate_type_marker_cases(dir: &Path) -> std::io::Result<()> {
         "bool": true,
         "date": bson::DateTime::now(),
         "null": Bson::Null,
-        "regex": Bson::RegularExpression(bson::Regex { pattern: "pattern".into(), options: "i".into() }),
+        "regex": Bson::RegularExpression(bson::Regex { pattern: cstr!("pattern").into(), options: cstr!("i").into() }),
         "int32": 123i32,
         "timestamp": bson::Timestamp { time: 12345, increment: 1 },
         "int64": 123i64,
diff --git a/serde-tests/json.rs b/serde-tests/json.rs
index 7d6d3b2d..8b12f014 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, RawArrayBuf, RawBson, RawDocumentBuf};
+use bson::{cstr, doc, Bson, JavaScriptCodeWithScope, RawArrayBuf, RawBson, RawDocumentBuf};
 
 use serde::{Deserialize, Serialize};
 
@@ -99,18 +99,18 @@ fn owned_raw_bson() {
     });
 
     let mut doc_buf = RawDocumentBuf::new();
-    doc_buf.append("a", "key").unwrap();
-    doc_buf.append("number", 12).unwrap();
-    doc_buf.append("bool", false).unwrap();
-    doc_buf.append("nu", RawBson::Null).unwrap();
+    doc_buf.append(cstr!("a"), "key");
+    doc_buf.append(cstr!("number"), 12);
+    doc_buf.append(cstr!("bool"), false);
+    doc_buf.append(cstr!("nu"), RawBson::Null);
 
     let mut array_buf = RawArrayBuf::new();
-    array_buf.push(1).unwrap();
-    array_buf.push("string").unwrap();
+    array_buf.push(1);
+    array_buf.push("string");
 
     let mut bson_doc = RawDocumentBuf::new();
-    bson_doc.append("first", true).unwrap();
-    bson_doc.append("second", "string").unwrap();
+    bson_doc.append(cstr!("first"), true);
+    bson_doc.append(cstr!("second"), "string");
 
     let expected = Foo {
         doc_buf,
diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index 9fbafdc4..00fe8f1c 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -18,6 +18,7 @@ use std::{
 };
 
 use bson::{
+    cstr,
     doc,
     oid::ObjectId,
     spec::BinarySubtype,
@@ -835,8 +836,8 @@ fn raw_regex() {
 
     let bytes = bson::serialize_to_vec(&doc! {
         "r": Regex {
-            pattern: "a[b-c]d".to_string(),
-            options: "ab".to_string(),
+            pattern: cstr!("a[b-c]d").into(),
+            options: cstr!("ab").into(),
         },
     })
     .expect("raw_regex");
@@ -927,8 +928,8 @@ impl AllTypes {
         };
         let date = DateTime::now();
         let regex = Regex {
-            pattern: "hello".to_string(),
-            options: "x".to_string(),
+            pattern: cstr!("hello").into(),
+            options: cstr!("x").into(),
         };
         let timestamp = Timestamp {
             time: 123,
@@ -1058,8 +1059,8 @@ fn all_raw_types_rmp() {
             scope: doc! { "x": 1 },
         },
         "regex": Regex {
-            pattern: "pattern".to_string(),
-            options: "opt".to_string()
+            pattern: cstr!("pattern").into(),
+            options: cstr!("opt").into()
         }
     })
     .unwrap();
@@ -1254,24 +1255,22 @@ fn owned_raw_types() {
 
     let f = Foo {
         subdoc: RawDocumentBuf::from_iter([
-            ("a key", RawBson::String("a value".to_string())),
-            ("an objectid", RawBson::ObjectId(oid)),
-            ("a date", RawBson::DateTime(dt)),
+            (cstr!("a key"), RawBson::String("a value".to_string())),
+            (cstr!("an objectid"), RawBson::ObjectId(oid)),
+            (cstr!("a date"), RawBson::DateTime(dt)),
             (
-                "code_w_scope",
+                cstr!("code_w_scope"),
                 RawBson::JavaScriptCodeWithScope(raw_code_w_scope.clone()),
             ),
-            ("decimal128", RawBson::Decimal128(d128)),
-        ])
-        .unwrap(),
+            (cstr!("decimal128"), RawBson::Decimal128(d128)),
+        ]),
         array: RawArrayBuf::from_iter([
             RawBson::String("a string".to_string()),
             RawBson::ObjectId(oid),
             RawBson::DateTime(dt),
             RawBson::JavaScriptCodeWithScope(raw_code_w_scope),
             RawBson::Decimal128(d128),
-        ])
-        .unwrap(),
+        ]),
     };
 
     let expected = doc! {
diff --git a/src/bson.rs b/src/bson.rs
index ab778734..7bcac566 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -31,7 +31,7 @@ use std::{
 use serde_json::{json, Value};
 
 pub use crate::document::Document;
-use crate::{base64, oid, spec::ElementType, Binary, Decimal128};
+use crate::{base64, oid, raw::CString, spec::ElementType, Binary, Decimal128};
 
 /// Possible BSON value types.
 #[derive(Clone, Default, PartialEq)]
@@ -268,6 +268,12 @@ impl From<String> for Bson {
     }
 }
 
+impl From<crate::raw::CString> for Bson {
+    fn from(a: crate::raw::CString) -> Bson {
+        Bson::String(a.into_string())
+    }
+}
+
 impl From<Document> for Bson {
     fn from(a: Document) -> Bson {
         Bson::Document(a)
@@ -480,14 +486,14 @@ impl Bson {
             Bson::Boolean(v) => json!(v),
             Bson::Null => Value::Null,
             Bson::RegularExpression(Regex { pattern, options }) => {
-                let mut chars: Vec<_> = options.chars().collect();
+                let mut chars: Vec<_> = options.as_str().chars().collect();
                 chars.sort_unstable();
 
                 let options: String = chars.into_iter().collect();
 
                 json!({
                     "$regularExpression": {
-                        "pattern": pattern,
+                        "pattern": pattern.into_string(),
                         "options": options,
                     }
                 })
@@ -619,7 +625,7 @@ impl Bson {
                 ref pattern,
                 ref options,
             }) => {
-                let mut chars: Vec<_> = options.chars().collect();
+                let mut chars: Vec<_> = options.as_str().chars().collect();
                 chars.sort_unstable();
 
                 let options: String = chars.into_iter().collect();
@@ -842,7 +848,9 @@ 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, options));
+                            if let Ok(regex) = Regex::from_strings(pattern, options) {
+                                return Bson::RegularExpression(regex);
+                            }
                         }
                     }
                 }
@@ -1147,7 +1155,7 @@ impl Timestamp {
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct Regex {
     /// The regex pattern to match.
-    pub pattern: String,
+    pub pattern: CString,
 
     /// The options for the regex.
     ///
@@ -1156,18 +1164,22 @@ pub struct Regex {
     /// 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: String,
+    pub options: CString,
 }
 
 impl Regex {
-    pub(crate) fn new(pattern: impl AsRef<str>, options: impl AsRef<str>) -> Self {
+    #[cfg(any(test, feature = "serde"))]
+    pub(crate) fn from_strings(
+        pattern: impl AsRef<str>,
+        options: impl AsRef<str>,
+    ) -> crate::error::Result<Self> {
         let mut chars: Vec<_> = options.as_ref().chars().collect();
         chars.sort_unstable();
         let options: String = chars.into_iter().collect();
-        Self {
-            pattern: pattern.as_ref().to_string(),
-            options,
-        }
+        Ok(Self {
+            pattern: pattern.as_ref().to_string().try_into()?,
+            options: options.try_into()?,
+        })
     }
 }
 
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 1739cbc1..4d3112cb 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -1306,15 +1306,15 @@ impl<'de> serde::de::Deserializer<'de> for &mut RegexAccess<'de> {
             RegexDeserializationStage::Pattern => {
                 self.stage = RegexDeserializationStage::Options;
                 match &self.re {
-                    BsonCow::Borrowed(re) => visitor.visit_borrowed_str(re.pattern),
-                    BsonCow::Owned(re) => visitor.visit_str(&re.pattern),
+                    BsonCow::Borrowed(re) => visitor.visit_borrowed_str(re.pattern.as_str()),
+                    BsonCow::Owned(re) => visitor.visit_str(re.pattern.as_str()),
                 }
             }
             RegexDeserializationStage::Options => {
                 self.stage = RegexDeserializationStage::Done;
                 match &self.re {
-                    BsonCow::Borrowed(re) => visitor.visit_borrowed_str(re.options),
-                    BsonCow::Owned(re) => visitor.visit_str(&re.options),
+                    BsonCow::Borrowed(re) => visitor.visit_borrowed_str(re.options.as_str()),
+                    BsonCow::Owned(re) => visitor.visit_str(re.options.as_str()),
                 }
             }
             RegexDeserializationStage::Done => {
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 88f3769c..47af21fc 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -442,7 +442,10 @@ impl<'de> Visitor<'de> for BsonVisitor {
 
                 "$regularExpression" => {
                     let re = visitor.next_value::<extjson::models::RegexBody>()?;
-                    return Ok(Bson::RegularExpression(Regex::new(re.pattern, re.options)));
+                    return Ok(Bson::RegularExpression(
+                        Regex::from_strings(re.pattern, re.options)
+                            .map_err(serde::de::Error::custom)?,
+                    ));
                 }
 
                 "$dbPointer" => {
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
index df5bbd4a..f5f1af3b 100644
--- a/src/extjson/de.rs
+++ b/src/extjson/de.rs
@@ -55,7 +55,7 @@ impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
 
         if obj.contains_key("$regularExpression") {
             let regex: models::Regex = serde_json::from_value(obj.into())?;
-            return Ok(regex.parse().into());
+            return Ok(regex.parse()?.into());
         }
 
         if obj.contains_key("$numberInt") {
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 31c137c7..88d3a2ca 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -122,8 +122,8 @@ pub(crate) struct RegexBody {
 }
 
 impl Regex {
-    pub(crate) fn parse(self) -> crate::Regex {
-        crate::Regex::new(self.body.pattern, self.body.options)
+    pub(crate) fn parse(self) -> crate::error::Result<crate::Regex> {
+        crate::Regex::from_strings(self.body.pattern, self.body.options)
     }
 }
 
diff --git a/src/macros.rs b/src/macros.rs
index 62d640b7..f1a18e78 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -240,12 +240,12 @@ macro_rules! rawbson {
 
     // Finished with trailing comma.
     (@array [$($elems:expr,)*]) => {
-        $crate::RawArrayBuf::from_iter(vec![$($elems,)*]).expect("invalid bson value")
+        $crate::RawArrayBuf::from_iter(vec![$($elems,)*])
     };
 
     // Finished without trailing comma.
     (@array [$($elems:expr),*]) => {
-        $crate::RawArrayBuf::from_iter(vec![$($elems),*]).expect("invalid bson value")
+        $crate::RawArrayBuf::from_iter(vec![$($elems),*])
     };
 
     // Next element is `null`.
@@ -291,15 +291,26 @@ macro_rules! rawbson {
     // 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).expect("invalid bson value");
+    // Insert the current entry with followed by trailing comma, with a key literal.
+    (@object $object:ident [$key:literal] ($value:expr) , $($rest:tt)*) => {{
+        $object.append($crate::raw::cstr!($key), $value);
+        $crate::rawbson!(@object $object () ($($rest)*) ($($rest)*));
+    }};
+
+    // Insert the current entry with followed by trailing comma, with a key expression.
+    (@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, with a key literal.
+    (@object $object:ident [$key:literal] ($value:expr)) => {
+        $object.append($crate::raw::cstr!($key), $value);
     };
 
-    // Insert the last entry without trailing comma.
+    // Insert the last entry without trailing comma, with a key expression.
     (@object $object:ident [$($key:tt)+] ($value:expr)) => {
-        $object.append(($($key)+), $value).expect("invalid bson value");
+        $object.append($($key)+, $value);
     };
 
     // Next value is `null`.
diff --git a/src/raw.rs b/src/raw.rs
index 3444a61d..769b6ce3 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -116,6 +116,7 @@ mod array;
 mod array_buf;
 mod bson;
 mod bson_ref;
+mod cstr;
 mod document;
 mod document_buf;
 mod iter;
@@ -142,6 +143,7 @@ pub use self::{
         RawJavaScriptCodeWithScopeRef,
         RawRegexRef,
     },
+    cstr::{assert_valid_cstr, cstr, validate_cstr, CStr, CString, IsValidCStr},
     document::RawDocument,
     document_buf::{BindRawBsonRef, BindValue, RawDocumentBuf},
     iter::{RawElement, RawIter},
@@ -316,15 +318,3 @@ pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
     buf.extend(s.as_bytes());
     buf.push(0);
 }
-
-pub(crate) fn write_cstring(buf: &mut Vec<u8>, s: &str) -> Result<()> {
-    if s.contains('\0') {
-        return Err(Error::malformed_bytes(format!(
-            "cstring with interior null: {:?}",
-            s
-        )));
-    }
-    buf.extend(s.as_bytes());
-    buf.push(0);
-    Ok(())
-}
diff --git a/src/raw/array_buf.rs b/src/raw/array_buf.rs
index d7e2068a..019c649c 100644
--- a/src/raw/array_buf.rs
+++ b/src/raw/array_buf.rs
@@ -53,19 +53,6 @@ impl RawArrayBuf {
         }
     }
 
-    #[allow(clippy::should_implement_trait)]
-    pub fn from_iter<B, I>(iter: I) -> crate::error::Result<Self>
-    where
-        B: BindRawBsonRef,
-        I: IntoIterator<Item = B>,
-    {
-        let mut array_buf = RawArrayBuf::new();
-        for item in iter {
-            array_buf.push(item)?;
-        }
-        Ok(array_buf)
-    }
-
     /// Construct a new [`RawArrayBuf`] from the provided [`Vec`] of bytes.
     ///
     /// This involves a traversal of the array to count the values.
@@ -78,14 +65,14 @@ impl RawArrayBuf {
     ///
     /// ```
     /// # use bson::error::Error;
-    /// use bson::raw::{RawArrayBuf, RawDocumentBuf};
+    /// use bson::raw::{cstr, 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");
+    /// doc.append(cstr!("a key"), "a value");
     /// array.push(doc.clone());
     ///
     /// let mut iter = array.into_iter();
@@ -102,10 +89,22 @@ impl RawArrayBuf {
     /// assert!(iter.next().is_none());
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn push(&mut self, value: impl BindRawBsonRef) -> crate::error::Result<()> {
-        self.inner.append(self.len.to_string(), value)?;
+    pub fn push(&mut self, value: impl BindRawBsonRef) {
+        self.inner.append(
+            super::CString::from_string_unchecked(self.len.to_string()),
+            value,
+        );
         self.len += 1;
-        Ok(())
+    }
+}
+
+impl<B: BindRawBsonRef> FromIterator<B> for RawArrayBuf {
+    fn from_iter<T: IntoIterator<Item = B>>(iter: T) -> Self {
+        let mut array_buf = RawArrayBuf::new();
+        for item in iter {
+            array_buf.push(item);
+        }
+        array_buf
     }
 }
 
@@ -200,7 +199,7 @@ impl TryFrom<crate::Array> for RawArrayBuf {
         let mut tmp = RawArrayBuf::new();
         for val in value {
             let raw: super::RawBson = val.try_into()?;
-            tmp.push(raw)?;
+            tmp.push(raw);
         }
         Ok(tmp)
     }
diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index fb2c7252..e07d8459 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -204,8 +204,8 @@ impl RawBson {
     pub fn as_regex(&self) -> Option<RawRegexRef<'_>> {
         match self {
             RawBson::RegularExpression(v) => Some(RawRegexRef {
-                pattern: v.pattern.as_str(),
-                options: v.options.as_str(),
+                pattern: v.pattern.as_ref(),
+                options: v.options.as_ref(),
             }),
             _ => None,
         }
@@ -289,8 +289,8 @@ impl RawBson {
             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(),
+                options: re.options.as_ref(),
+                pattern: re.pattern.as_ref(),
             }),
             RawBson::JavaScriptCode(c) => RawBsonRef::JavaScriptCode(c.as_str()),
             RawBson::JavaScriptCodeWithScope(code_w_scope) => {
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index a2847734..3b50f145 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -3,7 +3,7 @@ use std::convert::{TryFrom, TryInto};
 use super::{bson::RawBson, Error, RawArray, RawDocument, Result};
 use crate::{
     oid::{self, ObjectId},
-    raw::{write_cstring, write_string, RawJavaScriptCodeWithScope},
+    raw::{write_string, CStr, RawJavaScriptCodeWithScope},
     spec::{BinarySubtype, ElementType},
     Binary,
     Bson,
@@ -256,7 +256,13 @@ impl<'a> RawBsonRef<'a> {
             RawBsonRef::Boolean(b) => RawBson::Boolean(b),
             RawBsonRef::Null => RawBson::Null,
             RawBsonRef::RegularExpression(re) => {
-                RawBson::RegularExpression(Regex::new(re.pattern, re.options))
+                let mut chars: Vec<_> = re.options.as_str().chars().collect();
+                chars.sort_unstable();
+                let options: String = chars.into_iter().collect();
+                RawBson::RegularExpression(Regex {
+                    pattern: re.pattern.into(),
+                    options: super::CString::from_string_unchecked(options),
+                })
             }
             RawBsonRef::JavaScriptCode(c) => RawBson::JavaScriptCode(c.to_owned()),
             RawBsonRef::JavaScriptCodeWithScope(c_w_s) => {
@@ -287,7 +293,7 @@ impl<'a> RawBsonRef<'a> {
     }
 
     #[inline]
-    pub(crate) fn append_to(self, dest: &mut Vec<u8>) -> Result<()> {
+    pub(crate) fn append_to(self, dest: &mut Vec<u8>) {
         match self {
             Self::Int32(val) => dest.extend(val.to_le_bytes()),
             Self::Int64(val) => dest.extend(val.to_le_bytes()),
@@ -306,8 +312,8 @@ impl<'a> RawBsonRef<'a> {
             Self::Document(raw_document) => dest.extend(raw_document.as_bytes()),
             Self::Boolean(b) => dest.push(b as u8),
             Self::RegularExpression(re) => {
-                write_cstring(dest, re.pattern)?;
-                write_cstring(dest, re.options)?;
+                re.pattern.append_to(dest);
+                re.options.append_to(dest);
             }
             Self::JavaScriptCode(js) => write_string(dest, js),
             Self::JavaScriptCodeWithScope(code_w_scope) => {
@@ -327,7 +333,6 @@ impl<'a> RawBsonRef<'a> {
             }
             Self::Null | Self::Undefined | Self::MinKey | Self::MaxKey => {}
         }
-        Ok(())
     }
 }
 
@@ -592,7 +597,7 @@ impl<'a> From<&'a Binary> for RawBsonRef<'a> {
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct RawRegexRef<'a> {
     /// The regex pattern to match.
-    pub pattern: &'a str,
+    pub pattern: &'a CStr,
 
     /// The options for the regex.
     ///
@@ -601,7 +606,7 @@ pub struct RawRegexRef<'a> {
     /// 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,
+    pub options: &'a CStr,
 }
 
 #[cfg(feature = "serde")]
@@ -628,8 +633,8 @@ impl serde::Serialize for RawRegexRef<'_> {
     {
         #[derive(serde::Serialize)]
         struct BorrowedRegexBody<'a> {
-            pattern: &'a str,
-            options: &'a str,
+            pattern: &'a CStr,
+            options: &'a CStr,
         }
 
         let mut state = serializer.serialize_struct("$regularExpression", 1)?;
diff --git a/src/raw/cstr.rs b/src/raw/cstr.rs
new file mode 100644
index 00000000..842f872d
--- /dev/null
+++ b/src/raw/cstr.rs
@@ -0,0 +1,258 @@
+use core::str;
+
+use crate::error::{Error, Result};
+
+#[allow(rustdoc::invalid_rust_codeblocks)]
+/// A borrowed BSON-spec cstring: Zero or more UTF-8 encoded characters, excluding the nul byte.
+/// Can be constructed at compile-time via the [`cstr!`](crate::raw::cstr) macro or at run-time from
+/// a [`prim@str`] via [`TryFrom`].
+///
+/// Unlike [`std::ffi::CStr`], this is required to be valid UTF-8, and does not include the nul
+/// terminator in the buffer:
+/// ```
+/// // std::ffi::CStr accepts invalid UTF-8:
+/// let invalid: &std::ffi::CStr = c"\xc3\x28";
+/// ```
+/// ```compile_fail
+/// # use bson::raw::cstr;
+/// // bson::raw::CStr does not:
+/// let invalid: &bson::raw::CStr = cstr!("\xc3\x28");  // will not compile
+/// ```
+/// ```
+/// // &str accepts embedded nil characters:
+/// let invalid: &str = "foo\0bar";
+/// ```
+/// ```compile_fail
+/// # use bson::raw::cstr;
+/// // bson::raw::CStr does not:
+/// let invalid: &bson::raw::CStr = cstr!("foo\0bar");  // will not compile
+/// ```
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct CStr {
+    data: [u8],
+}
+
+impl<'a> TryFrom<&'a str> for &'a CStr {
+    type Error = Error;
+
+    fn try_from(value: &str) -> Result<&CStr> {
+        match validate_cstr(value) {
+            Some(cs) => Ok(cs),
+            None => Err(Error::malformed_bytes(format!(
+                "cstring with interior null: {:?}",
+                value,
+            ))),
+        }
+    }
+}
+
+impl CStr {
+    // Convenience shorthand for making the types of TryFrom line up
+    #[cfg(feature = "serde")]
+    pub(crate) fn from_str(value: &str) -> Result<&CStr> {
+        value.try_into()
+    }
+
+    const fn from_str_unchecked(value: &str) -> &Self {
+        // Safety: the conversion is safe because CStr is repr(transparent), and the deref is safe
+        // because the pointer came from a safe reference.
+        unsafe { &*(value.as_bytes() as *const [u8] as *const CStr) }
+    }
+
+    /// View the buffer as a Rust `&str`.
+    pub fn as_str(&self) -> &str {
+        // Safety: the only way to constrct a CStr is from a valid &str.
+        unsafe { str::from_utf8_unchecked(&self.data) }
+    }
+
+    /// The length in bytes of the buffer.
+    pub fn len(&self) -> usize {
+        self.as_str().len()
+    }
+
+    /// Whether the buffer contains zero bytes.
+    pub fn is_empty(&self) -> bool {
+        self.as_str().is_empty()
+    }
+
+    pub(crate) fn append_to(&self, buf: &mut Vec<u8>) {
+        buf.extend(&self.data);
+        buf.push(0);
+    }
+}
+
+impl PartialEq<&CStr> for &CStr {
+    fn eq(&self, other: &&CStr) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl std::borrow::ToOwned for CStr {
+    type Owned = CString;
+
+    fn to_owned(&self) -> Self::Owned {
+        self.into()
+    }
+}
+
+impl AsRef<CStr> for CStr {
+    fn as_ref(&self) -> &CStr {
+        self
+    }
+}
+
+impl AsRef<str> for CStr {
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::Serialize for &CStr {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        self.as_str().serialize(serializer)
+    }
+}
+
+#[doc(hidden)]
+#[diagnostic::on_unimplemented(message = "the string literal contains a zero byte")]
+pub trait ValidCStr {}
+#[doc(hidden)]
+pub struct IsValidCStr<const VALID: bool>;
+#[doc(hidden)]
+impl ValidCStr for IsValidCStr<true> {}
+
+#[doc(hidden)]
+pub const fn validate_cstr(text: &str) -> Option<&CStr> {
+    let bytes = text.as_bytes();
+    let mut i = 0;
+    while i < bytes.len() {
+        if bytes[i] == 0 {
+            return None;
+        }
+        i += 1;
+    }
+    Some(CStr::from_str_unchecked(text))
+}
+#[doc(hidden)]
+pub const fn assert_valid_cstr<T: ValidCStr>() {}
+
+#[allow(rustdoc::invalid_rust_codeblocks)]
+/// Construct a `'static &CStr`.  The validitiy will be verified at compile-time.
+/// ```
+/// # use bson::raw::{CStr, cstr};
+/// // A valid literal:
+/// let key: &CStr = cstr!("hello");
+/// ```
+/// ```compile_fail
+/// # use bson::raw::{CStr, cstr};
+/// // A literal with invalid UTF-8 will not compile:
+/// let key: &CStr = cstr!("\xc3\x28");
+/// ```
+/// ```compile_fail
+/// # use bson::raw::{CStr, cstr};
+/// // A literal with an embedded nil will not compile:
+/// let key: &CStr = cstr!("hel\0lo");
+/// ```
+#[macro_export]
+macro_rules! cstr {
+    ($text:literal) => {{
+        const VALIDATED: Option<&$crate::raw::CStr> = $crate::raw::validate_cstr($text);
+        const VALID: bool = VALIDATED.is_some();
+        $crate::raw::assert_valid_cstr::<$crate::raw::IsValidCStr<VALID>>();
+        VALIDATED.unwrap()
+    }};
+}
+pub use cstr;
+
+/// An owned BSON-spec cstring: Zero or more UTF-8 encoded characters, excluding the nul byte.
+/// `CString` is to `CStr` as [`String`] is to [`prim@str`].  Can be constructed from a [`CStr`] via
+/// [`ToOwned`]/[`Into`] or from a [`String`] or [`prim@str`] via [`TryFrom`].
+///
+/// Like `CStr`, this differs from [`std::ffi::CString`] in that it is required to be valid UTF-8,
+/// and does not include the nul terminator in the buffer.
+#[derive(Clone, Eq, PartialEq, Hash)]
+#[repr(transparent)]
+pub struct CString {
+    data: String,
+}
+
+impl TryFrom<String> for CString {
+    type Error = Error;
+
+    fn try_from(data: String) -> Result<Self> {
+        let _: &CStr = data.as_str().try_into()?;
+        Ok(Self { data })
+    }
+}
+
+impl TryFrom<&str> for CString {
+    type Error = Error;
+
+    fn try_from(data: &str) -> Result<Self> {
+        let cs: &CStr = data.try_into()?;
+        Ok(cs.into())
+    }
+}
+
+impl CString {
+    pub(crate) fn from_string_unchecked(data: String) -> Self {
+        Self { data }
+    }
+
+    /// Consume `self` to return the underlying `String`.
+    pub fn into_string(self) -> String {
+        self.data
+    }
+
+    /// View the buffer as a Rust `&str`.
+    pub fn as_str(&self) -> &str {
+        self.as_ref().as_str()
+    }
+}
+
+impl From<&CStr> for CString {
+    fn from(value: &CStr) -> Self {
+        Self {
+            data: value.as_str().into(),
+        }
+    }
+}
+
+impl AsRef<CStr> for CString {
+    fn as_ref(&self) -> &CStr {
+        CStr::from_str_unchecked(self.data.as_str())
+    }
+}
+
+impl std::fmt::Debug for CString {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.data.fmt(f)
+    }
+}
+
+impl std::fmt::Display for CString {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.data.fmt(f)
+    }
+}
+
+impl std::borrow::Borrow<CStr> for CString {
+    fn borrow(&self) -> &CStr {
+        self.as_ref()
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::Serialize for CString {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        self.data.serialize(serializer)
+    }
+}
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 4746d7c5..6e6d6335 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -5,6 +5,7 @@ use std::{
 
 use crate::{
     error::{Error, Result},
+    raw::CStr,
     Bson,
     DateTime,
     JavaScriptCodeWithScope,
@@ -387,18 +388,18 @@ impl RawDocument {
     /// the key corresponds to a value which isn't a regex.
     ///
     /// ```
-    /// use bson::{rawdoc, Regex};
+    /// use bson::{rawdoc, Regex, raw::cstr};
     ///
     /// let doc = rawdoc! {
     ///     "regex": Regex {
-    ///         pattern: r"end\s*$".into(),
-    ///         options: "i".into(),
+    ///         pattern: cstr!(r"end\s*$").into(),
+    ///         options: cstr!("i").into(),
     ///     },
     ///     "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, cstr!(r"end\s*$"));
+    /// assert_eq!(doc.get_regex("regex")?.options, cstr!("i"));
     /// assert!(doc.get_regex("bool").is_err());
     /// assert!(doc.get_regex("unknown").is_err());
     /// # Ok::<(), Box<dyn std::error::Error>>(())
@@ -505,9 +506,10 @@ impl RawDocument {
         }
     }
 
-    pub(crate) fn read_cstring_at(&self, start_at: usize) -> RawResult<&str> {
+    pub(crate) fn read_cstring_at(&self, start_at: usize) -> RawResult<&CStr> {
         let bytes = self.cstring_bytes_at(start_at)?;
-        try_to_str(bytes)
+        let s = try_to_str(bytes)?;
+        s.try_into()
     }
 
     /// Copy this into a [`Document`], returning an error if invalid BSON is encountered.
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 8c8ee3f4..c654727b 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -4,7 +4,10 @@ use std::{
     ops::Deref,
 };
 
-use crate::{raw::MIN_BSON_DOCUMENT_SIZE, Document};
+use crate::{
+    raw::{CStr, MIN_BSON_DOCUMENT_SIZE},
+    Document,
+};
 
 use super::{bson::RawBson, iter::Iter, RawBsonRef, RawDocument, RawIter, Result};
 
@@ -87,20 +90,6 @@ impl RawDocumentBuf {
         Self::decode_from_bytes(buf)
     }
 
-    #[allow(clippy::should_implement_trait)]
-    pub fn from_iter<S, B, I>(iter: I) -> Result<Self>
-    where
-        S: AsRef<str>,
-        B: BindRawBsonRef,
-        I: IntoIterator<Item = (S, B)>,
-    {
-        let mut buf = RawDocumentBuf::new();
-        for (k, v) in iter {
-            buf.append(k, v)?;
-        }
-        Ok(buf)
-    }
-
     /// Create a [`RawDocumentBuf`] from a [`Document`].
     ///
     /// ```
@@ -117,8 +106,9 @@ impl RawDocumentBuf {
     pub fn from_document(doc: impl Borrow<Document>) -> Result<Self> {
         let mut out = RawDocumentBuf::new();
         for (k, v) in doc.borrow() {
+            let k: &CStr = k.as_str().try_into()?;
             let val: RawBson = v.clone().try_into()?;
-            out.append(k, val)?;
+            out.append(k, val);
         }
         Ok(out)
     }
@@ -187,23 +177,23 @@ impl RawDocumentBuf {
     /// 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.
+    /// Keys can be a [`&CStr`](crate::raw::CStr) or [`CString`](crate::raw::CString).
     ///
     /// Values can be any type that can be converted to either borrowed or owned raw bson data; see
     /// the documentation for [BindRawBsonRef] for more details.
     /// ```
     /// # use bson::error::Error;
-    /// use bson::{doc, raw::{RawBsonRef, RawDocumentBuf}};
+    /// use bson::{doc, raw::{cstr, RawBsonRef, RawDocumentBuf}};
     ///
     /// let mut doc = RawDocumentBuf::new();
     /// // `&str` and `i32` both convert to `RawBsonRef`
-    /// doc.append("a string", "some string");
-    /// doc.append("an integer", 12_i32);
+    /// doc.append(cstr!("a string"), "some string");
+    /// doc.append(cstr!("an integer"), 12_i32);
     ///
     /// let mut subdoc = RawDocumentBuf::new();
-    /// subdoc.append("a key", true);
-    /// doc.append("a borrowed document", &subdoc);
-    /// doc.append("an owned document", subdoc);
+    /// subdoc.append(cstr!("a key"), true);
+    /// doc.append(cstr!("a borrowed document"), &subdoc);
+    /// doc.append(cstr!("an owned document"), subdoc);
     ///
     /// let expected = doc! {
     ///     "a string": "some string",
@@ -215,14 +205,19 @@ impl RawDocumentBuf {
     /// assert_eq!(doc.to_document()?, expected);
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn append(
-        &mut self,
-        key: impl AsRef<str>,
-        value: impl BindRawBsonRef,
-    ) -> crate::error::Result<()> {
-        value.bind(|value_ref| {
-            raw_writer::RawWriter::new(&mut self.data).append(key.as_ref(), value_ref)
-        })
+    pub fn append(&mut self, key: impl AsRef<CStr>, value: impl BindRawBsonRef) {
+        let key = key.as_ref();
+        value.bind(|value_ref| raw_writer::RawWriter::new(&mut self.data).append(key, value_ref));
+    }
+}
+
+impl<K: AsRef<CStr>, B: BindRawBsonRef> FromIterator<(K, B)> for RawDocumentBuf {
+    fn from_iter<T: IntoIterator<Item = (K, B)>>(iter: T) -> Self {
+        let mut buf = RawDocumentBuf::new();
+        for (k, v) in iter {
+            buf.append(k, v);
+        }
+        buf
     }
 }
 
@@ -287,8 +282,9 @@ impl TryFrom<Document> for RawDocumentBuf {
     fn try_from(doc: Document) -> std::result::Result<Self, Self::Error> {
         let mut out = RawDocumentBuf::new();
         for (k, v) in doc {
+            let k: &CStr = k.as_str().try_into()?;
             let val: RawBson = v.try_into()?;
-            out.append(k, val)?;
+            out.append(k, val);
         }
         Ok(out)
     }
diff --git a/src/raw/document_buf/raw_writer.rs b/src/raw/document_buf/raw_writer.rs
index dc550dbc..d988a823 100644
--- a/src/raw/document_buf/raw_writer.rs
+++ b/src/raw/document_buf/raw_writer.rs
@@ -1,4 +1,4 @@
-use crate::{raw::write_cstring, RawBsonRef};
+use crate::{raw::CStr, RawBsonRef};
 
 pub(super) struct RawWriter<'a> {
     data: &'a mut Vec<u8>,
@@ -9,19 +9,17 @@ impl<'a> RawWriter<'a> {
         Self { data }
     }
 
-    pub(super) fn append(&mut self, key: &str, value: RawBsonRef) -> crate::error::Result<()> {
+    pub(super) fn append(&mut self, key: &CStr, value: RawBsonRef) {
         let original_len = self.data.len();
         self.data[original_len - 1] = value.element_type() as u8;
 
-        write_cstring(self.data, key)?;
-        value.append_to(self.data)?;
+        key.append_to(self.data);
+        value.append_to(self.data);
 
         // append trailing null byte
         self.data.push(0);
         // update length
         let new_len = (self.data.len() as i32).to_le_bytes();
         self.data[0..4].copy_from_slice(&new_len);
-
-        Ok(())
     }
 }
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 6355917e..7516c3c0 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -2,7 +2,7 @@ use std::convert::TryInto;
 
 use crate::{
     oid::ObjectId,
-    raw::{Error, Result, MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE},
+    raw::{CStr, Error, Result, MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE},
     spec::{BinarySubtype, ElementType},
     Bson,
     DateTime,
@@ -50,7 +50,7 @@ impl<'a> Iterator for Iter<'a> {
         match self.inner.next() {
             Some(Ok(elem)) => match elem.value() {
                 Err(e) => Some(Err(e)),
-                Ok(value) => Some(Ok((elem.key, value))),
+                Ok(value) => Some(Ok((elem.key.as_str(), value))),
             },
             Some(Err(e)) => Some(Err(e)),
             None => None,
@@ -111,7 +111,7 @@ impl<'a> RawIter<'a> {
 
 #[derive(Clone)]
 pub struct RawElement<'a> {
-    key: &'a str,
+    key: &'a CStr,
     kind: ElementType,
     doc: &'a RawDocument,
     start_at: usize,
@@ -145,9 +145,11 @@ impl TryInto<Bson> for RawElement<'_> {
 impl<'a> RawElement<'a> {
     #[cfg(feature = "serde")]
     pub(crate) fn toplevel(bytes: &'a [u8]) -> Result<Self> {
+        use crate::raw::cstr;
+
         let doc = RawDocument::decode_from_bytes(bytes)?;
         Ok(Self {
-            key: "TOPLEVEL",
+            key: cstr!("TOPLEVEL"),
             kind: ElementType::EmbeddedDocument,
             doc,
             start_at: 0,
@@ -160,7 +162,7 @@ impl<'a> RawElement<'a> {
     }
 
     pub fn key(&self) -> &'a str {
-        self.key
+        self.key.as_str()
     }
 
     pub fn element_type(&self) -> ElementType {
@@ -305,11 +307,12 @@ impl<'a> RawElement<'a> {
                     String::from_utf8_lossy(self.doc.cstring_bytes_at(self.start_at)?).into_owned();
                 let pattern_len = pattern.len();
                 Utf8LossyBson::RegularExpression(crate::Regex {
-                    pattern,
+                    pattern: pattern.try_into()?,
                     options: String::from_utf8_lossy(
                         self.doc.cstring_bytes_at(self.start_at + pattern_len + 1)?,
                     )
-                    .into_owned(),
+                    .into_owned()
+                    .try_into()?,
                 })
             }
             _ => return Ok(None),
@@ -317,7 +320,7 @@ impl<'a> RawElement<'a> {
     }
 
     fn malformed_error(&self, e: impl ToString) -> Error {
-        Error::malformed_bytes(e).with_key(self.key)
+        Error::malformed_bytes(e).with_key(self.key.as_str())
     }
 
     pub(crate) fn slice(&self) -> &'a [u8] {
@@ -344,7 +347,7 @@ impl<'a> RawElement<'a> {
         Ok(ObjectId::from_bytes(
             self.doc.as_bytes()[start_at..(start_at + 12)]
                 .try_into()
-                .map_err(|e| Error::malformed_bytes(e).with_key(self.key))?,
+                .map_err(|e| Error::malformed_bytes(e).with_key(self.key.as_str()))?,
         ))
     }
 }
@@ -443,7 +446,7 @@ impl<'a> Iterator for RawIter<'a> {
             }),
             Err(error) => {
                 self.valid = false;
-                Err(error.with_key(key))
+                Err(error.with_key(key.as_str()))
             }
         })
     }
diff --git a/src/raw/serde/bson_visitor.rs b/src/raw/serde/bson_visitor.rs
index 8739321e..436b873e 100644
--- a/src/raw/serde/bson_visitor.rs
+++ b/src/raw/serde/bson_visitor.rs
@@ -84,14 +84,14 @@ impl OwnedOrBorrowedRawBsonVisitor {
                 match (body.pattern, body.options) {
                     (Cow::Borrowed(p), Cow::Borrowed(o)) => {
                         RawBsonRef::RegularExpression(RawRegexRef {
-                            pattern: p,
-                            options: o,
+                            pattern: p.try_into().map_err(A::Error::custom)?,
+                            options: o.try_into().map_err(A::Error::custom)?,
                         })
                         .into()
                     }
                     (p, o) => RawBson::RegularExpression(Regex {
-                        pattern: p.into_owned(),
-                        options: o.into_owned(),
+                        pattern: p.into_owned().try_into().map_err(A::Error::custom)?,
+                        options: o.into_owned().try_into().map_err(A::Error::custom)?,
                     })
                     .into(),
                 }
diff --git a/src/raw/serde/seeded_visitor.rs b/src/raw/serde/seeded_visitor.rs
index 8361421c..f6b0ae95 100644
--- a/src/raw/serde/seeded_visitor.rs
+++ b/src/raw/serde/seeded_visitor.rs
@@ -6,7 +6,7 @@ use serde::{
 };
 
 use crate::{
-    raw::{write_cstring, write_string, RAW_BSON_NEWTYPE},
+    raw::{write_string, RAW_BSON_NEWTYPE},
     spec::{BinarySubtype, ElementType},
     RawBson,
     RawBsonRef,
@@ -119,7 +119,10 @@ impl<'a, 'de> SeededVisitor<'a, 'de> {
 
     /// Appends a cstring to the buffer. Returns an error if the given string contains a null byte.
     fn append_cstring(&mut self, key: &str) -> Result<(), String> {
-        write_cstring(self.buffer.get_owned_buffer(), key).map_err(|e| e.to_string())
+        crate::raw::CStr::from_str(key)
+            .map_err(|e| e.to_string())?
+            .append_to(self.buffer.get_owned_buffer());
+        Ok(())
     }
 
     /// Appends a string and its length to the buffer.
@@ -273,8 +276,7 @@ impl<'de> Visitor<'de> for SeededVisitor<'_, 'de> {
                     // Cases that don't
                     _ => {
                         let bson = bson.as_ref();
-                        bson.append_to(self.buffer.get_owned_buffer())
-                            .map_err(A::Error::custom)?;
+                        bson.append_to(self.buffer.get_owned_buffer());
                         Ok(bson.element_type())
                     }
                 }
diff --git a/src/raw/test.rs b/src/raw/test.rs
index b651004d..ef28f456 100644
--- a/src/raw/test.rs
+++ b/src/raw/test.rs
@@ -104,7 +104,7 @@ fn rawdoc_to_doc() {
         "boolean": true,
         "datetime": DateTime::now(),
         "null": RawBson::Null,
-        "regex": Regex { pattern: String::from(r"end\s*$"), options: String::from("i")},
+        "regex": Regex { pattern: cstr!(r"end\s*$").into(), options: cstr!("i").into()},
         "javascript": RawBson::JavaScriptCode(String::from("console.log(console);")),
         "symbol": RawBson::Symbol(String::from("artist-formerly-known-as")),
         "javascript_with_scope": RawJavaScriptCodeWithScope {
@@ -267,7 +267,7 @@ fn null() {
 #[test]
 fn regex() {
     let rawdoc = rawdoc! {
-        "regex": Regex { pattern: String::from(r"end\s*$"), options: String::from("i")},
+        "regex": Regex { pattern: cstr!(r"end\s*$").into(), options: cstr!("i").into()},
     };
     let regex = rawdoc
         .get("regex")
@@ -275,8 +275,8 @@ fn regex() {
         .expect("no key regex")
         .as_regex()
         .expect("was not regex");
-    assert_eq!(regex.pattern, r"end\s*$");
-    assert_eq!(regex.options, "i");
+    assert_eq!(regex.pattern, cstr!(r"end\s*$"));
+    assert_eq!(regex.options, cstr!("i"));
 }
 #[test]
 fn javascript() {
@@ -388,7 +388,7 @@ fn document_iteration() {
         "boolean": true,
         "datetime": DateTime::now(),
         "null": RawBson::Null,
-        "regex": Regex { pattern: String::from(r"end\s*$"), options: String::from("i") },
+        "regex": Regex { pattern: cstr!(r"end\s*$").into(), options: cstr!("i").into() },
         "javascript": RawBson::JavaScriptCode(String::from("console.log(console);")),
         "symbol": RawBson::Symbol(String::from("artist-formerly-known-as")),
         "javascript_with_scope": RawJavaScriptCodeWithScope {
diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs
index fdaeef7f..e530ab7f 100644
--- a/src/raw/test/append.rs
+++ b/src/raw/test/append.rs
@@ -1,6 +1,6 @@
 use crate::{
     oid::ObjectId,
-    raw::RawJavaScriptCodeWithScope,
+    raw::{cstr, RawJavaScriptCodeWithScope},
     spec::BinarySubtype,
     tests::LOCK,
     Binary,
@@ -19,13 +19,10 @@ use crate::{
 
 use pretty_assertions::assert_eq;
 
-fn append_test(
-    expected: Document,
-    append: impl FnOnce(&mut RawDocumentBuf) -> crate::error::Result<()>,
-) {
+fn append_test(expected: Document, append: impl FnOnce(&mut RawDocumentBuf)) {
     let bytes = expected.encode_to_vec().unwrap();
     let mut buf = RawDocumentBuf::new();
-    assert!(append(&mut buf).is_ok());
+    append(&mut buf);
     assert_eq!(buf.as_bytes(), bytes);
 }
 
@@ -37,10 +34,9 @@ fn i32() {
         "c": 0_i32
     };
     append_test(expected, |doc| {
-        doc.append("a", -1_i32)?;
-        doc.append("b", 123_i32)?;
-        doc.append("c", 0_i32)?;
-        Ok(())
+        doc.append(cstr!("a"), -1_i32);
+        doc.append(cstr!("b"), 123_i32);
+        doc.append(cstr!("c"), 0_i32);
     });
 }
 
@@ -52,10 +48,9 @@ fn i64() {
         "c": 0_i64
     };
     append_test(expected, |doc| {
-        doc.append("a", -1_i64)?;
-        doc.append("b", 123_i64)?;
-        doc.append("c", 0_i64)?;
-        Ok(())
+        doc.append(cstr!("a"), -1_i64);
+        doc.append(cstr!("b"), 123_i64);
+        doc.append(cstr!("c"), 0_i64);
     });
 }
 
@@ -68,11 +63,10 @@ fn str() {
         "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")?;
-        Ok(())
+        doc.append(cstr!("first"), "the quick");
+        doc.append(cstr!("second"), "brown fox");
+        doc.append(cstr!("third"), "jumped over");
+        doc.append(cstr!("last"), "the lazy sheep dog");
     });
 }
 
@@ -86,12 +80,11 @@ fn double() {
         "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)?;
-        Ok(())
+        doc.append(cstr!("positive"), 12.5);
+        doc.append(cstr!("0"), 0.0);
+        doc.append(cstr!("negative"), -123.24);
+        doc.append(cstr!("nan"), f64::NAN);
+        doc.append(cstr!("inf"), f64::INFINITY);
     });
 }
 
@@ -102,9 +95,8 @@ fn boolean() {
         "false": false,
     };
     append_test(expected, |doc| {
-        doc.append("true", true)?;
-        doc.append("false", false)?;
-        Ok(())
+        doc.append(cstr!("true"), true);
+        doc.append(cstr!("false"), false);
     });
 }
 
@@ -113,7 +105,7 @@ fn null() {
     let expected = doc! {
         "null": null,
     };
-    append_test(expected, |doc| doc.append("null", RawBson::Null));
+    append_test(expected, |doc| doc.append(cstr!("null"), RawBson::Null));
 }
 
 #[test]
@@ -126,12 +118,11 @@ fn document() {
         }
     };
     append_test(expected, |doc| {
-        doc.append("empty", RawDocumentBuf::new())?;
+        doc.append(cstr!("empty"), RawDocumentBuf::new());
         let mut buf = RawDocumentBuf::new();
-        buf.append("a", 1_i32)?;
-        buf.append("b", true)?;
-        doc.append("subdoc", buf)?;
-        Ok(())
+        buf.append(cstr!("a"), 1_i32);
+        buf.append(cstr!("b"), true);
+        doc.append(cstr!("subdoc"), buf);
     });
 }
 
@@ -147,16 +138,15 @@ fn array() {
         ]
     };
     append_test(expected, |doc| {
-        doc.append("empty", RawArrayBuf::new())?;
+        doc.append(cstr!("empty"), RawArrayBuf::new());
         let mut buf = RawArrayBuf::new();
-        buf.push(true)?;
-        buf.push("string")?;
+        buf.push(true);
+        buf.push("string");
         let mut subdoc = RawDocumentBuf::new();
-        subdoc.append("a", "subdoc")?;
-        buf.push(subdoc)?;
-        buf.push(123_i32)?;
-        doc.append("array", buf)?;
-        Ok(())
+        subdoc.append(cstr!("a"), "subdoc");
+        buf.push(subdoc);
+        buf.push(123_i32);
+        doc.append(cstr!("array"), buf);
     });
 }
 
@@ -168,7 +158,7 @@ fn oid() {
     let expected = doc! {
         "oid": oid,
     };
-    append_test(expected, |doc| doc.append("oid", oid));
+    append_test(expected, |doc| doc.append(cstr!("oid"), oid));
 }
 
 #[test]
@@ -182,9 +172,8 @@ fn datetime() {
     };
 
     append_test(expected, |doc| {
-        doc.append("now", dt)?;
-        doc.append("old", old)?;
-        Ok(())
+        doc.append(cstr!("now"), dt);
+        doc.append(cstr!("old"), old);
     });
 }
 
@@ -199,7 +188,7 @@ fn timestamp() {
         "ts": ts,
     };
 
-    append_test(expected, |doc| doc.append("ts", ts));
+    append_test(expected, |doc| doc.append(cstr!("ts"), ts));
 }
 
 #[test]
@@ -222,9 +211,8 @@ fn binary() {
     };
 
     append_test(expected, |doc| {
-        doc.append("generic", bin)?;
-        doc.append("binary_old", old)?;
-        Ok(())
+        doc.append(cstr!("generic"), bin);
+        doc.append(cstr!("binary_old"), old);
     });
 }
 
@@ -236,9 +224,8 @@ fn min_max_key() {
     };
 
     append_test(expected, |doc| {
-        doc.append("min", RawBson::MinKey)?;
-        doc.append("max", RawBson::MaxKey)?;
-        Ok(())
+        doc.append(cstr!("min"), RawBson::MinKey);
+        doc.append(cstr!("max"), RawBson::MaxKey);
     });
 }
 
@@ -248,17 +235,22 @@ fn undefined() {
         "undefined": Bson::Undefined,
     };
 
-    append_test(expected, |doc| doc.append("undefined", RawBson::Undefined));
+    append_test(expected, |doc| {
+        doc.append(cstr!("undefined"), RawBson::Undefined)
+    });
 }
 
 #[test]
 fn regex() {
     let expected = doc! {
-        "regex": Regex::new("some pattern", "abc"),
+        "regex": Regex::from_strings("some pattern", "abc").unwrap(),
     };
 
     append_test(expected, |doc| {
-        doc.append("regex", Regex::new("some pattern", "abc"))
+        doc.append(
+            cstr!("regex"),
+            Regex::from_strings("some pattern", "abc").unwrap(),
+        )
     });
 }
 
@@ -275,19 +267,21 @@ fn code() {
     };
 
     append_test(expected, |doc| {
-        doc.append("code", RawBson::JavaScriptCode("some code".to_string()))?;
+        doc.append(
+            cstr!("code"),
+            RawBson::JavaScriptCode("some code".to_string()),
+        );
 
         let mut scope = RawDocumentBuf::new();
-        scope.append("a", 1_i32)?;
-        scope.append("b", true)?;
+        scope.append(cstr!("a"), 1_i32);
+        scope.append(cstr!("b"), true);
         doc.append(
-            "code_w_scope",
+            cstr!("code_w_scope"),
             RawJavaScriptCodeWithScope {
                 code: "some code".to_string(),
                 scope,
             },
-        )?;
-        Ok(())
+        );
     });
 }
 
@@ -298,7 +292,7 @@ fn symbol() {
     };
 
     append_test(expected, |doc| {
-        doc.append("symbol", RawBson::Symbol("symbol".to_string()))
+        doc.append(cstr!("symbol"), RawBson::Symbol("symbol".to_string()))
     });
 }
 
@@ -317,7 +311,7 @@ fn dbpointer() {
 
     append_test(expected, |doc| {
         doc.append(
-            "symbol",
+            cstr!("symbol"),
             RawBson::DbPointer(DbPointer {
                 namespace: "ns".to_string(),
                 id,
@@ -333,7 +327,7 @@ fn decimal128() {
         "decimal": decimal
     };
 
-    append_test(expected, |doc| doc.append("decimal", decimal));
+    append_test(expected, |doc| doc.append(cstr!("decimal"), decimal));
 }
 
 #[test]
@@ -352,34 +346,33 @@ fn general() {
     };
 
     append_test(expected, |doc| {
-        doc.append("a", true)?;
-        doc.append("second key", 123.4)?;
-        doc.append("third", 15_i64)?;
-        doc.append("32", -100101_i32)?;
+        doc.append(cstr!("a"), true);
+        doc.append(cstr!("second key"), 123.4);
+        doc.append(cstr!("third"), 15_i64);
+        doc.append(cstr!("32"), -100101_i32);
 
         let mut subdoc = RawDocumentBuf::new();
-        subdoc.append("a", "subkey")?;
+        subdoc.append(cstr!("a"), "subkey");
 
         let mut subsubdoc = RawDocumentBuf::new();
-        subsubdoc.append("subdoc", dt)?;
-        subdoc.append("another", subsubdoc)?;
-        doc.append("subdoc", subdoc)?;
+        subsubdoc.append(cstr!("subdoc"), dt);
+        subdoc.append(cstr!("another"), subsubdoc);
+        doc.append(cstr!("subdoc"), subdoc);
 
         let mut array = RawArrayBuf::new();
-        array.push(1_i64)?;
-        array.push(true)?;
+        array.push(1_i64);
+        array.push(true);
 
         let mut array_subdoc = RawDocumentBuf::new();
-        array_subdoc.append("doc", 23_i64)?;
-        array.push(array_subdoc)?;
+        array_subdoc.append(cstr!("doc"), 23_i64);
+        array.push(array_subdoc);
 
         let mut sub_array = RawArrayBuf::new();
-        sub_array.push("another")?;
-        sub_array.push("array")?;
-        array.push(sub_array)?;
+        sub_array.push("another");
+        sub_array.push("array");
+        array.push(sub_array);
 
-        doc.append("array", array)?;
-        Ok(())
+        doc.append(cstr!("array"), array);
     });
 }
 
@@ -387,25 +380,18 @@ fn general() {
 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".to_string())),
-                        ])
-                        .unwrap(),
-                    ),
-                ])
-                .unwrap(),
-            ),
+            cstr!("array"),
+            RawBson::Array(RawArrayBuf::from_iter([
+                RawBson::Boolean(true),
+                RawBson::Document(RawDocumentBuf::from_iter([
+                    (cstr!("ok"), RawBson::Boolean(false)),
+                    (cstr!("other"), RawBson::String("hello".to_string())),
+                ])),
+            ])),
         ),
-        ("bool", RawBson::Boolean(true)),
-        ("string", RawBson::String("some string".to_string())),
-    ])
-    .unwrap();
+        (cstr!("bool"), RawBson::Boolean(true)),
+        (cstr!("string"), RawBson::String("some string".to_string())),
+    ]);
 
     let doc = doc! {
         "array": [
@@ -420,22 +406,22 @@ fn from_iter() {
     };
 
     let expected = doc! { "expected": doc };
-    append_test(expected, |doc| doc.append("expected", doc_buf));
+    append_test(expected, |doc| doc.append(cstr!("expected"), doc_buf));
 }
 
 #[test]
 fn array_buf() {
     let mut arr_buf = RawArrayBuf::new();
-    arr_buf.push(true).unwrap();
+    arr_buf.push(true);
 
     let mut doc_buf = RawDocumentBuf::new();
-    doc_buf.append("x", 3_i32).unwrap();
-    doc_buf.append("string", "string").unwrap();
-    arr_buf.push(doc_buf).unwrap();
+    doc_buf.append(cstr!("x"), 3_i32);
+    doc_buf.append(cstr!("string"), "string");
+    arr_buf.push(doc_buf);
 
     let mut sub_arr = RawArrayBuf::new();
-    sub_arr.push("a string").unwrap();
-    arr_buf.push(sub_arr).unwrap();
+    sub_arr.push("a string");
+    arr_buf.push(sub_arr);
 
     let arr = rawbson!([
         true,
diff --git a/src/raw/test/props.rs b/src/raw/test/props.rs
index 6f0157d2..4b5918ff 100644
--- a/src/raw/test/props.rs
+++ b/src/raw/test/props.rs
@@ -22,7 +22,7 @@ pub(crate) fn arbitrary_bson() -> impl Strategy<Value = Bson> {
         any::<i32>().prop_map(Bson::Int32),
         any::<i64>().prop_map(Bson::Int64),
         any::<(String, String)>().prop_map(|(pattern, options)| {
-            Bson::RegularExpression(Regex::new(pattern, options))
+            Bson::RegularExpression(Regex::from_strings(pattern, options).unwrap())
         }),
         any::<[u8; 12]>().prop_map(|bytes| Bson::ObjectId(crate::oid::ObjectId::from_bytes(bytes))),
         (arbitrary_binary_subtype(), any::<Vec<u8>>()).prop_map(|(subtype, bytes)| {
diff --git a/src/ser/raw.rs b/src/ser/raw.rs
index c376c479..73aec059 100644
--- a/src/ser/raw.rs
+++ b/src/ser/raw.rs
@@ -9,7 +9,7 @@ use serde::{
 use self::value_serializer::{ValueSerializer, ValueType};
 
 use crate::{
-    raw::{write_cstring, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
+    raw::{CStr, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE},
     ser::{Error, Result},
     serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
@@ -108,7 +108,7 @@ impl Serializer {
 
     fn serialize_raw(&mut self, v: RawBsonRef) -> Result<()> {
         self.update_element_type(v.element_type())?;
-        v.append_to(&mut self.bytes)?;
+        v.append_to(&mut self.bytes);
         Ok(())
     }
 }
@@ -290,7 +290,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
         T: serde::Serialize + ?Sized,
     {
         self.update_element_type(ElementType::EmbeddedDocument)?;
-        let mut d = DocumentSerializer::start(&mut *self)?;
+        let mut d = DocumentSerializer::start(&mut *self);
         d.serialize_entry(variant, value)?;
         d.end_doc()?;
         Ok(())
@@ -299,7 +299,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     #[inline]
     fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
         self.update_element_type(ElementType::Array)?;
-        DocumentSerializer::start(&mut *self)
+        Ok(DocumentSerializer::start(&mut *self))
     }
 
     #[inline]
@@ -325,13 +325,17 @@ impl<'a> serde::Serializer for &'a mut Serializer {
         _len: usize,
     ) -> Result<Self::SerializeTupleVariant> {
         self.update_element_type(ElementType::EmbeddedDocument)?;
-        VariantSerializer::start(&mut *self, variant, VariantInnerType::Tuple)
+        Ok(VariantSerializer::start(
+            &mut *self,
+            variant.try_into()?,
+            VariantInnerType::Tuple,
+        ))
     }
 
     #[inline]
     fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
         self.update_element_type(ElementType::EmbeddedDocument)?;
-        DocumentSerializer::start(&mut *self)
+        Ok(DocumentSerializer::start(&mut *self))
     }
 
     #[inline]
@@ -360,7 +364,7 @@ impl<'a> serde::Serializer for &'a mut Serializer {
         )?;
         match value_type {
             Some(vt) => Ok(StructSerializer::Value(ValueSerializer::new(self, vt))),
-            None => Ok(StructSerializer::Document(DocumentSerializer::start(self)?)),
+            None => Ok(StructSerializer::Document(DocumentSerializer::start(self))),
         }
     }
 
@@ -373,7 +377,11 @@ impl<'a> serde::Serializer for &'a mut Serializer {
         _len: usize,
     ) -> Result<Self::SerializeStructVariant> {
         self.update_element_type(ElementType::EmbeddedDocument)?;
-        VariantSerializer::start(&mut *self, variant, VariantInnerType::Struct)
+        Ok(VariantSerializer::start(
+            &mut *self,
+            variant.try_into()?,
+            VariantInnerType::Struct,
+        ))
     }
 }
 
@@ -431,32 +439,28 @@ pub(crate) struct VariantSerializer<'a> {
 }
 
 impl<'a> VariantSerializer<'a> {
-    fn start(
-        rs: &'a mut Serializer,
-        variant: &'static str,
-        inner_type: VariantInnerType,
-    ) -> Result<Self> {
+    fn start(rs: &'a mut Serializer, variant: &'static CStr, inner_type: VariantInnerType) -> Self {
         let doc_start = rs.bytes.len();
         // write placeholder length for document, will be updated at end
         static ZERO: RawBsonRef = RawBsonRef::Int32(0);
-        ZERO.append_to(&mut rs.bytes)?;
+        ZERO.append_to(&mut rs.bytes);
 
         let inner = match inner_type {
             VariantInnerType::Struct => ElementType::EmbeddedDocument,
             VariantInnerType::Tuple => ElementType::Array,
         };
         rs.bytes.push(inner as u8);
-        write_cstring(&mut rs.bytes, variant)?;
+        variant.append_to(&mut rs.bytes);
         let inner_start = rs.bytes.len();
         // write placeholder length for inner, will be updated at end
-        ZERO.append_to(&mut rs.bytes)?;
+        ZERO.append_to(&mut rs.bytes);
 
-        Ok(Self {
+        Self {
             root_serializer: rs,
             num_elements_serialized: 0,
             doc_start,
             inner_start,
-        })
+        }
     }
 
     #[inline]
@@ -465,7 +469,7 @@ impl<'a> VariantSerializer<'a> {
         T: Serialize + ?Sized,
     {
         self.root_serializer.reserve_element_type();
-        write_cstring(&mut self.root_serializer.bytes, k)?;
+        CStr::from_str(k)?.append_to(&mut self.root_serializer.bytes);
         v.serialize(&mut *self.root_serializer)?;
 
         self.num_elements_serialized += 1;
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index 21587da6..a2317eb7 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -2,7 +2,6 @@ use serde::{ser::Impossible, Serialize};
 
 use crate::{
     error::{Error, Result},
-    raw::write_cstring,
     RawBsonRef,
 };
 
@@ -20,14 +19,14 @@ pub(crate) struct DocumentSerializer<'a> {
 }
 
 impl<'a> DocumentSerializer<'a> {
-    pub(crate) fn start(rs: &'a mut Serializer) -> crate::ser::Result<Self> {
+    pub(crate) fn start(rs: &'a mut Serializer) -> Self {
         let start = rs.bytes.len();
-        RawBsonRef::Int32(0).append_to(&mut rs.bytes)?;
-        Ok(Self {
+        RawBsonRef::Int32(0).append_to(&mut rs.bytes);
+        Self {
             root_serializer: rs,
             num_keys_serialized: 0,
             start,
-        })
+        }
     }
 
     /// Serialize a document key using the provided closure.
@@ -258,7 +257,8 @@ impl serde::Serializer for KeySerializer<'_> {
 
     #[inline]
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
-        write_cstring(&mut self.root_serializer.bytes, v)
+        crate::raw::CStr::from_str(v)?.append_to(&mut self.root_serializer.bytes);
+        Ok(())
     }
 
     #[inline]
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index c57aa44f..3b661b00 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -51,7 +51,7 @@ enum SerializationStep {
     RegEx,
     RegExPattern,
     RegExOptions {
-        pattern: String,
+        pattern: crate::raw::CString,
     },
 
     Timestamp,
@@ -199,7 +199,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                 let increment = u32::try_from(v).map_err(Error::custom)?;
 
                 RawBsonRef::Timestamp(crate::Timestamp { time, increment })
-                    .append_to(&mut self.root_serializer.bytes)?;
+                    .append_to(&mut self.root_serializer.bytes);
 
                 Ok(())
             }
@@ -215,7 +215,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                     subtype: v.into(),
                     bytes,
                 };
-                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes);
                 self.state = SerializationStep::Done;
                 Ok(())
             }
@@ -258,11 +258,11 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::DateTimeNumberLong => {
                 let millis = v.parse().map_err(Error::custom)?;
                 RawBsonRef::DateTime(crate::DateTime::from_millis(millis))
-                    .append_to(&mut self.root_serializer.bytes)?;
+                    .append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::Oid => {
                 let oid = ObjectId::parse_str(v).map_err(Error::custom)?;
-                RawBsonRef::ObjectId(oid).append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::ObjectId(oid).append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::BinaryBytes => {
                 self.state = SerializationStep::BinarySubType {
@@ -274,10 +274,10 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                 let subtype: BinarySubtype = subtype_byte[0].into();
                 let bytes = &base64::decode(base64.as_str()).map_err(Error::custom)?;
                 let binary = RawBinaryRef { subtype, bytes };
-                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::Symbol => {
-                RawBsonRef::Symbol(v).append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::Symbol(v).append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::DbPointerRef => {
                 self.state = SerializationStep::DbPointerId { ns: v.to_owned() };
@@ -285,23 +285,26 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::DbPointerId { ns } => {
                 let id = ObjectId::parse_str(v).map_err(Error::custom)?;
                 RawBsonRef::DbPointer(crate::RawDbPointerRef { namespace: ns, id })
-                    .append_to(&mut self.root_serializer.bytes)?;
+                    .append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::RegExPattern => {
                 self.state = SerializationStep::RegExOptions {
-                    pattern: v.to_string(),
+                    pattern: v.to_string().try_into()?,
                 };
             }
             SerializationStep::RegExOptions { pattern } => {
                 let mut chars: Vec<_> = v.chars().collect();
                 chars.sort_unstable();
 
-                let options = &chars.into_iter().collect::<String>();
-                RawBsonRef::RegularExpression(crate::RawRegexRef { pattern, options })
-                    .append_to(&mut self.root_serializer.bytes)?;
+                let options = chars.into_iter().collect::<String>();
+                RawBsonRef::RegularExpression(crate::RawRegexRef {
+                    pattern: pattern.as_ref(),
+                    options: options.as_str().try_into()?,
+                })
+                .append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::Code => {
-                RawBsonRef::JavaScriptCode(v).append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::JavaScriptCode(v).append_to(&mut self.root_serializer.bytes);
             }
             SerializationStep::CodeWithScopeCode => {
                 self.state = SerializationStep::CodeWithScopeScope {
@@ -324,7 +327,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
         match self.state {
             SerializationStep::Decimal128Value => {
                 let dec = crate::Decimal128::from_bytes(v.try_into().map_err(Error::custom)?);
-                RawBsonRef::Decimal128(dec).append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::Decimal128(dec).append_to(&mut self.root_serializer.bytes);
                 Ok(())
             }
             SerializationStep::BinaryBytes => {
@@ -336,8 +339,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                     code,
                     scope: RawDocument::decode_from_bytes(v).map_err(Error::custom)?,
                 };
-                RawBsonRef::JavaScriptCodeWithScope(raw)
-                    .append_to(&mut self.root_serializer.bytes)?;
+                RawBsonRef::JavaScriptCodeWithScope(raw).append_to(&mut self.root_serializer.bytes);
                 self.state = SerializationStep::Done;
                 Ok(())
             }
@@ -445,9 +447,9 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     #[inline]
     fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
         match self.state {
-            SerializationStep::CodeWithScopeScope { ref code, raw } if !raw => {
-                CodeWithScopeSerializer::start(code.as_str(), self.root_serializer)
-            }
+            SerializationStep::CodeWithScopeScope { ref code, raw } if !raw => Ok(
+                CodeWithScopeSerializer::start(code.as_str(), self.root_serializer),
+            ),
             _ => Err(self.invalid_step("map")),
         }
     }
@@ -610,13 +612,13 @@ pub(crate) struct CodeWithScopeSerializer<'a> {
 
 impl<'a> CodeWithScopeSerializer<'a> {
     #[inline]
-    fn start(code: &str, rs: &'a mut Serializer) -> Result<Self> {
+    fn start(code: &str, rs: &'a mut Serializer) -> Self {
         let start = rs.bytes.len();
-        RawBsonRef::Int32(0).append_to(&mut rs.bytes)?; // placeholder length
+        RawBsonRef::Int32(0).append_to(&mut rs.bytes); // placeholder length
         write_string(&mut rs.bytes, code);
 
-        let doc = DocumentSerializer::start(rs)?;
-        Ok(Self { start, doc })
+        let doc = DocumentSerializer::start(rs);
+        Self { start, doc }
     }
 }
 
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index b7cb203b..ee47fb4f 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -625,8 +625,8 @@ impl Serialize for Regex {
         S: ser::Serializer,
     {
         let raw = RawRegexRef {
-            pattern: self.pattern.as_str(),
-            options: self.options.as_str(),
+            pattern: self.pattern.as_ref(),
+            options: self.options.as_ref(),
         };
         raw.serialize(serializer)
     }
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 2f80e7c5..7dd366a6 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -5,6 +5,7 @@ use std::{
 
 use crate::{
     base64,
+    cstr,
     doc,
     oid::ObjectId,
     spec::BinarySubtype,
@@ -76,8 +77,8 @@ fn test_display_timestamp_type() {
 #[test]
 fn test_display_regex_type() {
     let x = Regex {
-        pattern: String::from("pattern"),
-        options: String::from("options"),
+        pattern: cstr!("pattern").into(),
+        options: cstr!("options").into(),
     };
     let output = "/pattern/options";
     assert_eq!(format!("{}", x), output);
@@ -130,12 +131,12 @@ fn from_impls() {
     assert_eq!(Bson::from(false), Bson::Boolean(false));
     assert_eq!(
         Bson::from(Regex {
-            pattern: String::from("\\s+$"),
-            options: String::from("i")
+            pattern: cstr!("\\s+$").into(),
+            options: cstr!("i").into(),
         }),
         Bson::RegularExpression(Regex {
-            pattern: String::from("\\s+$"),
-            options: String::from("i")
+            pattern: cstr!("\\s+$").into(),
+            options: cstr!("i").into(),
         })
     );
     assert_eq!(
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
index 642dfe58..0cc9900c 100644
--- a/src/tests/modules/macros.rs
+++ b/src/tests/modules/macros.rs
@@ -1,5 +1,6 @@
 use crate::{
     base64,
+    cstr,
     doc,
     oid::ObjectId,
     spec::BinarySubtype,
@@ -34,7 +35,7 @@ fn standard_format() {
         },
         "bool": true,
         "null": null,
-        "regexp": Bson::RegularExpression(Regex { pattern: "s[ao]d".to_owned(), options: "i".to_owned() }),
+        "regexp": Bson::RegularExpression(Regex { pattern: cstr!("s[ao]d").into(), options: cstr!("i").into() }),
         "with_wrapped_parens": (-20),
         "code": Bson::JavaScriptCode("function(x) { return x._id; }".to_owned()),
         "i32": 12,
@@ -77,7 +78,7 @@ fn standard_format() {
             },
             "bool": true,
             "null": null,
-            "regexp": Regex { pattern: "s[ao]d".to_owned(), options: "i".to_owned() },
+            "regexp": Regex { pattern: cstr!("s[ao]d").into(), options: cstr!("i").into() },
             "with_wrapped_parens": (-20),
             "code": RawBson::JavaScriptCode("function(x) { return x._id; }".to_owned()),
             "i32": 12,
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index bca4defe..468fcd12 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -11,7 +11,6 @@ use crate::{
     tests::LOCK,
     Bson,
     Document,
-    Regex,
 };
 
 #[test]
@@ -162,12 +161,6 @@ fn cstring_null_bytes_error() {
     let doc = doc! { "a": { "\0": "b" } };
     verify_doc(doc);
 
-    let regex = doc! { "regex": Regex { pattern: "\0".into(), options: "a".into() } };
-    verify_doc(regex);
-
-    let regex = doc! { "regex": Regex { pattern: "a".into(), options: "\0".into() } };
-    verify_doc(regex);
-
     fn verify_doc(doc: Document) {
         let result = doc.encode_to_vec();
         assert!(result.is_err(), "unexpected success");
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 67bc6d09..01a36f76 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -6,6 +6,7 @@ use std::{
 use serde::{Deserialize, Serialize};
 
 use crate::{
+    cstr,
     de::deserialize_from_document,
     doc,
     oid::ObjectId,
@@ -158,8 +159,8 @@ fn test_serialize_deserialize_null() {
 fn test_serialize_deserialize_regexp() {
     let _guard = LOCK.run_concurrently();
     let src = Bson::RegularExpression(Regex {
-        pattern: "1".to_owned(),
-        options: "2".to_owned(),
+        pattern: cstr!("1").to_owned(),
+        options: cstr!("2").to_owned(),
     });
     let dst = vec![14, 0, 0, 0, 11, 107, 101, 121, 0, 49, 0, 50, 0, 0];
 
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 091df19c..b25456de 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -2,6 +2,7 @@
 
 use crate::{
     bson,
+    cstr,
     deserialize_from_bson,
     deserialize_from_document,
     doc,
@@ -150,8 +151,8 @@ fn test_ser_regex() {
     }
 
     let regex = Regex {
-        pattern: "12".into(),
-        options: "01".into(),
+        pattern: cstr!("12").into(),
+        options: cstr!("01").into(),
     };
 
     let foo = Foo {
@@ -179,8 +180,8 @@ fn test_de_regex() {
     }
 
     let regex = Regex {
-        pattern: "12".into(),
-        options: "01".into(),
+        pattern: cstr!("12").into(),
+        options: cstr!("01").into(),
     };
 
     let foo: Foo = deserialize_from_bson(Bson::Document(doc! {
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index 0255cf41..dccf3e0c 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -201,10 +201,9 @@ fn run_test(test: TestFile) {
                 let owned_raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
                     .expect(&description);
+                let test_key_cstr: &crate::raw::CStr = test_key.as_str().try_into().unwrap();
                 let from_slice_owned_vec =
-                    RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)])
-                        .expect(&description)
-                        .into_bytes();
+                    RawDocumentBuf::from_iter([(test_key_cstr, owned_raw_bson_field)]).into_bytes();
 
                 // deserialize the field from raw Bytes into a Bson
                 let deserializer_value =

From 543bad8e0a9536d43ef97ae74237c97f24eadcf3 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Thu, 3 Jul 2025 14:50:59 -0400
Subject: [PATCH 133/156] RUST-2241 Convert panic from malformed input to error
 (#568)

---
 serde-tests/test.rs | 8 ++++++++
 src/raw/iter.rs     | 3 +++
 2 files changed, 11 insertions(+)

diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index 00fe8f1c..bc8c5e2c 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -21,6 +21,7 @@ use bson::{
     cstr,
     doc,
     oid::ObjectId,
+    serde_helpers::Utf8LossyDeserialization,
     spec::BinarySubtype,
     Binary,
     Bson,
@@ -1330,3 +1331,10 @@ fn invalid_length() {
     // This is a regression test for fuzzer-generated input (RUST-1240).
     assert!(bson::deserialize_from_slice::<Document>(&[4, 0, 0, 128, 0, 87]).is_err());
 }
+
+#[test]
+fn code_with_scope_too_long() {
+    // This is a regression test for fuzzer-generated input (RUST-2241).
+    let bytes = base64::decode("KAAAAAsBCRwPAAAACwFAAAAEAA8AEAAAAAYAAAAA9wD5/wAABgALAA==").unwrap();
+    assert!(bson::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(&bytes).is_err());
+}
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 7516c3c0..b3185bcf 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -289,6 +289,9 @@ impl<'a> RawElement<'a> {
                 let slice = self.slice();
                 let code = String::from_utf8_lossy(read_lenencode_bytes(&slice[4..])?).into_owned();
                 let scope_start = 4 + 4 + code.len() + 1;
+                if scope_start >= slice.len() {
+                    return Err(self.malformed_error("code with scope length overrun"));
+                }
                 let scope = RawDocument::decode_from_bytes(&slice[scope_start..])?;
 
                 Utf8LossyBson::JavaScriptCodeWithScope(Utf8LossyJavaScriptCodeWithScope {

From 92aebb6c698545755ca31490f095c55f429dbfbd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 7 Jul 2025 09:59:56 -0400
Subject: [PATCH 134/156] Bump the rust-dependencies group with 3 updates
 (#569)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 14501d59..21613b68 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -160,9 +160,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.27"
+version = "1.2.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
+checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
 dependencies = [
  "shlex",
 ]
@@ -871,6 +871,18 @@ dependencies = [
  "serde_json",
 ]
 
+[[package]]
+name = "schemars"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "serde"
 version = "1.0.219"
@@ -935,16 +947,17 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.13.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42"
+checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5"
 dependencies = [
  "base64",
  "chrono",
  "hex",
  "indexmap 1.9.3",
  "indexmap 2.10.0",
- "schemars",
+ "schemars 0.9.0",
+ "schemars 1.0.4",
  "serde",
  "serde_derive",
  "serde_json",
@@ -954,9 +967,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.13.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77"
+checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f"
 dependencies = [
  "darling",
  "proc-macro2",

From 7703fee7e296ddf045d1dafe61359fccac41368a Mon Sep 17 00:00:00 2001
From: Jamie Tsai <49384456+JamieTsai1024@users.noreply.github.com>
Date: Mon, 7 Jul 2025 11:19:30 -0400
Subject: [PATCH 135/156] Rust 1748 Add serde_conv macro for
 object_id::AsHexString and object_id::FromHexString (#566)

---
 src/macros.rs        |  58 +++++++++++++++++++
 src/serde_helpers.rs | 132 +++++++++++++++++--------------------------
 2 files changed, 111 insertions(+), 79 deletions(-)

diff --git a/src/macros.rs b/src/macros.rs
index f1a18e78..278ea34a 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -432,3 +432,61 @@ macro_rules! rawdoc {
         object
     }};
 }
+
+/// Like [`serde_with::serde_conv!`], but with additional functionality:
+/// 1. Supports attaching documentation (`///`) and other attributes to the generated struct
+/// 2. Allows serializers that return a [`Result`]`, enabling error handling during serialization
+///
+/// This macro generates a `SerializeAs`/`DeserializeAs` implementation for a given type,
+/// with optional struct-level attributes like `#[derive(...)]` or `/// doc comments`.
+macro_rules! serde_conv_doc {
+    ($(#[$meta:meta])* $vis:vis $m:ident, $t:ty, $ser:expr, $de:expr) => {
+        #[allow(non_camel_case_types)]
+        $(#[$meta])*
+        $vis struct $m;
+
+        // Prevent clippy lints triggering because of the template here
+        // https://github.com/jonasbb/serde_with/pull/320
+        // https://github.com/jonasbb/serde_with/pull/729
+        #[allow(clippy::all)]
+        const _:() = {
+            impl $m {
+                $vis fn serialize<S>(x: &$t, serializer: S) -> Result<S::Ok, S::Error>
+                where
+                    S: Serializer,
+                {
+                    let y = $ser(x).map_err(serde::ser::Error::custom)?;
+                    Serialize::serialize(&y, serializer)
+                }
+
+                $vis fn deserialize<'de, D>(deserializer: D) -> Result<$t, D::Error>
+                where
+                    D: Deserializer<'de>,
+                {
+                    let y = Deserialize::deserialize(deserializer)?;
+                    $de(y).map_err(serde::de::Error::custom)
+                }
+            }
+
+            impl SerializeAs<$t> for $m {
+                fn serialize_as<S>(x: &$t, serializer: S) -> Result<S::Ok, S::Error>
+                where
+                    S: Serializer,
+                {
+                    Self::serialize(x, serializer)
+                }
+            }
+
+            impl<'de> DeserializeAs<'de, $t> for $m {
+                fn deserialize_as<D>(deserializer: D) -> Result<$t, D::Error>
+                where
+                    D: Deserializer<'de>,
+                {
+                    Self::deserialize(deserializer)
+                }
+            }
+        };
+    };
+}
+
+pub(crate) use serde_conv_doc;
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 52e11579..dbc93e0a 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -91,90 +91,64 @@ pub fn serialize_u64_as_i64<S: Serializer>(val: &u64, serializer: S) -> Result<S
 
 #[cfg(feature = "serde_with-3")]
 pub mod object_id {
-    use crate::oid::ObjectId;
-    use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
+    use crate::{macros::serde_conv_doc, oid::ObjectId};
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
 
-    /// Contains functions to serialize an ObjectId as a hex string and deserialize an
-    /// ObjectId from a hex string
-    /// ```rust
-    /// # #[cfg(feature = "serde_with-3")]
-    /// {
-    /// # use serde::{Serialize, Deserialize};
-    /// # use bson::serde_helpers::object_id;
-    /// # use serde_with::serde_as;
-    /// # use bson::oid::ObjectId;
-    /// #[serde_as]
-    /// #[derive(Serialize, Deserialize)]
-    /// struct Item {
-    ///     #[serde_as(as = "object_id::AsHexString")]
-    ///     pub id: ObjectId,
-    /// }
-    /// # }
-    /// ```
-    pub struct AsHexString;
-
-    impl SerializeAs<ObjectId> for AsHexString {
-        fn serialize_as<S>(val: &ObjectId, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            val.to_hex().serialize(serializer)
-        }
-    }
-
-    impl<'de> DeserializeAs<'de, ObjectId> for AsHexString {
-        fn deserialize_as<D>(deserializer: D) -> Result<ObjectId, D::Error>
-        where
-            D: Deserializer<'de>,
-        {
-            let hex_string = String::deserialize(deserializer)?;
-            ObjectId::parse_str(&hex_string).map_err(serde::de::Error::custom)
-        }
-    }
-
-    /// Contains functions to serialize a hex string as an ObjectId and deserialize a
-    /// hex string from an ObjectId
-    /// ```rust
-    /// # #[cfg(feature = "serde_with-3")]
-    /// {
-    /// # use serde::{Serialize, Deserialize};
-    /// # use bson::serde_helpers::object_id;
-    /// # use serde_with::serde_as;
-    /// #[serde_as]
-    /// #[derive(Serialize, Deserialize)]
-    /// struct Item {
-    ///     #[serde_as(as = "object_id::FromHexString")]
-    ///     pub id: String,
-    /// }
-    /// # }
-    /// ```
-    pub struct FromHexString;
-
-    impl SerializeAs<String> for FromHexString {
-        fn serialize_as<S>(val: &String, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            match ObjectId::parse_str(val) {
-                Ok(oid) => oid.serialize(serializer),
-                Err(e) => Err(ser::Error::custom(format!(
-                    "cannot convert {} to ObjectId: {}",
-                    val, e
-                ))),
-            }
+    serde_conv_doc!(
+        /// Contains functions to serialize an ObjectId as a hex string and deserialize an
+        /// ObjectId from a hex string
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// {
+        /// # use serde::{Serialize, Deserialize};
+        /// # use bson::serde_helpers::object_id;
+        /// # use serde_with::serde_as;
+        /// # use bson::oid::ObjectId;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "object_id::AsHexString")]
+        ///     pub id: ObjectId,
+        /// }
+        /// # }
+        /// ```
+        pub AsHexString,
+        ObjectId,
+        |oid: &ObjectId| -> Result<String, String> {
+            Ok(oid.to_hex())
+        },
+        |hex: String| -> Result<ObjectId, String> {
+            ObjectId::parse_str(&hex).map_err(|e| format!("Invalid ObjectId string, {}: {}", hex, e))
         }
-    }
+    );
 
-    impl<'de> DeserializeAs<'de, String> for FromHexString {
-        fn deserialize_as<D>(deserializer: D) -> Result<String, D::Error>
-        where
-            D: Deserializer<'de>,
-        {
-            let object_id = ObjectId::deserialize(deserializer)?;
-            Ok(object_id.to_hex())
+    serde_conv_doc!(
+        /// Contains functions to serialize a hex string as an ObjectId and deserialize a
+        /// hex string from an ObjectId
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// {
+        /// # use serde::{Serialize, Deserialize};
+        /// # use bson::serde_helpers::object_id;
+        /// # use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "object_id::FromHexString")]
+        ///     pub id: String,
+        /// }
+        /// # }
+        /// ```
+        pub FromHexString,
+        String,
+        |hex: &String| -> Result<ObjectId, String> {
+            ObjectId::parse_str(hex).map_err(|e| format!("Invalid ObjectId string, {}: {}", hex, e))
+        },
+        |oid: ObjectId| -> Result<String, String> {
+            Ok(oid.to_hex())
         }
-    }
+    );
 }
 
 /// Contains functions to serialize a u32 as an f64 (BSON double) and deserialize a

From 194177a1593835bf897dd2408db31ce949e32e77 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 8 Jul 2025 21:02:19 -0400
Subject: [PATCH 136/156] RUST-1992 Updates to allow the driver to be updated
 (#571)

---
 src/de/raw.rs           |   5 +-
 src/raw.rs              |  10 ++--
 src/raw/cstr.rs         | 116 +++++++++++++++++++++++++++++++++++++---
 src/raw/document.rs     |  20 ++++---
 src/raw/document_buf.rs |   2 +-
 src/raw/iter.rs         |  10 ++--
 src/raw/test.rs         |   2 +-
 7 files changed, 138 insertions(+), 27 deletions(-)

diff --git a/src/de/raw.rs b/src/de/raw.rs
index 4d3112cb..84ab1ae0 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -363,7 +363,7 @@ impl<'de> serde::de::MapAccess<'de> for DocumentAccess<'de> {
         match &self.elem {
             None => Ok(None),
             Some(elem) => seed
-                .deserialize(BorrowedStrDeserializer::new(elem.key()))
+                .deserialize(BorrowedStrDeserializer::new(elem.key().as_str()))
                 .map(Some),
         }
     }
@@ -421,7 +421,8 @@ impl<'de> serde::de::EnumAccess<'de> for DocumentAccess<'de> {
             Some(e) => e,
             None => return Err(Error::end_of_stream()),
         };
-        let de: BorrowedStrDeserializer<'_, Error> = BorrowedStrDeserializer::new(elem.key());
+        let de: BorrowedStrDeserializer<'_, Error> =
+            BorrowedStrDeserializer::new(elem.key().as_str());
         let key = seed.deserialize(de)?;
         Ok((key, self))
     }
diff --git a/src/raw.rs b/src/raw.rs
index 769b6ce3..ea802113 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -88,6 +88,8 @@
 //! ```rust
 //! use bson::{
 //!    raw::{
+//!        cstr,
+//!        CStr,
 //!        RawBsonRef,
 //!        RawDocumentBuf,
 //!    },
@@ -102,12 +104,12 @@
 //! let doc = RawDocumentBuf::from_document(&original_doc)?;
 //! let mut doc_iter = doc.iter();
 //!
-//! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?;
-//! assert_eq!(key, "crate");
+//! let (key, value): (&CStr, RawBsonRef) = doc_iter.next().unwrap()?;
+//! assert_eq!(key, cstr!("crate"));
 //! assert_eq!(value.as_str(), Some("bson"));
 //!
-//! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?;
-//! assert_eq!(key, "year");
+//! let (key, value): (&CStr, RawBsonRef) = doc_iter.next().unwrap()?;
+//! assert_eq!(key, cstr!("year"));
 //! assert_eq!(value.as_str(), Some("2021"));
 //! # Ok::<(), bson::error::Error>(())
 //! ```
diff --git a/src/raw/cstr.rs b/src/raw/cstr.rs
index 842f872d..8db13fcc 100644
--- a/src/raw/cstr.rs
+++ b/src/raw/cstr.rs
@@ -27,7 +27,7 @@ use crate::error::{Error, Result};
 /// // bson::raw::CStr does not:
 /// let invalid: &bson::raw::CStr = cstr!("foo\0bar");  // will not compile
 /// ```
-#[derive(Debug)]
+#[derive(Debug, Eq)]
 #[repr(transparent)]
 pub struct CStr {
     data: [u8],
@@ -76,18 +76,70 @@ impl CStr {
         self.as_str().is_empty()
     }
 
+    /// Returns the lowercase equivalent of this as a new [`CString`].
+    pub fn to_lowercase(&self) -> CString {
+        CString::from_string_unchecked(self.as_str().to_lowercase())
+    }
+
+    /// Returns the uppercase equivalent of this as a new [`CString`].
+    pub fn to_uppercase(&self) -> CString {
+        CString::from_string_unchecked(self.as_str().to_uppercase())
+    }
+
     pub(crate) fn append_to(&self, buf: &mut Vec<u8>) {
         buf.extend(&self.data);
         buf.push(0);
     }
 }
 
-impl PartialEq<&CStr> for &CStr {
-    fn eq(&self, other: &&CStr) -> bool {
+impl PartialEq for CStr {
+    fn eq(&self, other: &CStr) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl PartialEq<str> for CStr {
+    fn eq(&self, other: &str) -> bool {
+        self.as_str() == other
+    }
+}
+
+impl PartialEq<CString> for CStr {
+    fn eq(&self, other: &CString) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl PartialEq<String> for CStr {
+    fn eq(&self, other: &String) -> bool {
         self.as_str() == other.as_str()
     }
 }
 
+impl std::hash::Hash for CStr {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.as_str().hash(state);
+    }
+}
+
+impl Ord for CStr {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.as_str().cmp(other.as_str())
+    }
+}
+
+impl PartialOrd for CStr {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl std::fmt::Display for CStr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.as_str().fmt(f)
+    }
+}
+
 impl std::borrow::ToOwned for CStr {
     type Owned = CString;
 
@@ -108,6 +160,12 @@ impl AsRef<str> for CStr {
     }
 }
 
+impl<'a> From<&'a CStr> for &'a str {
+    fn from(value: &'a CStr) -> Self {
+        value.as_str()
+    }
+}
+
 #[cfg(feature = "serde")]
 impl serde::Serialize for &CStr {
     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
@@ -175,7 +233,7 @@ pub use cstr;
 ///
 /// Like `CStr`, this differs from [`std::ffi::CString`] in that it is required to be valid UTF-8,
 /// and does not include the nul terminator in the buffer.
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Clone, Eq)]
 #[repr(transparent)]
 pub struct CString {
     data: String,
@@ -229,6 +287,26 @@ impl AsRef<CStr> for CString {
     }
 }
 
+impl From<CString> for String {
+    fn from(value: CString) -> Self {
+        value.into_string()
+    }
+}
+
+impl std::ops::Deref for CString {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        self.as_ref()
+    }
+}
+
+impl std::borrow::Borrow<CStr> for CString {
+    fn borrow(&self) -> &CStr {
+        self.as_ref()
+    }
+}
+
 impl std::fmt::Debug for CString {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         self.data.fmt(f)
@@ -241,9 +319,33 @@ impl std::fmt::Display for CString {
     }
 }
 
-impl std::borrow::Borrow<CStr> for CString {
-    fn borrow(&self) -> &CStr {
-        self.as_ref()
+impl PartialEq for CString {
+    fn eq(&self, other: &Self) -> bool {
+        self.data == other.data
+    }
+}
+
+impl PartialEq<CStr> for CString {
+    fn eq(&self, other: &CStr) -> bool {
+        self.data.as_str() == other.as_str()
+    }
+}
+
+impl PartialEq<String> for CString {
+    fn eq(&self, other: &String) -> bool {
+        &self.data == other
+    }
+}
+
+impl PartialEq<str> for CString {
+    fn eq(&self, other: &str) -> bool {
+        self.data.as_str() == other
+    }
+}
+
+impl std::hash::Hash for CString {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.data.hash(state);
     }
 }
 
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 6e6d6335..8809ceb8 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -161,7 +161,7 @@ impl RawDocument {
     pub fn get(&self, key: impl AsRef<str>) -> RawResult<Option<RawBsonRef<'_>>> {
         for elem in RawIter::new(self) {
             let elem = elem?;
-            if key.as_ref() == elem.key() {
+            if key.as_ref() == elem.key().as_str() {
                 return Ok(Some(elem.try_into()?));
             }
         }
@@ -524,7 +524,7 @@ impl RawDocument {
         for elem in self.iter_elements() {
             let elem = elem?;
             let value = deep_utf8_lossy(elem.value_utf8_lossy()?)?;
-            out.insert(elem.key(), value);
+            out.insert(elem.key().as_str(), value);
         }
         Ok(out)
     }
@@ -543,7 +543,10 @@ fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
             let mut tmp = doc! {};
             for elem in doc.iter_elements() {
                 let elem = elem?;
-                tmp.insert(elem.key(), deep_utf8_lossy(elem.value_utf8_lossy()?)?);
+                tmp.insert(
+                    elem.key().as_str(),
+                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
+                );
             }
             Ok(Bson::Document(tmp))
         }
@@ -551,7 +554,10 @@ fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
             let mut tmp = doc! {};
             for elem in scope.iter_elements() {
                 let elem = elem?;
-                tmp.insert(elem.key(), deep_utf8_lossy(elem.value_utf8_lossy()?)?);
+                tmp.insert(
+                    elem.key().as_str(),
+                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
+                );
             }
             Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
                 code,
@@ -597,7 +603,7 @@ impl serde::Serialize for &RawDocument {
                     let mut map = serializer.serialize_map(None)?;
                     for kvp in self.0 {
                         let (k, v) = kvp.map_err(serde::ser::Error::custom)?;
-                        map.serialize_entry(k, &v)?;
+                        map.serialize_entry(k.as_str(), &v)?;
                     }
                     map.end()
                 } else {
@@ -643,7 +649,7 @@ impl TryFrom<&RawDocument> for crate::Document {
     fn try_from(rawdoc: &RawDocument) -> RawResult<Document> {
         rawdoc
             .into_iter()
-            .map(|res| res.and_then(|(k, v)| Ok((k.to_owned(), v.try_into()?))))
+            .map(|res| res.and_then(|(k, v)| Ok((k.as_str().to_owned(), v.try_into()?))))
             .collect()
     }
 }
@@ -666,7 +672,7 @@ impl TryFrom<&RawDocumentBuf> for Document {
 
 impl<'a> IntoIterator for &'a RawDocument {
     type IntoIter = Iter<'a>;
-    type Item = RawResult<(&'a str, RawBsonRef<'a>)>;
+    type Item = RawResult<(&'a CStr, RawBsonRef<'a>)>;
 
     fn into_iter(self) -> Iter<'a> {
         self.iter()
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index c654727b..277b5a9a 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -292,7 +292,7 @@ impl TryFrom<Document> for RawDocumentBuf {
 
 impl<'a> IntoIterator for &'a RawDocumentBuf {
     type IntoIter = Iter<'a>;
-    type Item = Result<(&'a str, RawBsonRef<'a>)>;
+    type Item = Result<(&'a CStr, RawBsonRef<'a>)>;
 
     fn into_iter(self) -> Iter<'a> {
         self.iter()
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index b3185bcf..ee9d5c27 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -44,13 +44,13 @@ impl<'a> Iter<'a> {
 }
 
 impl<'a> Iterator for Iter<'a> {
-    type Item = Result<(&'a str, RawBsonRef<'a>)>;
+    type Item = Result<(&'a CStr, RawBsonRef<'a>)>;
 
-    fn next(&mut self) -> Option<Result<(&'a str, RawBsonRef<'a>)>> {
+    fn next(&mut self) -> Option<Result<(&'a CStr, RawBsonRef<'a>)>> {
         match self.inner.next() {
             Some(Ok(elem)) => match elem.value() {
                 Err(e) => Some(Err(e)),
-                Ok(value) => Some(Ok((elem.key.as_str(), value))),
+                Ok(value) => Some(Ok((elem.key, value))),
             },
             Some(Err(e)) => Some(Err(e)),
             None => None,
@@ -161,8 +161,8 @@ impl<'a> RawElement<'a> {
         self.size
     }
 
-    pub fn key(&self) -> &'a str {
-        self.key.as_str()
+    pub fn key(&self) -> &'a CStr {
+        self.key
     }
 
     pub fn element_type(&self) -> ElementType {
diff --git a/src/raw/test.rs b/src/raw/test.rs
index ef28f456..b2c731dc 100644
--- a/src/raw/test.rs
+++ b/src/raw/test.rs
@@ -404,7 +404,7 @@ fn document_iteration() {
     assert_eq!(
         rawdoc
             .into_iter()
-            .collect::<Result<Vec<(&str, _)>>>()
+            .collect::<Result<Vec<(_, _)>>>()
             .expect("collecting iterated doc")
             .len(),
         17

From 174fe65a7a79a67742008c669bd672bd025d439a Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Mon, 14 Jul 2025 10:33:13 -0400
Subject: [PATCH 137/156] RUST-2240 Move `serde_json` API behind a feature flag
 (#567)

---
 Cargo.toml                |   4 +-
 README.md                 |   5 +-
 serde-tests/Cargo.toml    |   2 +-
 src/bson.rs               | 142 +----------------
 src/error.rs              |   2 +
 src/extjson.rs            |  93 +----------
 src/extjson/de.rs         | 187 ----------------------
 src/extjson/json.rs       | 316 ++++++++++++++++++++++++++++++++++++++
 src/extjson/models.rs     |   3 +
 src/lib.rs                |  91 ++++++++++-
 src/tests/modules/bson.rs |   5 +-
 11 files changed, 424 insertions(+), 426 deletions(-)
 delete mode 100644 src/extjson/de.rs
 create mode 100644 src/extjson/json.rs

diff --git a/Cargo.toml b/Cargo.toml
index 1e7e43db..307fc803 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -48,6 +48,7 @@ serde_path_to_error = ["dep:serde_path_to_error"]
 # should be used in conjunction with chrono-0_4 or uuid-0_8.
 serde_with-3 = ["dep:serde_with", "dep:serde"]
 serde = ["dep:serde"]
+serde_json-1 = ["dep:serde_json"]
 
 [lib]
 name = "bson"
@@ -57,7 +58,7 @@ ahash = "0.8.0"
 chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
 rand = "0.9"
 serde = { version = "1.0", features = ["derive"], optional = true }
-serde_json = { version = "1.0", features = ["preserve_order"] }
+serde_json = { version = "1.0", features = ["preserve_order"], optional = true }
 indexmap = "2.1.0"
 hex = "0.4.2"
 base64 = "0.22.1"
@@ -84,6 +85,7 @@ pretty_assertions = "0.6.1"
 proptest = "1.0.0"
 serde_bytes = "0.11"
 serde_path_to_error = "0.1.16"
+serde_json = "1"
 chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false }
 
 [package.metadata.docs.rs]
diff --git a/README.md b/README.md
index e9d98592..eafc2ab7 100644
--- a/README.md
+++ b/README.md
@@ -50,10 +50,11 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
 | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.              | n/a                | no      |
 | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API.                  | n/a                | no      |
 | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.                  | n/a                | no      |
-| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with         | no      |
-| `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | serde_path_to_error  | no |
+| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| `serde_with`         | no      |
+| `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature.  | `serde_path_to_error`  | no |
 | `compat-3-0-0` | Required for future compatibility if default features are disabled. | n/a | no |
 | `large_dates` | Increase the supported year range for some `bson::DateTime` utilities from +/-9,999 (inclusive) to +/-999,999 (inclusive). Note that enabling this feature can impact performance and introduce parsing ambiguities. | n/a | no |
+| `serde_json-1` | Enable support for v1.x of the [`serde_json`](https://docs.rs/serde_json/1.x) crate in the public API. | `serde_json` | no |
 
 ## Overview of the BSON Format
 
diff --git a/serde-tests/Cargo.toml b/serde-tests/Cargo.toml
index 12a09e8c..05878dee 100644
--- a/serde-tests/Cargo.toml
+++ b/serde-tests/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2018"
 default = []
 
 [dependencies]
-bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3"] }
+bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3", "serde_json-1"] }
 serde = { version = "1.0", features = ["derive"] }
 pretty_assertions = "0.6.1"
 hex = "0.4.2"
diff --git a/src/bson.rs b/src/bson.rs
index 7bcac566..69ec9d6d 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -28,10 +28,8 @@ use std::{
     ops::Index,
 };
 
-use serde_json::{json, Value};
-
 pub use crate::document::Document;
-use crate::{base64, oid, raw::CString, spec::ElementType, Binary, Decimal128};
+use crate::{oid, raw::CString, spec::ElementType, Binary, Decimal128};
 
 /// Possible BSON value types.
 #[derive(Clone, Default, PartialEq)]
@@ -450,143 +448,7 @@ where
     }
 }
 
-/// This will create the [relaxed Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) representation of the provided [`Bson`](../enum.Bson.html).
-impl From<Bson> for Value {
-    fn from(bson: Bson) -> Self {
-        bson.into_relaxed_extjson()
-    }
-}
-
 impl Bson {
-    /// Converts the Bson value into its [relaxed extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-    pub fn into_relaxed_extjson(self) -> Value {
-        match self {
-            Bson::Double(v) if v.is_nan() => {
-                let s = if v.is_sign_negative() { "-NaN" } else { "NaN" };
-
-                json!({ "$numberDouble": s })
-            }
-            Bson::Double(v) if v.is_infinite() => {
-                let s = if v.is_sign_negative() {
-                    "-Infinity"
-                } else {
-                    "Infinity"
-                };
-
-                json!({ "$numberDouble": s })
-            }
-            Bson::Double(v) => json!(v),
-            Bson::String(v) => json!(v),
-            Bson::Array(v) => Value::Array(v.into_iter().map(Bson::into_relaxed_extjson).collect()),
-            Bson::Document(v) => Value::Object(
-                v.into_iter()
-                    .map(|(k, v)| (k, v.into_relaxed_extjson()))
-                    .collect(),
-            ),
-            Bson::Boolean(v) => json!(v),
-            Bson::Null => Value::Null,
-            Bson::RegularExpression(Regex { pattern, options }) => {
-                let mut chars: Vec<_> = options.as_str().chars().collect();
-                chars.sort_unstable();
-
-                let options: String = chars.into_iter().collect();
-
-                json!({
-                    "$regularExpression": {
-                        "pattern": pattern.into_string(),
-                        "options": options,
-                    }
-                })
-            }
-            Bson::JavaScriptCode(code) => json!({ "$code": code }),
-            Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
-                "$code": code,
-                "$scope": Bson::Document(scope).into_relaxed_extjson(),
-            }),
-            Bson::Int32(v) => v.into(),
-            Bson::Int64(v) => v.into(),
-            Bson::Timestamp(Timestamp { time, increment }) => json!({
-                "$timestamp": {
-                    "t": time,
-                    "i": increment,
-                }
-            }),
-            Bson::Binary(Binary { subtype, ref bytes }) => {
-                let tval: u8 = From::from(subtype);
-                json!({
-                    "$binary": {
-                        "base64": base64::encode(bytes),
-                        "subType": hex::encode([tval]),
-                    }
-                })
-            }
-            Bson::ObjectId(v) => json!({"$oid": v.to_hex()}),
-            Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time_0_3().year() <= 9999 => {
-                json!({
-                    // Unwrap safety: timestamps in the guarded range can always be formatted.
-                    "$date": v.try_to_rfc3339_string().unwrap(),
-                })
-            }
-            Bson::DateTime(v) => json!({
-                "$date": { "$numberLong": v.timestamp_millis().to_string() },
-            }),
-            Bson::Symbol(v) => json!({ "$symbol": v }),
-            Bson::Decimal128(v) => json!({ "$numberDecimal": v.to_string() }),
-            Bson::Undefined => json!({ "$undefined": true }),
-            Bson::MinKey => json!({ "$minKey": 1 }),
-            Bson::MaxKey => json!({ "$maxKey": 1 }),
-            Bson::DbPointer(DbPointer {
-                ref namespace,
-                ref id,
-            }) => json!({
-                "$dbPointer": {
-                    "$ref": namespace,
-                    "$id": {
-                        "$oid": id.to_hex()
-                    }
-                }
-            }),
-        }
-    }
-
-    /// Converts the Bson value into its [canonical extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-    pub fn into_canonical_extjson(self) -> Value {
-        match self {
-            Bson::Int32(i) => json!({ "$numberInt": i.to_string() }),
-            Bson::Int64(i) => json!({ "$numberLong": i.to_string() }),
-            Bson::Double(f) if f.is_normal() => {
-                let mut s = f.to_string();
-                if f.fract() == 0.0 {
-                    s.push_str(".0");
-                }
-
-                json!({ "$numberDouble": s })
-            }
-            Bson::Double(f) if f == 0.0 => {
-                let s = if f.is_sign_negative() { "-0.0" } else { "0.0" };
-
-                json!({ "$numberDouble": s })
-            }
-            Bson::DateTime(date) => {
-                json!({ "$date": { "$numberLong": date.timestamp_millis().to_string() } })
-            }
-            Bson::Array(arr) => {
-                Value::Array(arr.into_iter().map(Bson::into_canonical_extjson).collect())
-            }
-            Bson::Document(arr) => Value::Object(
-                arr.into_iter()
-                    .map(|(k, v)| (k, v.into_canonical_extjson()))
-                    .collect(),
-            ),
-            Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
-                "$code": code,
-                "$scope": Bson::Document(scope).into_canonical_extjson(),
-            }),
-
-            other => other.into_relaxed_extjson(),
-        }
-    }
-
     /// Get the [`ElementType`] of this value.
     pub fn element_type(&self) -> ElementType {
         match *self {
@@ -668,7 +530,7 @@ impl Bson {
                 } else {
                     doc! {
                         "$binary": {
-                            "base64": base64::encode(bytes),
+                            "base64": crate::base64::encode(bytes),
                             "subType": hex::encode([tval]),
                         }
                     }
diff --git a/src/error.rs b/src/error.rs
index 7b9d5918..9dd62185 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,3 +1,5 @@
+//! Contains the error-related types for the `bson` crate.
+
 mod decimal128;
 mod oid;
 mod uuid;
diff --git a/src/extjson.rs b/src/extjson.rs
index a23ca419..f661cf4a 100644
--- a/src/extjson.rs
+++ b/src/extjson.rs
@@ -1,92 +1,3 @@
-//! Deserialization and serialization of [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
-//!
-//! ## Overview of Extended JSON
-//!
-//! MongoDB Extended JSON (abbreviated extJSON) is format of JSON that allows for the encoding of
-//! BSON type information. Normal JSON cannot unambiguously represent all BSON types losslessly, so
-//! an extension was designed to include conventions for representing those types.
-//!
-//! For example, a BSON binary is represented by the following format:
-//! ```text
-//! {
-//!    "$binary": {
-//!        "base64": <base64 encoded payload as a string>,
-//!        "subType": <subtype as a one or two character hex string>,
-//!    }
-//! }
-//! ```
-//! For more information on extJSON and the complete list of translations, see the [official MongoDB documentation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-//!
-//! All MongoDB drivers and BSON libraries interpret and produce extJSON, so it can serve as a
-//! useful tool for communicating between applications where raw BSON bytes cannot be used (e.g. via
-//! JSON REST APIs). It's also useful for representing BSON data as a string.
-//!
-//! ### Canonical and Relaxed Modes
-//!
-//! There are two modes of extJSON: "Canonical" and "Relaxed". They are the same except for the
-//! following differences:
-//!   - In relaxed mode, all BSON numbers are represented by the JSON number type, rather than the
-//!     object notation.
-//!   - In relaxed mode, the string in the datetime object notation is RFC 3339 (ISO-8601) formatted
-//!     (if the date is after 1970).
-//!
-//! e.g.
-//! ```rust
-//! # use bson::bson;
-//! let doc = bson!({ "x": 5, "d": bson::DateTime::now() });
-//!
-//! println!("relaxed: {}", doc.clone().into_relaxed_extjson());
-//! // relaxed: "{"x":5,"d":{"$date":"2020-06-01T22:19:13.075Z"}}"
-//!
-//! println!("canonical: {}", doc.into_canonical_extjson());
-//! // canonical: {"x":{"$numberInt":"5"},"d":{"$date":{"$numberLong":"1591050020711"}}}
-//! ```
-//!
-//! Canonical mode is useful when BSON values need to be round tripped without losing any type
-//! information. Relaxed mode is more useful when debugging or logging BSON data.
-//!
-//! ## Deserializing Extended JSON
-//!
-//! Extended JSON can be deserialized using [`Bson`](../enum.Bson.html)'s
-//! `TryFrom<serde_json::Value>` implementation. This implementation accepts both canonical and
-//! relaxed extJSON, and the two modes can even be mixed within a single representation.
-//!
-//! e.g.
-//! ```rust
-//! # use bson::Bson;
-//! # use serde_json::json;
-//! # use std::convert::{TryFrom, TryInto};
-//! let json_doc = json!({ "x": 5i32, "y": { "$numberInt": "5" }, "z": { "subdoc": "hello" } });
-//! let bson: Bson = json_doc.try_into().unwrap(); // Bson::Document(...)
-//!
-//! let json_date = json!({ "$date": { "$numberLong": "1590972160292" } });
-//! let bson_date: Bson = json_date.try_into().unwrap(); // Bson::DateTime(...)
-//!
-//! let invalid_ext_json = json!({ "$numberLong": 5 });
-//! Bson::try_from(invalid_ext_json).expect_err("5 should be a string");
-//! ```
-//!
-//! ## Serializing to Extended JSON
-//!
-//! Extended JSON can be created via [`Bson`](../enum.Bson.html)'s `Into<serde_json::Value>`
-//! implementation (which will create relaxed extJSON),
-//! [`Bson::into_relaxed_extjson`](../enum.Bson.html#method.into_relaxed_extjson), and
-//! [`Bson::into_canonical_extjson`](../enum.Bson.html#method.into_canonical_extjson).
-//!
-//! e.g.
-//! ```rust
-//! # use bson::{bson, oid};
-//! let doc = bson!({ "x": 5i32, "_id": oid::ObjectId::new() });
-//!
-//! let relaxed_extjson: serde_json::Value = doc.clone().into();
-//! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": <hexstring> } }
-//!
-//! let relaxed_extjson = doc.clone().into_relaxed_extjson();
-//! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": <hexstring> } }
-//!
-//! let canonical_extjson = doc.into_canonical_extjson();
-//! println!("{}", canonical_extjson); // { "x": { "$numberInt": "5" }, "_id": { "$oid": <hexstring> } }
-//! ```
-
-pub mod de;
+#[cfg(feature = "serde_json-1")]
+pub(crate) mod json;
 pub(crate) mod models;
diff --git a/src/extjson/de.rs b/src/extjson/de.rs
deleted file mode 100644
index f5f1af3b..00000000
--- a/src/extjson/de.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-//! Deserializing [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
-//!
-//! ## Usage
-//!
-//! Extended JSON can be deserialized using [`Bson`](../../enum.Bson.html)'s
-//! `TryFrom<serde_json::Value>` implementation. This implementation accepts both canonical and
-//! relaxed extJSON, and the two modes can even be mixed within a single representation.
-//!
-//! e.g.
-//! ```rust
-//! # use bson::Bson;
-//! # use serde_json::json;
-//! # use std::convert::{TryFrom, TryInto};
-//! let json_doc = json!({ "x": 5i32, "y": { "$numberInt": "5" }, "z": { "subdoc": "hello" } });
-//! let bson: Bson = json_doc.try_into().unwrap(); // Bson::Document(...)
-//!
-//! let json_date = json!({ "$date": { "$numberLong": "1590972160292" } });
-//! let bson_date: Bson = json_date.try_into().unwrap(); // Bson::DateTime(...)
-//!
-//! let invalid_ext_json = json!({ "$numberLong": 5 });
-//! Bson::try_from(invalid_ext_json).expect_err("5 should be a string");
-//! ```
-
-use std::convert::{TryFrom, TryInto};
-
-use serde::de::{Error as _, Unexpected};
-
-use crate::{
-    error::{Error, Result},
-    extjson::models,
-    Bson,
-    Document,
-};
-
-impl From<serde_json::Error> for Error {
-    fn from(error: serde_json::Error) -> Self {
-        Self::deserialization(error)
-    }
-}
-
-/// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
-    type Error = Error;
-
-    fn try_from(obj: serde_json::Map<String, serde_json::Value>) -> Result<Self> {
-        if obj.contains_key("$oid") {
-            let oid: models::ObjectId = serde_json::from_value(obj.into())?;
-            return Ok(Bson::ObjectId(oid.parse()?));
-        }
-
-        if obj.contains_key("$symbol") {
-            let symbol: models::Symbol = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Symbol(symbol.value));
-        }
-
-        if obj.contains_key("$regularExpression") {
-            let regex: models::Regex = serde_json::from_value(obj.into())?;
-            return Ok(regex.parse()?.into());
-        }
-
-        if obj.contains_key("$numberInt") {
-            let int: models::Int32 = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Int32(int.parse()?));
-        }
-
-        if obj.contains_key("$numberLong") {
-            let int: models::Int64 = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Int64(int.parse()?));
-        }
-
-        if obj.contains_key("$numberDouble") {
-            let double: models::Double = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Double(double.parse()?));
-        }
-
-        if obj.contains_key("$numberDecimal") {
-            let decimal: models::Decimal128 = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Decimal128(decimal.parse()?));
-        }
-
-        if obj.contains_key("$binary") {
-            let binary: models::Binary = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Binary(binary.parse()?));
-        }
-
-        if obj.contains_key("$uuid") {
-            let uuid: models::Uuid = serde_json::from_value(obj.into())?;
-            return Ok(Bson::Binary(uuid.parse()?));
-        }
-
-        if obj.contains_key("$code") {
-            let code_w_scope: models::JavaScriptCodeWithScope = serde_json::from_value(obj.into())?;
-            return match code_w_scope.scope {
-                Some(scope) => Ok(crate::JavaScriptCodeWithScope {
-                    code: code_w_scope.code,
-                    scope: scope.try_into()?,
-                }
-                .into()),
-                None => Ok(Bson::JavaScriptCode(code_w_scope.code)),
-            };
-        }
-
-        if obj.contains_key("$timestamp") {
-            let ts: models::Timestamp = serde_json::from_value(obj.into())?;
-            return Ok(ts.parse().into());
-        }
-
-        if obj.contains_key("$date") {
-            let extjson_datetime: models::DateTime = serde_json::from_value(obj.into())?;
-            return Ok(Bson::DateTime(extjson_datetime.parse()?));
-        }
-
-        if obj.contains_key("$minKey") {
-            let min_key: models::MinKey = serde_json::from_value(obj.into())?;
-            return min_key.parse();
-        }
-
-        if obj.contains_key("$maxKey") {
-            let max_key: models::MaxKey = serde_json::from_value(obj.into())?;
-            return max_key.parse();
-        }
-
-        if obj.contains_key("$dbPointer") {
-            let db_ptr: models::DbPointer = serde_json::from_value(obj.into())?;
-            return Ok(db_ptr.parse()?.into());
-        }
-
-        if obj.contains_key("$undefined") {
-            let undefined: models::Undefined = serde_json::from_value(obj.into())?;
-            return undefined.parse();
-        }
-
-        Ok(Bson::Document(obj.try_into()?))
-    }
-}
-
-/// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-impl TryFrom<serde_json::Value> for Bson {
-    type Error = Error;
-
-    fn try_from(value: serde_json::Value) -> Result<Self> {
-        match value {
-            serde_json::Value::Number(x) => x
-                .as_i64()
-                .map(|i| {
-                    if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
-                        Bson::Int32(i as i32)
-                    } else {
-                        Bson::Int64(i)
-                    }
-                })
-                .or_else(|| x.as_f64().map(Bson::from))
-                .ok_or_else(|| {
-                    Error::invalid_value(
-                        Unexpected::Other(format!("{}", x).as_str()),
-                        &"a number that could fit in i32, i64, or f64",
-                    )
-                }),
-            serde_json::Value::String(x) => Ok(x.into()),
-            serde_json::Value::Bool(x) => Ok(x.into()),
-            serde_json::Value::Array(x) => Ok(Bson::Array(
-                x.into_iter()
-                    .map(Bson::try_from)
-                    .collect::<Result<Vec<Bson>>>()?,
-            )),
-            serde_json::Value::Null => Ok(Bson::Null),
-            serde_json::Value::Object(map) => map.try_into(),
-        }
-    }
-}
-
-/// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
-impl TryFrom<serde_json::Map<String, serde_json::Value>> for Document {
-    type Error = Error;
-
-    fn try_from(obj: serde_json::Map<String, serde_json::Value>) -> Result<Self> {
-        Ok(obj
-            .into_iter()
-            .map(|(k, v)| -> Result<(String, Bson)> {
-                let value: Bson = v.try_into()?;
-                Ok((k, value))
-            })
-            .collect::<Result<Vec<(String, Bson)>>>()?
-            .into_iter()
-            .collect())
-    }
-}
diff --git a/src/extjson/json.rs b/src/extjson/json.rs
new file mode 100644
index 00000000..1743a4cb
--- /dev/null
+++ b/src/extjson/json.rs
@@ -0,0 +1,316 @@
+use std::convert::{TryFrom, TryInto};
+
+use serde::de::{Error as _, Unexpected};
+use serde_json::{json, Value};
+
+use crate::{
+    error::{Error, Result},
+    extjson::models,
+    Binary,
+    Bson,
+    DbPointer,
+    Document,
+    JavaScriptCodeWithScope,
+    Regex,
+    Timestamp,
+};
+
+impl From<serde_json::Error> for Error {
+    fn from(error: serde_json::Error) -> Self {
+        Self::deserialization(error)
+    }
+}
+
+/// Converts the [`serde_json::Map`] into [`Bson`]. This conversion can interpret both canonical
+/// and relaxed [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
+impl TryFrom<serde_json::Map<String, serde_json::Value>> for Bson {
+    type Error = Error;
+
+    fn try_from(obj: serde_json::Map<String, serde_json::Value>) -> Result<Self> {
+        if obj.contains_key("$oid") {
+            let oid: models::ObjectId = serde_json::from_value(obj.into())?;
+            return Ok(Bson::ObjectId(oid.parse()?));
+        }
+
+        if obj.contains_key("$symbol") {
+            let symbol: models::Symbol = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Symbol(symbol.value));
+        }
+
+        if obj.contains_key("$regularExpression") {
+            let regex: models::Regex = serde_json::from_value(obj.into())?;
+            return Ok(regex.parse()?.into());
+        }
+
+        if obj.contains_key("$numberInt") {
+            let int: models::Int32 = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Int32(int.parse()?));
+        }
+
+        if obj.contains_key("$numberLong") {
+            let int: models::Int64 = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Int64(int.parse()?));
+        }
+
+        if obj.contains_key("$numberDouble") {
+            let double: models::Double = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Double(double.parse()?));
+        }
+
+        if obj.contains_key("$numberDecimal") {
+            let decimal: models::Decimal128 = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Decimal128(decimal.parse()?));
+        }
+
+        if obj.contains_key("$binary") {
+            let binary: models::Binary = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Binary(binary.parse()?));
+        }
+
+        if obj.contains_key("$uuid") {
+            let uuid: models::Uuid = serde_json::from_value(obj.into())?;
+            return Ok(Bson::Binary(uuid.parse()?));
+        }
+
+        if obj.contains_key("$code") {
+            let code_w_scope: models::JavaScriptCodeWithScope = serde_json::from_value(obj.into())?;
+            return match code_w_scope.scope {
+                Some(scope) => Ok(crate::JavaScriptCodeWithScope {
+                    code: code_w_scope.code,
+                    scope: scope.try_into()?,
+                }
+                .into()),
+                None => Ok(Bson::JavaScriptCode(code_w_scope.code)),
+            };
+        }
+
+        if obj.contains_key("$timestamp") {
+            let ts: models::Timestamp = serde_json::from_value(obj.into())?;
+            return Ok(ts.parse().into());
+        }
+
+        if obj.contains_key("$date") {
+            let extjson_datetime: models::DateTime = serde_json::from_value(obj.into())?;
+            return Ok(Bson::DateTime(extjson_datetime.parse()?));
+        }
+
+        if obj.contains_key("$minKey") {
+            let min_key: models::MinKey = serde_json::from_value(obj.into())?;
+            return min_key.parse();
+        }
+
+        if obj.contains_key("$maxKey") {
+            let max_key: models::MaxKey = serde_json::from_value(obj.into())?;
+            return max_key.parse();
+        }
+
+        if obj.contains_key("$dbPointer") {
+            let db_ptr: models::DbPointer = serde_json::from_value(obj.into())?;
+            return Ok(db_ptr.parse()?.into());
+        }
+
+        if obj.contains_key("$undefined") {
+            let undefined: models::Undefined = serde_json::from_value(obj.into())?;
+            return undefined.parse();
+        }
+
+        Ok(Bson::Document(obj.try_into()?))
+    }
+}
+
+/// Converts the [`serde_json::Value`] into [`Bson`]. This conversion can interpret both canonical
+/// and relaxed [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
+impl TryFrom<serde_json::Value> for Bson {
+    type Error = Error;
+
+    fn try_from(value: serde_json::Value) -> Result<Self> {
+        match value {
+            serde_json::Value::Number(x) => x
+                .as_i64()
+                .map(|i| {
+                    if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
+                        Bson::Int32(i as i32)
+                    } else {
+                        Bson::Int64(i)
+                    }
+                })
+                .or_else(|| x.as_f64().map(Bson::from))
+                .ok_or_else(|| {
+                    Error::invalid_value(
+                        Unexpected::Other(format!("{}", x).as_str()),
+                        &"a number that could fit in i32, i64, or f64",
+                    )
+                }),
+            serde_json::Value::String(x) => Ok(x.into()),
+            serde_json::Value::Bool(x) => Ok(x.into()),
+            serde_json::Value::Array(x) => Ok(Bson::Array(
+                x.into_iter()
+                    .map(Bson::try_from)
+                    .collect::<Result<Vec<Bson>>>()?,
+            )),
+            serde_json::Value::Null => Ok(Bson::Null),
+            serde_json::Value::Object(map) => map.try_into(),
+        }
+    }
+}
+
+/// Converts the [`serde_json::Map`] into a [`Document`]. This conversion can interpret both
+/// canonical and relaxed [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
+impl TryFrom<serde_json::Map<String, serde_json::Value>> for Document {
+    type Error = Error;
+
+    fn try_from(obj: serde_json::Map<String, serde_json::Value>) -> Result<Self> {
+        Ok(obj
+            .into_iter()
+            .map(|(k, v)| -> Result<(String, Bson)> {
+                let value: Bson = v.try_into()?;
+                Ok((k, value))
+            })
+            .collect::<Result<Vec<(String, Bson)>>>()?
+            .into_iter()
+            .collect())
+    }
+}
+
+/// Converts [`Bson`] into a [`serde_json::Value`] in relaxed
+/// [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
+impl From<Bson> for Value {
+    fn from(bson: Bson) -> Self {
+        bson.into_relaxed_extjson()
+    }
+}
+
+impl Bson {
+    /// Converts this value into a [`serde_json::Value`] in relaxed
+    /// [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
+    /// format.
+    pub fn into_relaxed_extjson(self) -> Value {
+        match self {
+            Bson::Double(v) if v.is_nan() => {
+                let s = if v.is_sign_negative() { "-NaN" } else { "NaN" };
+
+                json!({ "$numberDouble": s })
+            }
+            Bson::Double(v) if v.is_infinite() => {
+                let s = if v.is_sign_negative() {
+                    "-Infinity"
+                } else {
+                    "Infinity"
+                };
+
+                json!({ "$numberDouble": s })
+            }
+            Bson::Double(v) => json!(v),
+            Bson::String(v) => json!(v),
+            Bson::Array(v) => Value::Array(v.into_iter().map(Bson::into_relaxed_extjson).collect()),
+            Bson::Document(v) => Value::Object(
+                v.into_iter()
+                    .map(|(k, v)| (k, v.into_relaxed_extjson()))
+                    .collect(),
+            ),
+            Bson::Boolean(v) => json!(v),
+            Bson::Null => Value::Null,
+            Bson::RegularExpression(Regex { pattern, options }) => {
+                let mut chars: Vec<_> = options.as_str().chars().collect();
+                chars.sort_unstable();
+
+                let options: String = chars.into_iter().collect();
+
+                json!({
+                    "$regularExpression": {
+                        "pattern": pattern.into_string(),
+                        "options": options,
+                    }
+                })
+            }
+            Bson::JavaScriptCode(code) => json!({ "$code": code }),
+            Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
+                "$code": code,
+                "$scope": Bson::Document(scope).into_relaxed_extjson(),
+            }),
+            Bson::Int32(v) => v.into(),
+            Bson::Int64(v) => v.into(),
+            Bson::Timestamp(Timestamp { time, increment }) => json!({
+                "$timestamp": {
+                    "t": time,
+                    "i": increment,
+                }
+            }),
+            Bson::Binary(Binary { subtype, ref bytes }) => {
+                let tval: u8 = From::from(subtype);
+                json!({
+                    "$binary": {
+                        "base64": crate::base64::encode(bytes),
+                        "subType": hex::encode([tval]),
+                    }
+                })
+            }
+            Bson::ObjectId(v) => json!({"$oid": v.to_hex()}),
+            Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time_0_3().year() <= 9999 => {
+                json!({
+                    // Unwrap safety: timestamps in the guarded range can always be formatted.
+                    "$date": v.try_to_rfc3339_string().unwrap(),
+                })
+            }
+            Bson::DateTime(v) => json!({
+                "$date": { "$numberLong": v.timestamp_millis().to_string() },
+            }),
+            Bson::Symbol(v) => json!({ "$symbol": v }),
+            Bson::Decimal128(v) => json!({ "$numberDecimal": v.to_string() }),
+            Bson::Undefined => json!({ "$undefined": true }),
+            Bson::MinKey => json!({ "$minKey": 1 }),
+            Bson::MaxKey => json!({ "$maxKey": 1 }),
+            Bson::DbPointer(DbPointer {
+                ref namespace,
+                ref id,
+            }) => json!({
+                "$dbPointer": {
+                    "$ref": namespace,
+                    "$id": {
+                        "$oid": id.to_hex()
+                    }
+                }
+            }),
+        }
+    }
+
+    /// Converts this value into a [`serde_json::Value`] in canonical
+    /// [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
+    /// format.
+    pub fn into_canonical_extjson(self) -> Value {
+        match self {
+            Bson::Int32(i) => json!({ "$numberInt": i.to_string() }),
+            Bson::Int64(i) => json!({ "$numberLong": i.to_string() }),
+            Bson::Double(f) if f.is_normal() => {
+                let mut s = f.to_string();
+                if f.fract() == 0.0 {
+                    s.push_str(".0");
+                }
+
+                json!({ "$numberDouble": s })
+            }
+            Bson::Double(f) if f == 0.0 => {
+                let s = if f.is_sign_negative() { "-0.0" } else { "0.0" };
+
+                json!({ "$numberDouble": s })
+            }
+            Bson::DateTime(date) => {
+                json!({ "$date": { "$numberLong": date.timestamp_millis().to_string() } })
+            }
+            Bson::Array(arr) => {
+                Value::Array(arr.into_iter().map(Bson::into_canonical_extjson).collect())
+            }
+            Bson::Document(arr) => Value::Object(
+                arr.into_iter()
+                    .map(|(k, v)| (k, v.into_canonical_extjson()))
+                    .collect(),
+            ),
+            Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
+                "$code": code,
+                "$scope": Bson::Document(scope).into_canonical_extjson(),
+            }),
+
+            other => other.into_relaxed_extjson(),
+        }
+    }
+}
diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index 88d3a2ca..d7107d4e 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -1,5 +1,7 @@
 //! A module defining serde models for the extended JSON representations of the various BSON types.
 
+#![cfg_attr(not(feature = "serde_json-1"), allow(unused))]
+
 use serde::{
     de::{Error as _, Unexpected},
     Deserialize,
@@ -196,6 +198,7 @@ impl Uuid {
     }
 }
 
+#[cfg(feature = "serde_json-1")]
 #[derive(Deserialize)]
 #[serde(deny_unknown_fields)]
 pub(crate) struct JavaScriptCodeWithScope {
diff --git a/src/lib.rs b/src/lib.rs
index a4972cc4..ae9aae3f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -68,6 +68,7 @@
 //! | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | no |
 //! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
 //! | `large_dates` | Increase the supported year range for some `bson::DateTime` utilities from +/-9,999 (inclusive) to +/-999,999 (inclusive). Note that enabling this feature can impact performance and introduce parsing ambiguities. | no |
+//! | `serde_json-1` | Enable support for v1.x of the [`serde_json`](https://docs.rs/serde_json/1.x) crate in the public API. | no |
 //!
 //! ## BSON values
 //!
@@ -222,6 +223,94 @@
 //! failing field.  This feature does incur a small CPU and memory overhead during (de)serialization
 //! and should be enabled with care in performance-sensitive environments.
 //!
+//! ## Working with Extended JSON
+//!
+//! MongoDB Extended JSON (extJSON) is a format of JSON that allows for the encoding
+//! of BSON type information. Normal JSON cannot unambiguously represent all BSON types losslessly,
+//! so an extension was designed to include conventions for representing those types.
+//!
+//! For example, a BSON binary is represented by the following format:
+//! ```text
+//! {
+//!    "$binary": {
+//!        "base64": <base64 encoded payload as a string>,
+//!        "subType": <subtype as a one or two character hex string>,
+//!    }
+//! }
+//! ```
+//! For more information on extJSON and the complete list of translations, see the [official MongoDB documentation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
+//!
+//! All MongoDB drivers and BSON libraries interpret and produce extJSON, so it can serve as a
+//! useful tool for communicating between applications where raw BSON bytes cannot be used (e.g. via
+//! JSON REST APIs). It's also useful for representing BSON data as a string.
+//!
+//! ### Canonical and Relaxed Modes
+//!
+//! There are two modes of extJSON: "Canonical" and "Relaxed". They are the same except for the
+//! following differences:
+//!   - In relaxed mode, all BSON numbers are represented by the JSON number type, rather than the
+//!     object notation.
+//!   - In relaxed mode, the string in the datetime object notation is RFC 3339 (ISO-8601) formatted
+//!     (if the date is after 1970).
+//!
+//! e.g.
+//! ```rust
+//! # use bson::bson;
+//! let doc = bson!({ "x": 5, "d": bson::DateTime::now() });
+//!
+//! println!("relaxed: {}", doc.clone().into_relaxed_extjson());
+//! // relaxed: "{"x":5,"d":{"$date":"2020-06-01T22:19:13.075Z"}}"
+//!
+//! println!("canonical: {}", doc.into_canonical_extjson());
+//! // canonical: {"x":{"$numberInt":"5"},"d":{"$date":{"$numberLong":"1591050020711"}}}
+//! ```
+//!
+//! Canonical mode is useful when BSON values need to be round tripped without losing any type
+//! information. Relaxed mode is more useful when debugging or logging BSON data.
+//!
+//! ### Deserializing from Extended JSON
+//!
+//! Extended JSON can be deserialized into a [`Bson`] value using the
+//! [`TryFrom`](https://docs.rs/bson/latest/bson/enum.Bson.html#impl-TryFrom%3CValue%3E-for-Bson)
+//! implementation for [`serde_json::Value`]. This implementation accepts both canonical and relaxed
+//! extJSON, and the two modes can be mixed within a single representation.
+//!
+//! e.g.
+//! ```rust
+//! # use bson::Bson;
+//! # use serde_json::json;
+//! # use std::convert::{TryFrom, TryInto};
+//! let json_doc = json!({ "x": 5i32, "y": { "$numberInt": "5" }, "z": { "subdoc": "hello" } });
+//! let bson: Bson = json_doc.try_into().unwrap(); // Bson::Document(...)
+//!
+//! let json_date = json!({ "$date": { "$numberLong": "1590972160292" } });
+//! let bson_date: Bson = json_date.try_into().unwrap(); // Bson::DateTime(...)
+//!
+//! let invalid_ext_json = json!({ "$numberLong": 5 });
+//! Bson::try_from(invalid_ext_json).expect_err("5 should be a string");
+//! ```
+//!
+//! ### Serializing to Extended JSON
+//!
+//! A [`Bson`] value can be serialized into extJSON using the [`Bson::into_relaxed_extjson`] and
+//! [`Bson::into_canonical_extjson`] methods. The `Into<serde_json::Value>` implementation for
+//! [`Bson`] produces relaxed extJSON.
+//!
+//! e.g.
+//! ```rust
+//! # use bson::{bson, oid};
+//! let doc = bson!({ "x": 5i32, "_id": oid::ObjectId::new() });
+//!
+//! let relaxed_extjson: serde_json::Value = doc.clone().into();
+//! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": <hexstring> } }
+//!
+//! let relaxed_extjson = doc.clone().into_relaxed_extjson();
+//! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": <hexstring> } }
+//!
+//! let canonical_extjson = doc.into_canonical_extjson();
+//! println!("{}", canonical_extjson); // { "x": { "$numberInt": "5" }, "_id": { "$oid": <hexstring> } }
+//! ```
+//!
 //! ## Working with datetimes
 //!
 //! The BSON format includes a datetime type, which is modeled in this crate by the
@@ -340,7 +429,7 @@ pub mod decimal128;
 pub mod document;
 pub mod error;
 #[cfg(feature = "serde")]
-pub mod extjson;
+mod extjson;
 pub mod oid;
 pub mod raw;
 #[cfg(feature = "serde")]
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index 7dd366a6..f9d3636f 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -19,9 +19,8 @@ use crate::{
     Timestamp,
 };
 
-use serde_json::Value;
-
 #[test]
+#[cfg(feature = "serde_json-1")]
 fn to_json() {
     let _guard = LOCK.run_concurrently();
     let mut doc = Document::new();
@@ -32,7 +31,7 @@ fn to_json() {
     doc.insert("first", Bson::Int32(1));
     doc.insert("second", Bson::String("foo".to_owned()));
     doc.insert("alphanumeric", Bson::String("bar".to_owned()));
-    let data: Value = Bson::Document(doc).into();
+    let data: serde_json::Value = Bson::Document(doc).into();
 
     assert!(data.is_object());
     let obj = data.as_object().unwrap();

From 7e8c8599065785f0059d573ec5bbea7e90a7d01f Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Wed, 16 Jul 2025 18:48:27 +0100
Subject: [PATCH 138/156] RUST-2057 Test relaxed encoding of y10k dates (#572)

---
 src/decimal128.rs                             | 25 ++++++++++------
 src/tests/spec/json/bson-corpus/binary.json   | 30 +++++++++++++++++++
 src/tests/spec/json/bson-corpus/datetime.json |  1 +
 .../spec/json/bson-corpus/decimal128-1.json   | 24 +++++++++++++++
 4 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/src/decimal128.rs b/src/decimal128.rs
index b827e986..8ec2dead 100644
--- a/src/decimal128.rs
+++ b/src/decimal128.rs
@@ -356,7 +356,9 @@ impl std::str::FromStr for ParsedDecimal128 {
                         exp_str = post;
                     }
                 }
-                let mut exp = exp_str.parse::<i16>().map_err(|e| {
+                // Initially parse the exponent as an i128 to handle corner cases with zero
+                // coefficients and very large exponents.
+                let mut wide_exp = exp_str.parse::<i128>().map_err(|e| {
                     Error::decimal128(Decimal128ErrorKind::InvalidExponent {}).with_message(e)
                 })?;
 
@@ -367,7 +369,7 @@ impl std::str::FromStr for ParsedDecimal128 {
                         .len()
                         .try_into()
                         .map_err(|_| Error::decimal128(Decimal128ErrorKind::Underflow {}))?;
-                    exp = exp
+                    wide_exp = wide_exp
                         .checked_sub(exp_adj)
                         .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Underflow {}))?;
                     joined_str = format!("{}{}", pre, post);
@@ -386,16 +388,17 @@ impl std::str::FromStr for ParsedDecimal128 {
                         let exp_adj = (len - decimal_str.len())
                             .try_into()
                             .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
-                        exp = exp
+                        wide_exp = wide_exp
                             .checked_add(exp_adj)
                             .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                     }
                 }
 
                 // Check exponent limits
-                if exp < Exponent::TINY {
+                const TINY: i128 = Exponent::TINY as i128;
+                if wide_exp < TINY {
                     if decimal_str != "0" {
-                        let delta = (Exponent::TINY - exp)
+                        let delta = (TINY - wide_exp)
                             .try_into()
                             .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                         let new_precision = decimal_str
@@ -404,12 +407,13 @@ impl std::str::FromStr for ParsedDecimal128 {
                             .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                         decimal_str = round_decimal_str(decimal_str, new_precision)?;
                     }
-                    exp = Exponent::TINY;
+                    wide_exp = Exponent::TINY.into();
                 }
                 let padded_str;
-                if exp > Exponent::MAX {
+                const MAX: i128 = Exponent::MAX as i128;
+                if wide_exp > MAX {
                     if decimal_str != "0" {
-                        let delta = (exp - Exponent::MAX)
+                        let delta = (wide_exp - MAX)
                             .try_into()
                             .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                         if decimal_str
@@ -423,10 +427,13 @@ impl std::str::FromStr for ParsedDecimal128 {
                         padded_str = format!("{}{}", decimal_str, "0".repeat(delta));
                         decimal_str = &padded_str;
                     }
-                    exp = Exponent::MAX;
+                    wide_exp = Exponent::MAX.into();
                 }
 
                 // Assemble the final value
+                let exp: i16 = wide_exp
+                    .try_into()
+                    .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
                 let exponent = Exponent::from_native(exp);
                 let coeff: u128 = decimal_str.parse().map_err(|e: ParseIntError| {
                     Error::decimal128(Decimal128ErrorKind::InvalidCoefficient {}).with_message(e)
diff --git a/src/tests/spec/json/bson-corpus/binary.json b/src/tests/spec/json/bson-corpus/binary.json
index 20aaef74..0e0056f3 100644
--- a/src/tests/spec/json/bson-corpus/binary.json
+++ b/src/tests/spec/json/bson-corpus/binary.json
@@ -74,6 +74,36 @@
             "description": "$type query operator (conflicts with legacy $binary form with $type field)",
             "canonical_bson": "180000000378001000000010247479706500020000000000",
             "canonical_extjson": "{\"x\" : { \"$type\" : {\"$numberInt\": \"2\"}}}"
+        },
+        {
+            "description": "subtype 0x09 Vector FLOAT32",
+            "canonical_bson": "170000000578000A0000000927000000FE420000E04000",
+            "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"JwAAAP5CAADgQA==\", \"subType\": \"09\"}}}"
+        },
+        {
+            "description": "subtype 0x09 Vector INT8",
+            "canonical_bson": "11000000057800040000000903007F0700",
+            "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"AwB/Bw==\", \"subType\": \"09\"}}}"
+        },
+        {
+            "description": "subtype 0x09 Vector PACKED_BIT",
+            "canonical_bson": "11000000057800040000000910007F0700",
+            "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"EAB/Bw==\", \"subType\": \"09\"}}}"
+        },
+        {
+            "description": "subtype 0x09 Vector (Zero-length) FLOAT32",
+            "canonical_bson": "0F0000000578000200000009270000",
+            "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"JwA=\", \"subType\": \"09\"}}}"
+        },
+        {
+            "description": "subtype 0x09 Vector (Zero-length) INT8",
+            "canonical_bson": "0F0000000578000200000009030000",
+            "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"AwA=\", \"subType\": \"09\"}}}"
+        },
+        {
+            "description": "subtype 0x09 Vector (Zero-length) PACKED_BIT",
+            "canonical_bson": "0F0000000578000200000009100000",
+            "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"EAA=\", \"subType\": \"09\"}}}"
         }
     ],
     "decodeErrors": [
diff --git a/src/tests/spec/json/bson-corpus/datetime.json b/src/tests/spec/json/bson-corpus/datetime.json
index f857afdc..1554341d 100644
--- a/src/tests/spec/json/bson-corpus/datetime.json
+++ b/src/tests/spec/json/bson-corpus/datetime.json
@@ -24,6 +24,7 @@
         {
             "description" : "Y10K",
             "canonical_bson" : "1000000009610000DC1FD277E6000000",
+            "relaxed_extjson" : "{\"a\":{\"$date\":{\"$numberLong\":\"253402300800000\"}}}",
             "canonical_extjson" : "{\"a\":{\"$date\":{\"$numberLong\":\"253402300800000\"}}}"
         },
         {
diff --git a/src/tests/spec/json/bson-corpus/decimal128-1.json b/src/tests/spec/json/bson-corpus/decimal128-1.json
index 7eefec6b..8e7fbc93 100644
--- a/src/tests/spec/json/bson-corpus/decimal128-1.json
+++ b/src/tests/spec/json/bson-corpus/decimal128-1.json
@@ -312,6 +312,30 @@
            "canonical_bson": "18000000136400000000000a5bc138938d44c64d31cc3700",
            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+999\"}}"
+        },
+        {
+            "description": "Clamped zeros with a large positive exponent",
+            "canonical_bson": "180000001364000000000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2147483647\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}"
+        },
+        {
+            "description": "Clamped zeros with a large negative exponent",
+            "canonical_bson": "180000001364000000000000000000000000000000000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-2147483647\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}"
+        },
+        {
+            "description": "Clamped negative zeros with a large positive exponent",
+            "canonical_bson": "180000001364000000000000000000000000000000FEDF00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+2147483647\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}"
+        },
+        {
+            "description": "Clamped negative zeros with a large negative exponent",
+            "canonical_bson": "180000001364000000000000000000000000000000008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-2147483647\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}"
         }
     ]
 }

From f14d6d1cf0c0384c644cdac3e8a42b7a45c4e27f Mon Sep 17 00:00:00 2001
From: Jamie Tsai <49384456+JamieTsai1024@users.noreply.github.com>
Date: Wed, 16 Jul 2025 13:50:06 -0400
Subject: [PATCH 139/156] RUST-1748 Refactor BSON DateTime serde converters
 using serde_conv_doc macro (#570)

---
 README.md            |   4 +-
 src/datetime.rs      |  44 +--
 src/lib.rs           |   6 +-
 src/serde_helpers.rs | 361 ++++++++++--------------
 src/tests/serde.rs   | 654 +++++++++++++++++++++----------------------
 5 files changed, 494 insertions(+), 575 deletions(-)

diff --git a/README.md b/README.md
index eafc2ab7..4faf91c2 100644
--- a/README.md
+++ b/README.md
@@ -230,7 +230,7 @@ provides a `DateTime` type, but its `Serialize` and `Deserialize` implementation
 instead, so when using it with BSON, the BSON datetime type is not used. To work around this, the
 `chrono-0_4` feature flag can be enabled. This flag exposes a number of convenient conversions
 between `bson::DateTime` and `chrono::DateTime`, including the
-[`bson_datetime::FromChronoDateTime`](https://docs.rs/bson/latest/bson/serde_helpers/bson_datetime/struct.FromChronoDateTime/index.html)
+[`datetime::FromChrono04DateTime`](https://docs.rs/bson/latest/bson/serde_helpers/datetime/struct.FromChrono04DateTime/index.html)
 serde helper, which can be used to (de)serialize `chrono::DateTime`s to/from BSON datetimes, and the
 `From<chrono::DateTime>` implementation for `Bson`, which allows `chrono::DateTime` values to be
 used in the `doc!` and `bson!` macros.
@@ -251,7 +251,7 @@ struct Foo {
 
     // serializes as a BSON datetime.
     // this requires the "chrono-0_4" feature flag
-    #[serde_as(as = "bson::serde_helpers::bson_datetime::FromChronoDateTime")]
+    #[serde_as(as = "bson::serde_helpers::datetime::FromChrono04DateTime")]
     chrono_as_bson: chrono::DateTime<chrono::Utc>,
 }
 
diff --git a/src/datetime.rs b/src/datetime.rs
index 81e46a3d..3fc7a20c 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -108,20 +108,25 @@ use crate::error::{Error, Result};
 ///
 /// ### `serde_helpers`
 /// The `bson` crate provides a number of useful helpers for serializing and deserializing
-/// various datetime types to and from different formats. For example, to serialize a
-/// [`chrono::DateTime`] as a BSON datetime, you can use
-/// [`crate::serde_helpers::bson_datetime::FromChronoDateTime`].
-/// Similarly, to serialize a BSON [`DateTime`] to a string, you can use
-/// [`crate::serde_helpers::bson_datetime::AsRfc3339String`]. Check out the
-/// [`crate::serde_helpers`] module documentation for a list of all of the helpers offered by the
+/// various datetime types to and from different formats using the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
 /// crate.
 ///
+/// > **Note:** All helpers in this module require use of the [`#[serde_as]`](https://docs.rs/serde_with/latest/serde_with/attr.serde_as.html)
+/// > attribute on the struct. This enables the enhanced serialization behavior provided by
+/// > `serde_with-3`.
+///
+/// For example, to serialize a [`chrono::DateTime`] as a BSON datetime, you can use
+/// [`crate::serde_helpers::datetime::FromChrono04DateTime`].
+/// Similarly, to serialize a BSON [`DateTime`] to a string, you can use
+/// [`crate::serde_helpers::datetime::AsRfc3339String`]. Check out the
+/// [`crate::serde_helpers`] module documentation for a list of all of the helpers
+/// offered by the crate.
 /// ```rust
-/// # #[cfg(feature = "chrono-0_4")]
+/// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
 /// # {
 /// use serde::{Serialize, Deserialize};
 /// use serde_with::serde_as;
-/// use bson::serde_helpers::bson_datetime;
+/// use bson::serde_helpers::datetime;
 ///
 /// #[serde_as]
 /// #[derive(Serialize, Deserialize)]
@@ -134,33 +139,30 @@ use crate::error::{Error, Result};
 ///
 ///     // serializes as a BSON datetime.
 ///     // this requires the "chrono-0_4" feature flag
-///     #[serde_as(as = "bson_datetime::FromChronoDateTime")]
+///     #[serde_as(as = "datetime::FromChrono04DateTime")]
 ///     chrono_as_bson: chrono::DateTime<chrono::Utc>,
 ///
 ///     // serializes as an RFC 3339 / ISO-8601 string.
-///     #[serde_as(as = "bson_datetime::AsRfc3339String")]
+///     // this requires the "serde_with-3" feature flag
+///     #[serde_as(as = "datetime::AsRfc3339String")]
 ///     bson_as_string: bson::DateTime,
 /// }
 /// # }
 /// ```
-/// ### The `serde_with-3` feature flag
-///
-/// The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for
-/// (de)serializing [`chrono::DateTime`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
-/// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3`
-/// can handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only
-/// works on fields that are exactly [`chrono::DateTime`].
+/// The main benefit of using the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/) crate
+/// is that it can handle nested [`chrono::DateTime`] values (e.g. in [`Option`] or [`Vec`]).
 /// ```
 /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
 /// # {
 /// use serde::{Deserialize, Serialize};
-/// use bson::doc;
+/// use serde_with::serde_as;
+/// use bson::{doc, serde_helpers::datetime};
 ///
-/// #[serde_with::serde_as]
+/// #[serde_as]
 /// #[derive(Deserialize, Serialize, PartialEq, Debug)]
 /// struct Foo {
-///   /// Serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization
-///   #[serde_as(as = "Option<bson::DateTime>")]
+///   /// serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization
+///   #[serde_as(as = "Option<datetime::FromChrono04DateTime>")]
 ///   as_bson: Option<chrono::DateTime<chrono::Utc>>,
 /// }
 ///
diff --git a/src/lib.rs b/src/lib.rs
index ae9aae3f..53f72fb8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -322,7 +322,7 @@
 //! on strings instead, so when using it with BSON, the BSON datetime type is not used. To work
 //! around this, the `chrono-0_4` feature flag can be enabled. This flag exposes a number of
 //! convenient conversions between [`bson::DateTime`](crate::DateTime) and [`chrono::DateTime`],
-//! including the [`serde_helpers::bson_datetime::FromChronoDateTime`]
+//! including the [`serde_helpers::datetime::FromChrono04DateTime`]
 //! serde helper, which can be used to (de)serialize [`chrono::DateTime`]s to/from BSON datetimes,
 //! and the `From<chrono::DateTime>` implementation for [`Bson`], which allows [`chrono::DateTime`]
 //! values to be used in the `doc!` and `bson!` macros.
@@ -334,7 +334,7 @@
 //! use serde::{Serialize, Deserialize};
 //! use serde_with::serde_as;
 //! use bson::doc;
-//! use bson::serde_helpers::bson_datetime;
+//! use bson::serde_helpers::datetime;
 //!
 //! #[serde_as]
 //! #[derive(Serialize, Deserialize)]
@@ -347,7 +347,7 @@
 //!
 //!     // serializes as a BSON datetime.
 //!     // this requires the "chrono-0_4" feature flag
-//!     #[serde_as(as = "bson_datetime::FromChronoDateTime")]
+//!     #[serde_as(as = "datetime::FromChrono04DateTime")]
 //!     chrono_as_bson: chrono::DateTime<chrono::Utc>,
 //! }
 //!
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index dbc93e0a..ded62da6 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -1,5 +1,5 @@
 //! Collection of helper functions for serializing to and deserializing from BSON using Serde
-
+use serde::{de::Visitor, ser, Deserialize, Serialize, Serializer};
 use std::{
     convert::TryFrom,
     marker::PhantomData,
@@ -7,19 +7,6 @@ use std::{
     result::Result,
 };
 
-use serde::{de::Visitor, ser, Deserialize, Serialize, Serializer};
-
-#[doc(inline)]
-pub use i64_as_bson_datetime::{
-    deserialize as deserialize_i64_from_bson_datetime,
-    serialize as serialize_i64_as_bson_datetime,
-};
-#[cfg(feature = "time-0_3")]
-#[doc(inline)]
-pub use time_0_3_offsetdatetime_as_bson_datetime::{
-    deserialize as deserialize_time_0_3_offsetdatetime_from_bson_datetime,
-    serialize as serialize_time_0_3_offsetdatetime_as_bson_datetime,
-};
 #[doc(inline)]
 pub use timestamp_as_u32::{
     deserialize as deserialize_timestamp_from_u32,
@@ -232,227 +219,165 @@ pub mod u64_as_f64 {
     }
 }
 
-/// Contains functions to serialize a [`time::OffsetDateTime`] as a [`crate::DateTime`] and
-/// deserialize a [`time::OffsetDateTime`] from a [`crate::DateTime`].
+/// Type converters for serializing and deserializing [`crate::DateTime`] using
+/// [`serde_with::serde_as`].
 ///
-/// ```rust
-/// # #[cfg(feature = "time-0_3")]
-/// # {
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::time_0_3_offsetdatetime_as_bson_datetime;
-/// #[derive(Serialize, Deserialize)]
-/// struct Event {
-///     #[serde(with = "time_0_3_offsetdatetime_as_bson_datetime")]
-///     pub date: time::OffsetDateTime,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "time-0_3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
-pub mod time_0_3_offsetdatetime_as_bson_datetime {
-    use crate::DateTime;
-    use serde::{Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-
-    /// Deserializes a [`time::OffsetDateTime`] from a [`crate::DateTime`].
-    #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<time::OffsetDateTime, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let datetime = DateTime::deserialize(deserializer)?;
-        Ok(datetime.to_time_0_3())
-    }
-
-    /// Serializes a [`time::OffsetDateTime`] as a [`crate::DateTime`].
-    #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
-    pub fn serialize<S: Serializer>(
-        val: &time::OffsetDateTime,
-        serializer: S,
-    ) -> Result<S::Ok, S::Error> {
-        let datetime = DateTime::from_time_0_3(val.to_owned());
-        datetime.serialize(serializer)
-    }
-}
-
+/// ## Available converters
+/// - [`datetime::AsRfc3339String`] — converts a [`crate::DateTime`] to and from an RFC 3339 string.
+/// - [`datetime::FromRfc3339String`] — converts a RFC 3339 string to and from a
+///   [`crate::DateTime`].
+/// - [`datetime::FromI64`] — converts an `i64` to and from a [`crate::DateTime`].
+/// - [`datetime::FromChrono04DateTime`] — converts a [`chrono::DateTime`] to and from a
+///   [`crate::DateTime`].
+/// - [`datetime::FromTime03OffsetDateTime`] — converts a [`time::OffsetDateTime`] to and from a
+///   [`crate::DateTime`].
 #[cfg(feature = "serde_with-3")]
 #[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
-pub mod bson_datetime {
-    use crate::{Bson, DateTime};
+pub mod datetime {
+    use crate::{macros::serde_conv_doc, DateTime};
     use chrono::Utc;
-    use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
     use std::result::Result;
 
-    /// Contains functions to serialize a [`crate::DateTime`] as an RFC 3339 (ISO 8601) formatted
-    /// string and deserialize a [`crate::DateTime`] from an RFC 3339 (ISO 8601) formatted
-    /// string.
-    ///
-    /// ```rust
-    /// # #[cfg(feature = "serde_with-3")]
-    /// {
-    /// # use serde::{Serialize, Deserialize};
-    /// # use bson::serde_helpers::bson_datetime;
-    /// # use serde_with::serde_as;
-    /// #[serde_as]
-    /// #[derive(Serialize, Deserialize)]
-    /// struct Event {
-    ///     #[serde_as(as = "bson_datetime::AsRfc3339String")]
-    ///     pub date: bson::DateTime,
-    /// }
-    /// # }
-    /// ```
-    pub struct AsRfc3339String;
-
-    impl SerializeAs<crate::DateTime> for AsRfc3339String {
-        fn serialize_as<S>(val: &crate::DateTime, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let formatted = val.try_to_rfc3339_string().map_err(|e| {
-                ser::Error::custom(format!("cannot format {} as RFC 3339: {}", val, e))
-            })?;
-            serializer.serialize_str(&formatted)
-        }
-    }
-
-    impl<'de> DeserializeAs<'de, crate::DateTime> for AsRfc3339String {
-        fn deserialize_as<D>(deserializer: D) -> Result<crate::DateTime, D::Error>
-        where
-            D: Deserializer<'de>,
-        {
-            let iso = String::deserialize(deserializer)?;
-            let date = crate::DateTime::parse_rfc3339_str(&iso).map_err(|e| {
-                de::Error::custom(format!(
-                    "cannot parse RFC 3339 datetime from \"{}\": {}",
-                    iso, e
-                ))
-            })?;
-            Ok(date)
-        }
-    }
-
-    /// Contains functions to serialize an RFC 3339 (ISO 8601) formatted string as a
-    /// [`crate::DateTime`] and deserialize an RFC 3339 (ISO 8601) formatted string from a
-    /// [`crate::DateTime`].
-    ///
-    /// ```rust
-    /// # #[cfg(feature = "serde_with-3")]
-    /// {
-    /// # use serde::{Serialize, Deserialize};
-    /// # use bson::serde_helpers::bson_datetime;
-    /// # use serde_with::serde_as;
-    /// #[serde_as]
-    /// #[derive(Serialize, Deserialize)]
-    /// struct Event {
-    ///     #[serde_as(as = "bson_datetime::FromRfc3339String")]
-    ///     pub date: String,
-    /// }
-    /// # }
-    /// ```
-    pub struct FromRfc3339String;
-
-    impl SerializeAs<String> for FromRfc3339String {
-        fn serialize_as<S>(val: &String, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let date = DateTime::parse_rfc3339_str(val).map_err(|e| {
-                ser::Error::custom(format!("cannot convert {} to DateTime: {}", val, e))
-            })?;
-            Bson::DateTime(date).serialize(serializer)
+    serde_conv_doc!(
+        /// Converts a [`DateTime`] to and from an RFC 3339 (ISO 8601) formatted string.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::{serde_helpers::datetime, DateTime};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Event {
+        ///     #[serde_as(as = "datetime::AsRfc3339String")]
+        ///     pub date: DateTime,
+        /// }
+        /// # }
+        /// ```
+        pub AsRfc3339String,
+        DateTime,
+        |date: &DateTime| -> Result<String, String> {
+            date.try_to_rfc3339_string().map_err(|e| {
+                format!("Cannot format DateTime {} as RFC 3339 string: {}", date, e)
+            })
+        },
+        |string: String| -> Result<DateTime, String> {
+            DateTime::parse_rfc3339_str(&string).map_err(|e| format!("Cannot format RFC 3339 string {} as DateTime: {}", string, e))
         }
-    }
+    );
 
-    impl<'de> DeserializeAs<'de, String> for FromRfc3339String {
-        fn deserialize_as<D>(deserializer: D) -> Result<String, D::Error>
-        where
-            D: Deserializer<'de>,
-        {
-            let date = DateTime::deserialize(deserializer)?;
+    serde_conv_doc!(
+        /// Converts an RFC 3339 (ISO 8601) formatted string to and from a [`DateTime`].
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::serde_helpers::datetime;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Event {
+        ///     #[serde_as(as = "datetime::FromRfc3339String")]
+        ///     pub date: String,
+        /// }
+        /// # }
+        pub FromRfc3339String,
+        String,
+        |string: &String| -> Result<DateTime, String> {
+            DateTime::parse_rfc3339_str(string).map_err(|e| format!("Cannot format RFC 3339 string {} as DateTime: {}", string, e))
+        },
+        |date: DateTime| -> Result<String, String> {
             date.try_to_rfc3339_string().map_err(|e| {
-                de::Error::custom(format!("cannot format {} as RFC 3339: {}", date, e))
+                format!("Cannot format DateTime {} as RFC 3339 string: {}", date, e)
             })
         }
-    }
+    );
 
-    #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
-    #[cfg_attr(
-        docsrs,
-        doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3")))
-    )]
-    /// Contains functions to serialize a [`chrono::DateTime`] as a [`crate::DateTime`] and
-    /// deserialize a [`chrono::DateTime`] from a [`crate::DateTime`].
-    ///
-    /// ```rust
-    /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
-    /// # {
-    /// # use serde::{Serialize, Deserialize};
-    /// # use bson::serde_helpers::bson_datetime;
-    /// # use serde_with::serde_as;
-    /// #[serde_as]
-    /// #[derive(Serialize, Deserialize)]
-    /// struct Event {
-    ///     #[serde_as(as = "bson_datetime::FromChronoDateTime")]
-    ///     pub date: chrono::DateTime<chrono::Utc>,
-    /// }
-    /// # }
-    /// ```
-    pub struct FromChronoDateTime;
-
-    impl SerializeAs<chrono::DateTime<Utc>> for FromChronoDateTime {
-        fn serialize_as<S>(val: &chrono::DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let datetime = DateTime::from_chrono(val.to_owned());
-            datetime.serialize(serializer)
+    serde_conv_doc!(
+        /// Converts an `i64` integer to and from a [`DateTime`].
+        ///
+        /// The `i64` should represent milliseconds. See [`DateTime::from_millis`] for more details.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::serde_helpers::datetime;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "datetime::FromI64")]
+        ///     pub now: i64,
+        /// }
+        /// # }
+        /// ```
+        pub FromI64,
+        i64,
+        |value: &i64| -> Result<DateTime, String> {
+            Ok(DateTime::from_millis(*value))
+        },
+        |date: DateTime| -> Result<i64, String> {
+            Ok(date.timestamp_millis())
         }
-    }
+    );
 
-    impl<'de> DeserializeAs<'de, chrono::DateTime<Utc>> for FromChronoDateTime {
-        fn deserialize_as<D>(deserializer: D) -> Result<chrono::DateTime<Utc>, D::Error>
-        where
-            D: Deserializer<'de>,
-        {
-            let datetime = DateTime::deserialize(deserializer)?;
-            Ok(datetime.to_chrono())
+    #[cfg(feature = "chrono-0_4")]
+    serde_conv_doc!(
+        #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
+        /// Converts a [`chrono::DateTime`] to and from a [`DateTime`].
+        /// ```rust
+        /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::datetime;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Event {
+        ///     #[serde_as(as = "datetime::FromChrono04DateTime")]
+        ///     pub date: chrono::DateTime<chrono::Utc>,
+        /// }
+        /// # }
+        /// ```
+        pub FromChrono04DateTime,
+        chrono::DateTime<Utc>,
+        |chrono_date: &chrono::DateTime<Utc>| -> Result<DateTime, String> {
+            Ok(DateTime::from_chrono(*chrono_date))
+        },
+        |bson_date: DateTime| -> Result<chrono::DateTime<Utc>, String> {
+            Ok(bson_date.to_chrono())
         }
-    }
-}
-
-/// Contains functions to `serialize` a `i64` integer as [`crate::DateTime`] and
-/// `deserialize` a `i64` integer from [`crate::DateTime`].
-///
-/// ### The i64 should represent seconds `(DateTime::timestamp_millis(..))`.
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::i64_as_bson_datetime;
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "i64_as_bson_datetime")]
-///     pub now: i64,
-/// }
-/// ```
-pub mod i64_as_bson_datetime {
-    use crate::DateTime;
-    use serde::{Deserialize, Deserializer, Serialize, Serializer};
-
-    /// Deserializes a i64 integer from a DateTime.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<i64, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let date: DateTime = DateTime::deserialize(deserializer)?;
-        Ok(date.timestamp_millis())
-    }
+    );
 
-    /// Serializes a i64 integer as a DateTime.
-    pub fn serialize<S: Serializer>(val: &i64, serializer: S) -> Result<S::Ok, S::Error> {
-        let date_time = DateTime::from_millis(*val);
-        date_time.serialize(serializer)
-    }
+    #[cfg(feature = "time-0_3")]
+    serde_conv_doc!(
+        #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
+        /// Converts a [`time::OffsetDateTime`] to and from a [`DateTime`].
+        /// ```rust
+        /// # #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::datetime;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Event {
+        ///     #[serde_as(as = "datetime::FromTime03OffsetDateTime")]
+        ///     pub date: time::OffsetDateTime,
+        /// }
+        /// # }
+        /// ```
+        pub FromTime03OffsetDateTime,
+        time::OffsetDateTime,
+        |value: &time::OffsetDateTime| -> Result<DateTime, String> {
+            Ok(DateTime::from_time_0_3(*value))
+        },
+        |date: DateTime| -> Result<time::OffsetDateTime, String> {
+            Ok(date.to_time_0_3())
+        }
+    );
 }
 
 #[allow(unused_macros)]
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index b25456de..1bbde432 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -7,14 +7,7 @@ use crate::{
     deserialize_from_document,
     doc,
     oid::ObjectId,
-    serde_helpers::{
-        self,
-        bson_datetime,
-        i64_as_bson_datetime,
-        object_id,
-        timestamp_as_u32,
-        u32_as_timestamp,
-    },
+    serde_helpers::{self, datetime, object_id, timestamp_as_u32, u32_as_timestamp},
     serialize_to_bson,
     serialize_to_document,
     spec::BinarySubtype,
@@ -748,364 +741,383 @@ fn test_unsigned_helpers() {
 }
 
 #[test]
-fn test_datetime_helpers() {
-    use time::{format_description::well_known::Rfc3339, OffsetDateTime};
-
+#[cfg(feature = "serde_with-3")]
+fn test_datetime_rfc3339_string_helpers() {
     let _guard = LOCK.run_concurrently();
 
-    #[cfg(feature = "serde_with-3")]
-    {
-        #[serde_as]
-        #[derive(Deserialize, Serialize, Debug)]
-        struct A {
-            #[serde_as(as = "bson_datetime::AsRfc3339String")]
-            pub date: DateTime,
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "datetime::AsRfc3339String")]
+        pub date: DateTime,
 
-            #[serde_as(as = "Option<bson_datetime::AsRfc3339String>")]
-            pub date_optional_none: Option<DateTime>,
+        #[serde_as(as = "Option<datetime::AsRfc3339String>")]
+        pub date_optional_none: Option<DateTime>,
 
-            #[serde_as(as = "Option<bson_datetime::AsRfc3339String>")]
-            pub date_optional_some: Option<DateTime>,
+        #[serde_as(as = "Option<datetime::AsRfc3339String>")]
+        pub date_optional_some: Option<DateTime>,
 
-            #[serde_as(as = "Vec<bson_datetime::AsRfc3339String>")]
-            pub date_vector: Vec<DateTime>,
-        }
+        #[serde_as(as = "Vec<datetime::AsRfc3339String>")]
+        pub date_vector: Vec<DateTime>,
+    }
 
-        let iso = "1996-12-20T00:39:57Z";
-        let date = DateTime::parse_rfc3339_str(iso).unwrap();
-        let a = A {
-            date,
-            date_optional_none: None,
-            date_optional_some: Some(date),
-            date_vector: vec![date],
-        };
+    let iso = "1996-12-20T00:39:57Z";
+    let date = DateTime::parse_rfc3339_str(iso).unwrap();
+    let a = A {
+        date,
+        date_optional_none: None,
+        date_optional_some: Some(date),
+        date_vector: vec![date],
+    };
 
-        // Serialize the struct to BSON
-        let doc = serialize_to_document(&a).unwrap();
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
 
-        // Validate serialized data
-        assert_eq!(
-            doc.get_str("date").unwrap(),
-            iso,
-            "Expected serialized date to match original date from RFC 3339 string."
-        );
+    // Validate serialized data
+    assert_eq!(
+        doc.get_str("date").unwrap(),
+        iso,
+        "Expected serialized date to match original date from RFC 3339 string."
+    );
 
-        assert_eq!(
-            doc.get("date_optional_none"),
-            Some(&Bson::Null),
-            "Expected serialized date_optional_none to be None."
-        );
+    assert_eq!(
+        doc.get("date_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized date_optional_none to be None."
+    );
 
-        match doc.get("date_optional_some") {
-            Some(Bson::String(value)) => {
-                assert_eq!(
-                    value, iso,
-                    "Expected serialized date_optional_some to match original date."
-                )
-            }
-            _ => panic!("Expected serialized date_optional_some to be a BSON String."),
-        }
+    assert_eq!(
+        doc.get("date_optional_some"),
+        Some(&Bson::String(iso.to_string())),
+        "Expected serialized date_optional_some to match original."
+    );
 
-        let date_vector = doc
-            .get_array("date_vector")
-            .expect("Expected serialized date_vector to be a BSON array.");
-        let expected_date_vector: Vec<Bson> = a
-            .date_vector
-            .iter()
-            .map(|dt| Bson::String(dt.try_to_rfc3339_string().unwrap()))
-            .collect();
-        assert_eq!(
-            date_vector, &expected_date_vector,
-            "Expected each serialized element in date_vector to match the original."
-        );
+    let date_vector = doc
+        .get_array("date_vector")
+        .expect("Expected serialized date_vector to be a BSON array.");
+    let expected_date_vector: Vec<Bson> = vec![Bson::String(date.try_to_rfc3339_string().unwrap())];
+    assert_eq!(
+        date_vector, &expected_date_vector,
+        "Expected each serialized element in date_vector to match the original."
+    );
 
-        // Deserialize the BSON back to the struct
-        let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
 
-        // Validate deserialized data
-        assert_eq!(
-            a_deserialized.date, date,
-            "Expected deserialized date to match the original."
-        );
+    // Validate deserializing error case with an invalid DateTime string
+    let invalid_doc = doc! {
+        "date": "not_a_valid_date",
+        "date_optional_none": Bson::Null,
+        "date_optional_some": "also_invalid_date",
+        "date_vector": ["bad1", "bad2"]
+    };
+    let result: Result<A, _> = deserialize_from_document(invalid_doc);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for invalid DateTime strings"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("BSON error"),
+        "Expected error message to mention BSON error: {}",
+        err_string
+    );
 
-        assert_eq!(
-            a_deserialized.date_optional_none, None,
-            "Expected deserialized date_optional_none to be None."
-        );
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct B {
+        #[serde_as(as = "datetime::FromRfc3339String")]
+        pub date: String,
 
-        assert_eq!(
-            a_deserialized.date_optional_some,
-            Some(date),
-            "Expected deserialized date_optional_some to match the original."
-        );
+        #[serde_as(as = "Option<datetime::FromRfc3339String>")]
+        pub date_optional_none: Option<String>,
 
-        assert_eq!(
-            a_deserialized.date_vector,
-            vec![date],
-            "Expected deserialized date_vector to match the original."
-        );
+        #[serde_as(as = "Option<datetime::FromRfc3339String>")]
+        pub date_optional_some: Option<String>,
 
-        // Validate deserializing error case with an invalid DateTime string
-        let invalid_doc = doc! {
-            "date": "not_a_valid_date",
-            "date_optional_none": Bson::Null,
-            "date_optional_some": "also_invalid_date",
-            "date_vector": ["bad1", "bad2"]
-        };
-        let result: Result<A, _> = deserialize_from_document(invalid_doc);
-        assert!(
-            result.is_err(),
-            "Deserialization should fail for invalid DateTime strings"
-        );
-        let err_string = format!("{:?}", result.unwrap_err());
-        assert!(
-            err_string.contains("BSON error"),
-            "Expected error message to mention BSON error: {}",
-            err_string
-        );
+        #[serde_as(as = "Vec<datetime::FromRfc3339String>")]
+        pub date_vector: Vec<String>,
     }
 
-    #[cfg(feature = "time-0_3")]
-    {
-        use time::macros::datetime;
+    let date = DateTime::now();
+    let b = B {
+        date: date.try_to_rfc3339_string().unwrap(),
+        date_optional_none: None,
+        date_optional_some: Some(date.try_to_rfc3339_string().unwrap()),
+        date_vector: vec![date.try_to_rfc3339_string().unwrap()],
+    };
 
-        #[derive(Deserialize, Serialize)]
-        struct B {
-            #[serde(with = "serde_helpers::time_0_3_offsetdatetime_as_bson_datetime")]
-            pub date: time::OffsetDateTime,
-        }
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&b).unwrap();
 
-        let date = r#"
-    {
-        "date": {
-                "$date": {
-                    "$numberLong": "1591700287095"
-                }
-        }
-    }"#;
-        let json: serde_json::Value = serde_json::from_str(date).unwrap();
-        let b: B = serde_json::from_value(json).unwrap();
-        let expected = datetime!(2020-06-09 10:58:07.095 UTC);
-        assert_eq!(b.date, expected);
-        let doc = serialize_to_document(&b).unwrap();
-        assert_eq!(doc.get_datetime("date").unwrap().to_time_0_3(), expected);
-        let b: B = deserialize_from_document(doc).unwrap();
-        assert_eq!(b.date, expected);
-    }
+    // Validate serialized data
+    assert_eq!(
+        *doc.get_datetime("date").unwrap(),
+        date,
+        "Expected serialized date to be a BSON DateTime."
+    );
 
-    #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
-    {
-        use std::str::FromStr;
+    assert_eq!(
+        doc.get("date_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized date_optional_none to be None."
+    );
 
-        #[serde_as]
-        #[derive(Deserialize, Serialize)]
-        struct A {
-            #[serde_as(as = "bson_datetime::FromChronoDateTime")]
-            pub date: chrono::DateTime<chrono::Utc>,
+    assert_eq!(
+        doc.get("date_optional_some"),
+        Some(&Bson::DateTime(date)),
+        "Expected serialized date_optional_some to match original."
+    );
 
-            #[serde_as(as = "Option<bson_datetime::FromChronoDateTime>")]
-            pub date_optional_none: Option<chrono::DateTime<chrono::Utc>>,
+    let date_vector = doc
+        .get_array("date_vector")
+        .expect("Expected serialized date_vector to be a BSON array.");
+    let expected_date_vector: Vec<Bson> = vec![Bson::DateTime(date)];
+    assert_eq!(
+        date_vector, &expected_date_vector,
+        "Expected each serialized element in date_vector match the original."
+    );
 
-            #[serde_as(as = "Option<bson_datetime::FromChronoDateTime>")]
-            pub date_optional_some: Option<chrono::DateTime<chrono::Utc>>,
+    // Validate deserialized data
+    let b_deserialized: B = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        b_deserialized, b,
+        "Deserialized struct does not match original."
+    );
 
-            #[serde_as(as = "Vec<bson_datetime::FromChronoDateTime>")]
-            pub date_vector: Vec<chrono::DateTime<chrono::Utc>>,
-        }
+    // Validate serializing error case with an invalid DateTime string
+    let invalid_date = "invalid_date";
+    let bad_b = B {
+        date: invalid_date.to_string(),
+        date_optional_none: None,
+        date_optional_some: Some(invalid_date.to_string()),
+        date_vector: vec![invalid_date.to_string()],
+    };
+    let result = serialize_to_document(&bad_b);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for invalid DateTime strings"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("BSON error"),
+        "Expected error message to mention BSON error: {}",
+        err_string
+    );
+}
 
-        let iso = "1996-12-20T00:39:57Z";
-        let date: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_str(iso).unwrap();
-        let a: A = A {
-            date,
-            date_optional_none: None,
-            date_optional_some: Some(date),
-            date_vector: vec![date],
-        };
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_datetime_i64_helper() {
+    let _guard = LOCK.run_concurrently();
 
-        // Serialize the struct to BSON
-        let doc = serialize_to_document(&a).unwrap();
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "datetime::FromI64")]
+        date: i64,
 
-        // Validate serialized data
-        assert_eq!(
-            doc.get_datetime("date").unwrap().to_chrono(),
-            date,
-            "Expected serialized date to match original date."
-        );
+        #[serde_as(as = "Option<datetime::FromI64>")]
+        date_optional_none: Option<i64>,
 
-        assert_eq!(
-            doc.get("date_optional_none"),
-            Some(&Bson::Null),
-            "Expected serialized date_optional_none to be None."
-        );
+        #[serde_as(as = "Option<datetime::FromI64>")]
+        date_optional_some: Option<i64>,
 
-        match doc.get("date_optional_some") {
-            Some(Bson::DateTime(value)) => {
-                assert_eq!(
-                    *value,
-                    DateTime::from_chrono(date),
-                    "Expected serialized date_optional_some to match original."
-                )
-            }
-            _ => panic!("Expected serialized date_optional_some to be a BSON DateTime."),
-        }
+        #[serde_as(as = "Vec<datetime::FromI64>")]
+        date_vector: Vec<i64>,
+    }
 
-        let date_vector = doc
-            .get_array("date_vector")
-            .expect("Expected serialized date_vector to be a BSON array.");
-        let expected_date_vector: Vec<Bson> = a
-            .date_vector
-            .into_iter()
-            .map(|dt| Bson::DateTime(dt.into()))
-            .collect();
-        assert_eq!(
-            date_vector, &expected_date_vector,
-            "Expected each serialized element in date_vector to be a BSON DateTime matching the \
-             original."
-        );
+    let date = DateTime::now();
+    let a = A {
+        date: date.timestamp_millis(),
+        date_optional_none: None,
+        date_optional_some: Some(date.timestamp_millis()),
+        date_vector: vec![date.timestamp_millis()],
+    };
 
-        // Deserialize the BSON back to the struct
-        let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
 
-        // Validate deserialized data
-        assert_eq!(
-            a_deserialized.date, date,
-            "Expected deserialized date to match original."
-        );
+    // Validate serialized data
+    assert_eq!(
+        doc.get_datetime("date").unwrap(),
+        &date,
+        "Expected serialized date to match original date."
+    );
 
-        assert_eq!(
-            a_deserialized.date_optional_none, None,
-            "Expected deserialized date_optional_none to be None."
-        );
+    assert_eq!(
+        doc.get("date_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized date_optional_none to be None."
+    );
 
-        assert_eq!(
-            a_deserialized.date_optional_some,
-            Some(date),
-            "Expected deserialized date_optional_some to match the original."
-        );
+    assert_eq!(
+        doc.get("date_optional_some"),
+        Some(&Bson::DateTime(date)),
+        "Expected serialized date_optional_some to match original."
+    );
 
-        assert_eq!(
-            a_deserialized.date_vector,
-            vec![date],
-            "Expected deserialized date_vector to match original."
-        );
-    }
+    let date_vector = doc
+        .get_array("date_vector")
+        .expect("Expected serialized date_vector to be a BSON array.");
+    let expected_date_vector: Vec<Bson> = vec![Bson::DateTime(date)];
+    assert_eq!(
+        date_vector, &expected_date_vector,
+        "Expected each serialized element in date_vector match the original."
+    );
 
-    #[cfg(feature = "serde_with-3")]
-    {
-        #[serde_as]
-        #[derive(Deserialize, Serialize)]
-        struct C {
-            #[serde_as(as = "bson_datetime::FromRfc3339String")]
-            pub date: String,
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+}
 
-            #[serde_as(as = "Option<bson_datetime::FromRfc3339String>")]
-            pub date_optional_none: Option<String>,
+#[test]
+#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
+fn test_datetime_chrono04_datetime_helper() {
+    let _guard = LOCK.run_concurrently();
 
-            #[serde_as(as = "Option<bson_datetime::FromRfc3339String>")]
-            pub date_optional_some: Option<String>,
+    use std::str::FromStr;
 
-            #[serde_as(as = "Vec<bson_datetime::FromRfc3339String>")]
-            pub date_vector: Vec<String>,
-        }
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "datetime::FromChrono04DateTime")]
+        pub date: chrono::DateTime<chrono::Utc>,
 
-        let date = "2020-06-09T10:58:07.095Z";
-        let c = C {
-            date: date.to_string(),
-            date_optional_none: None,
-            date_optional_some: Some(date.to_string()),
-            date_vector: vec![date.to_string()],
-        };
+        #[serde_as(as = "Option<datetime::FromChrono04DateTime>")]
+        pub date_optional_none: Option<chrono::DateTime<chrono::Utc>>,
 
-        // Serialize the struct to BSON
-        let doc = serialize_to_document(&c).unwrap();
+        #[serde_as(as = "Option<datetime::FromChrono04DateTime>")]
+        pub date_optional_some: Option<chrono::DateTime<chrono::Utc>>,
 
-        // Validate serialized data
-        assert!(
-            doc.get_datetime("date").is_ok(),
-            "Expected serialized date to be a BSON DateTime."
-        );
+        #[serde_as(as = "Vec<datetime::FromChrono04DateTime>")]
+        pub date_vector: Vec<chrono::DateTime<chrono::Utc>>,
+    }
 
-        assert_eq!(
-            doc.get("date_optional_none"),
-            Some(&Bson::Null),
-            "Expected serialized date_optional_none to be None."
-        );
+    let iso = "1996-12-20T00:39:57Z";
+    let date: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_str(iso).unwrap();
+    let a: A = A {
+        date,
+        date_optional_none: None,
+        date_optional_some: Some(date),
+        date_vector: vec![date],
+    };
 
-        let expected_date = DateTime::from_time_0_3(
-            OffsetDateTime::parse(date, &Rfc3339)
-                .expect("Failed to parse date string into DateTime."),
-        );
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
 
-        match doc.get("date_optional_some") {
-            Some(Bson::DateTime(value)) => {
-                assert_eq!(
-                    *value, expected_date,
-                    "Expected serialized date_optional_some to match original."
-                )
-            }
-            _ => panic!("Expected serialized date_optional_some to be a BSON String."),
-        }
+    // Validate serialized data
+    assert_eq!(
+        doc.get_datetime("date").unwrap().to_chrono(),
+        date,
+        "Expected serialized date to match original date."
+    );
 
-        let date_vector = doc
-            .get_array("date_vector")
-            .expect("Expected serialized date_vector to be a BSON array.");
-        let expected_date_vector: Vec<Bson> = c
-            .date_vector
-            .into_iter()
-            .map(|dt| Bson::DateTime(DateTime::parse_rfc3339_str(dt).unwrap()))
-            .collect();
-        assert_eq!(
-            date_vector, &expected_date_vector,
-            "Expected each serialized element in date_vector match the original."
-        );
+    assert_eq!(
+        doc.get("date_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized date_optional_none to be None."
+    );
 
-        // Deserialize the BSON back to the struct
-        let c_deserialized: C = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        doc.get("date_optional_some"),
+        Some(&Bson::DateTime(DateTime::from_chrono(date))),
+        "Expected serialized date_optional_some to match original."
+    );
 
-        // Validate deserialized data
-        assert_eq!(
-            c_deserialized.date,
-            date.to_string(),
-            "Expected deserialized date to match original."
-        );
+    let date_vector = doc
+        .get_array("date_vector")
+        .expect("Expected serialized date_vector to be a BSON array.");
+    let expected_date_vector: Vec<Bson> = vec![Bson::DateTime(date.into())];
+    assert_eq!(
+        date_vector, &expected_date_vector,
+        "Expected each serialized element in date_vector to be a BSON DateTime matching the \
+         original."
+    );
 
-        assert_eq!(
-            c_deserialized.date_optional_none, None,
-            "Expected deserialized date_optional_none to be None."
-        );
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+}
 
-        assert_eq!(
-            c_deserialized.date_optional_some,
-            Some(date.to_string()),
-            "Expected deserialized date_optional_some to match original."
-        );
+#[test]
+#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
+fn test_datetime_time03_offset_datetime_helper() {
+    use time::OffsetDateTime;
+    let _guard = LOCK.run_concurrently();
 
-        assert_eq!(
-            c_deserialized.date_vector,
-            vec![date.to_string()],
-            "Expected deserialized date_vector to match original."
-        );
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "datetime::FromTime03OffsetDateTime")]
+        pub date: OffsetDateTime,
 
-        // Validate serializing error case with an invalid DateTime string
-        let invalid_date = "invalid_date";
-        let bad_c = C {
-            date: invalid_date.to_string(),
-            date_optional_none: None,
-            date_optional_some: Some(invalid_date.to_string()),
-            date_vector: vec![invalid_date.to_string()],
-        };
-        let result = serialize_to_document(&bad_c);
-        assert!(
-            result.is_err(),
-            "Deserialization should fail for invalid DateTime strings"
-        );
-        let err_string = format!("{:?}", result.unwrap_err());
-        assert!(
-            err_string.contains("BSON error"),
-            "Expected error message to mention BSON error: {}",
-            err_string
-        );
+        #[serde_as(as = "Option<datetime::FromTime03OffsetDateTime>")]
+        pub date_optional_none: Option<OffsetDateTime>,
+
+        #[serde_as(as = "Option<datetime::FromTime03OffsetDateTime>")]
+        pub date_optional_some: Option<OffsetDateTime>,
+
+        #[serde_as(as = "Vec<datetime::FromTime03OffsetDateTime>")]
+        pub date_vector: Vec<OffsetDateTime>,
     }
+
+    let date = DateTime::now();
+    let a: A = A {
+        date: date.to_time_0_3(),
+        date_optional_none: None,
+        date_optional_some: Some(date.to_time_0_3()),
+        date_vector: vec![date.to_time_0_3()],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_datetime("date").unwrap(),
+        &date,
+        "Expected serialized date to match original date."
+    );
+
+    assert_eq!(
+        doc.get("date_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized date_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("date_optional_some"),
+        Some(&Bson::DateTime(date)),
+        "Expected serialized date_optional_some to match original."
+    );
+
+    let date_vector = doc
+        .get_array("date_vector")
+        .expect("Expected serialized date_vector to be a BSON array.");
+    let expected_date_vector: Vec<Bson> = vec![Bson::DateTime(date)];
+    assert_eq!(
+        date_vector, &expected_date_vector,
+        "Expected each serialized element in date_vector to be a BSON DateTime matching the \
+         original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
 }
 
 #[test]
@@ -1334,26 +1346,6 @@ fn test_oid_helpers() {
     }
 }
 
-#[test]
-fn test_i64_as_bson_datetime() {
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Serialize, Deserialize)]
-    struct A {
-        #[serde(with = "i64_as_bson_datetime")]
-        now: i64,
-    }
-
-    let now = DateTime::now();
-    let a = A {
-        now: now.timestamp_millis(),
-    };
-    let doc = serialize_to_document(&a).unwrap();
-    assert_eq!(doc.get_datetime("now").unwrap(), &now);
-    let a: A = deserialize_from_document(doc).unwrap();
-    assert_eq!(a.now, now.timestamp_millis());
-}
-
 #[test]
 #[cfg(feature = "uuid-1")]
 fn test_uuid_1_helpers() {

From 3b34ff9f2f73fe7f4e367c4a1703f36f2f993a48 Mon Sep 17 00:00:00 2001
From: Jamie Tsai <49384456+JamieTsai1024@users.noreply.github.com>
Date: Mon, 21 Jul 2025 11:04:40 -0400
Subject: [PATCH 140/156] RUST-1748 Convert unsigned serde helpers to use
 serde_conv  (#575)

---
 src/extjson/models.rs |  12 +-
 src/serde_helpers.rs  | 495 ++++++++++++++----------
 src/tests/serde.rs    | 881 +++++++++++++++++++++++++++++++++++-------
 3 files changed, 1052 insertions(+), 336 deletions(-)

diff --git a/src/extjson/models.rs b/src/extjson/models.rs
index d7107d4e..57c3c978 100644
--- a/src/extjson/models.rs
+++ b/src/extjson/models.rs
@@ -6,8 +6,9 @@ use serde::{
     de::{Error as _, Unexpected},
     Deserialize,
     Serialize,
+    Serializer,
 };
-use std::borrow::Cow;
+use std::{borrow::Cow, result::Result as StdResult};
 
 use crate::{
     base64,
@@ -217,13 +218,18 @@ pub(crate) struct Timestamp {
     body: TimestampBody,
 }
 
+/// Serializes a u32 as an i64.
+fn serialize_u32_as_i64<S: Serializer>(val: &u32, serializer: S) -> StdResult<S::Ok, S::Error> {
+    serializer.serialize_i64(*val as i64)
+}
+
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(deny_unknown_fields)]
 pub(crate) struct TimestampBody {
-    #[serde(serialize_with = "crate::serde_helpers::serialize_u32_as_i64")]
+    #[serde(serialize_with = "serialize_u32_as_i64")]
     pub(crate) t: u32,
 
-    #[serde(serialize_with = "crate::serde_helpers::serialize_u32_as_i64")]
+    #[serde(serialize_with = "serialize_u32_as_i64")]
     pub(crate) i: u32,
 }
 
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index ded62da6..017c18d5 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -1,27 +1,11 @@
 //! Collection of helper functions for serializing to and deserializing from BSON using Serde
-use serde::{de::Visitor, ser, Deserialize, Serialize, Serializer};
+use serde::{de::Visitor, Deserialize, Serialize, Serializer};
 use std::{
-    convert::TryFrom,
     marker::PhantomData,
     ops::{Deref, DerefMut},
     result::Result,
 };
 
-#[doc(inline)]
-pub use timestamp_as_u32::{
-    deserialize as deserialize_timestamp_from_u32,
-    serialize as serialize_timestamp_as_u32,
-};
-#[doc(inline)]
-pub use u32_as_f64::{deserialize as deserialize_u32_from_f64, serialize as serialize_u32_as_f64};
-#[doc(inline)]
-pub use u32_as_timestamp::{
-    deserialize as deserialize_u32_from_timestamp,
-    serialize as serialize_u32_as_timestamp,
-};
-#[doc(inline)]
-pub use u64_as_f64::{deserialize as deserialize_u64_from_f64, serialize as serialize_u64_as_f64};
-
 #[cfg(feature = "uuid-1")]
 #[doc(inline)]
 pub use uuid_1_as_binary::{
@@ -47,35 +31,6 @@ pub use uuid_1_as_python_legacy_binary::{
     serialize as serialize_uuid_1_as_python_legacy_binary,
 };
 
-/// Attempts to serialize a u32 as an i32. Errors if an exact conversion is not possible.
-pub fn serialize_u32_as_i32<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> {
-    match i32::try_from(*val) {
-        Ok(val) => serializer.serialize_i32(val),
-        Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i32", val))),
-    }
-}
-
-/// Serializes a u32 as an i64.
-pub fn serialize_u32_as_i64<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> {
-    serializer.serialize_i64(*val as i64)
-}
-
-/// Attempts to serialize a u64 as an i32. Errors if an exact conversion is not possible.
-pub fn serialize_u64_as_i32<S: Serializer>(val: &u64, serializer: S) -> Result<S::Ok, S::Error> {
-    match i32::try_from(*val) {
-        Ok(val) => serializer.serialize_i32(val),
-        Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i32", val))),
-    }
-}
-
-/// Attempts to serialize a u64 as an i64. Errors if an exact conversion is not possible.
-pub fn serialize_u64_as_i64<S: Serializer>(val: &u64, serializer: S) -> Result<S::Ok, S::Error> {
-    match i64::try_from(*val) {
-        Ok(val) => serializer.serialize_i64(val),
-        Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i64", val))),
-    }
-}
-
 #[cfg(feature = "serde_with-3")]
 pub mod object_id {
     use crate::{macros::serde_conv_doc, oid::ObjectId};
@@ -138,87 +93,6 @@ pub mod object_id {
     );
 }
 
-/// Contains functions to serialize a u32 as an f64 (BSON double) and deserialize a
-/// u32 from an f64 (BSON double).
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::u32_as_f64;
-/// #[derive(Serialize, Deserialize)]
-/// struct FileInfo {
-///     #[serde(with = "u32_as_f64")]
-///     pub size_bytes: u32,
-/// }
-/// ```
-pub mod u32_as_f64 {
-    use serde::{de, Deserialize, Deserializer, Serializer};
-
-    /// Deserializes a u32 from an f64 (BSON double). Errors if an exact conversion is not possible.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let f = f64::deserialize(deserializer)?;
-        if (f - f as u32 as f64).abs() <= f64::EPSILON {
-            Ok(f as u32)
-        } else {
-            Err(de::Error::custom(format!(
-                "cannot convert f64 (BSON double) {} to u32",
-                f
-            )))
-        }
-    }
-
-    /// Serializes a u32 as an f64 (BSON double).
-    pub fn serialize<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> {
-        serializer.serialize_f64(*val as f64)
-    }
-}
-
-/// Contains functions to serialize a u64 as an f64 (BSON double) and deserialize a
-/// u64 from an f64 (BSON double).
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::u64_as_f64;
-/// #[derive(Serialize, Deserialize)]
-/// struct FileInfo {
-///     #[serde(with = "u64_as_f64")]
-///     pub size_bytes: u64,
-/// }
-/// ```
-pub mod u64_as_f64 {
-    use serde::{de, ser, Deserialize, Deserializer, Serializer};
-
-    /// Deserializes a u64 from an f64 (BSON double). Errors if an exact conversion is not possible.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let f = f64::deserialize(deserializer)?;
-        if (f - f as u64 as f64).abs() <= f64::EPSILON {
-            Ok(f as u64)
-        } else {
-            Err(de::Error::custom(format!(
-                "cannot convert f64 (BSON double) {} to u64",
-                f
-            )))
-        }
-    }
-
-    /// Serializes a u64 as an f64 (BSON double). Errors if an exact conversion is not possible.
-    pub fn serialize<S: Serializer>(val: &u64, serializer: S) -> Result<S::Ok, S::Error> {
-        if val < &u64::MAX && *val == *val as f64 as u64 {
-            serializer.serialize_f64(*val as f64)
-        } else {
-            Err(ser::Error::custom(format!(
-                "cannot convert u64 {} to f64 (BSON double)",
-                val
-            )))
-        }
-    }
-}
-
 /// Type converters for serializing and deserializing [`crate::DateTime`] using
 /// [`serde_with::serde_as`].
 ///
@@ -380,6 +254,298 @@ pub mod datetime {
     );
 }
 
+/// Type converters for serializing and deserializing `crate::Timestamp` using
+/// [`serde_with::serde_as`].
+///
+/// ## Available converters
+/// - [`timestamp::AsU32`] — converts a [`crate::Timestamp`] to and from a `u32`.
+/// - [`timestamp::FromU32`] — converts a `u32` to and from a [`crate::Timestamp`].
+#[cfg(feature = "serde_with-3")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
+pub mod timestamp {
+    use crate::{macros::serde_conv_doc, Timestamp};
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
+    use serde_with::{DeserializeAs, SerializeAs};
+    use std::result::Result;
+
+    serde_conv_doc!(
+        /// Converts a [`Timestamp`] to and from a `u32`.
+        ///
+        /// The `u32` should represent seconds since the Unix epoch.
+        ///
+        /// Serialization errors if the Timestamp has a non-zero increment.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::{serde_helpers::timestamp, Timestamp};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "timestamp::AsU32")]
+        ///     pub timestamp: Timestamp,
+        /// }
+        /// # }
+        /// ```
+        pub AsU32,
+        Timestamp,
+        |timestamp: &Timestamp| -> Result<u32, String> {
+            if timestamp.increment != 0 {
+                return Err(format!("Cannot convert Timestamp with a non-zero increment to u32: {:?}", timestamp));
+            }
+            Ok(timestamp.time)
+        },
+        |value: u32| -> Result<Timestamp, String> {
+            Ok(Timestamp { time: value, increment: 0 })
+        }
+    );
+
+    serde_conv_doc!(
+        /// Converts a `u32` to and from a [`Timestamp`].
+        ///
+        /// The `u32` should represent seconds since the Unix epoch.
+        ///
+        /// Deserialization errors if the Timestamp has a non-zero increment.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::serde_helpers::timestamp;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Event {
+        ///     #[serde_as(as = "timestamp::FromU32")]
+        ///     pub time: u32,
+        /// }
+        /// # }
+        /// ```
+        pub FromU32,
+        u32,
+        |value: &u32| -> Result<Timestamp, String> {
+            Ok(Timestamp { time: *value, increment: 0 })
+        },
+        |timestamp: Timestamp| -> Result<u32, String> {
+            if timestamp.increment != 0 {
+                return Err(format!("Cannot convert Timestamp with a non-zero increment to u32: {:?}", timestamp));
+            }
+            Ok(timestamp.time)
+        }
+    );
+}
+
+/// Type converters for serializing and deserializing `u32` using [`serde_with::serde_as`].
+///
+/// ## Available converters
+/// - [`u32::AsF64`] — converts a `u32` to and from an `f64`.
+/// - [`u32::AsI32`] — converts a `u32` to and from an `i32`.
+/// - [`u32::AsI64`] — converts a `u32` to and from an `i64`.
+#[cfg(feature = "serde_with-3")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
+pub mod u32 {
+    use crate::macros::serde_conv_doc;
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
+    use serde_with::{DeserializeAs, SerializeAs};
+    use std::result::Result;
+
+    serde_conv_doc!(
+        /// Converts a `u32` to and from an `f64`.
+        ///
+        /// Deserialization errors if an exact conversion is not possible.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::serde_helpers::u32;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct FileInfo {
+        ///     #[serde_as(as = "u32::AsF64")]
+        ///     pub size_bytes: u32,
+        /// }
+        /// # }
+        /// ```
+        pub AsF64,
+        u32,
+        |value: &u32| -> Result<f64, String> {
+            Ok(f64::from(*value))
+        },
+        |value: f64| -> Result<u32, String> {
+            if (value - value as u32 as f64).abs() <= f64::EPSILON {
+                Ok(value as u32)
+            } else {
+                Err(format!("Cannot convert f64 {} to u32", value))
+            }
+        }
+    );
+
+    serde_conv_doc!(
+        /// Converts a `u32` to and from an `i32`.
+        ///
+        /// Errors if an exact conversion is not possible.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::{serde_helpers::u32};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "u32::AsI32")]
+        ///     pub value: u32,
+        /// }
+        /// # }
+        /// ```
+        pub AsI32,
+        u32,
+        |value: &u32| -> Result<i32, String> {
+            i32::try_from(*value).map_err(|e| format!("Cannot convert u32 {} to i32: {}", value, e))
+        },
+        |value: i32| -> Result<u32, String> {
+            u32::try_from(value).map_err(|e| format!("Cannot convert i32 {} to u32: {}", value, e))
+        }
+    );
+
+    serde_conv_doc!(
+        /// Converts a `u32` to and from an `i64`.
+        ///
+        /// Deserialization errors if an exact conversion is not possible.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::{serde_helpers::u32};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "u32::AsI64")]
+        ///     pub value: u32,
+        /// }
+        /// # }
+        /// ```
+        pub AsI64,
+        u32,
+        |value: &u32| -> Result<i64, String> {
+            Ok(i64::from(*value))
+        },
+        |value: i64| -> Result<u32, String> {
+            u32::try_from(value).map_err(|e| format!("Cannot convert i64 {} to u32: {}", value, e))
+        }
+    );
+}
+
+/// Type converters for serializing and deserializing `u64` using [`serde_with::serde_as`].
+///
+/// ## Available converters
+/// - [`u64::AsF64`] — converts a `u64` to and from an `f64`.
+/// - [`u64::AsI32`] — converts a `u64` to and from an `i32`.
+/// - [`u64::AsI64`] — converts a `u64` to and from an `i64`.
+#[cfg(feature = "serde_with-3")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
+pub mod u64 {
+    use crate::macros::serde_conv_doc;
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
+    use serde_with::{DeserializeAs, SerializeAs};
+    use std::result::Result;
+
+    serde_conv_doc!(
+        /// Converts a `u64` to and from an `f64`.
+        ///
+        /// Errors if an exact conversion is not possible.
+        ///
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::serde_helpers::u64;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct FileInfo {
+        ///     #[serde_as(as = "u64::AsF64")]
+        ///     pub size_bytes: u64,
+        /// }
+        /// # }
+        /// ```
+        pub AsF64,
+        u64,
+        |value: &u64| -> Result<f64, String> {
+            if value < &u64::MAX && *value == *value as f64 as u64 {
+                Ok(*value as f64)
+            } else {
+                Err(format!("Cannot convert u64 {} to f64", value))
+            }
+        },
+        |value: f64| -> Result<u64, String> {
+            if (value - value as u64 as f64).abs() <= f64::EPSILON {
+               Ok(value as u64)
+            } else {
+                Err(format!("Cannot convert f64 {} to u64", value))
+            }
+        }
+    );
+
+    serde_conv_doc!(
+        /// Converts a `u64` to and from an `i32`.
+        ///
+        /// Errors if an exact conversion is not possible.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::{serde_helpers::u64};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "u64::AsI32")]
+        ///     pub value: u64,
+        /// }
+        /// # }
+        /// ```
+        pub AsI32,
+        u64,
+        |value: &u64| -> Result<i32, String> {
+            i32::try_from(*value).map_err(|e| format!("Cannot convert u64 {} to i32: {}", value, e))
+        },
+        |value: i32| -> Result<u64, String> {
+            u64::try_from(value).map_err(|e| format!("Cannot convert i32 {} to u64: {}", value, e))
+        }
+    );
+
+    serde_conv_doc!(
+        /// Converts a `u64` to and from an `i64`.
+        ///
+        /// Errors if an exact conversion is not possible.
+        /// ```rust
+        /// # #[cfg(feature = "serde_with-3")]
+        /// # {
+        /// use bson::{serde_helpers::u64};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "u64::AsI64")]
+        ///     pub value: u64,
+        /// }
+        /// # }
+        /// ```
+        pub AsI64,
+        u64,
+        |value: &u64| -> Result<i64, String> {
+            i64::try_from(*value).map_err(|e| format!("Cannot convert u64 {} to i64: {}", value, e))
+        },
+        |value: i64| -> Result<u64, String> {
+            u64::try_from(value).map_err(|e| format!("Cannot convert i64 {} to u64: {}", value, e))
+        }
+    );
+}
+
 #[allow(unused_macros)]
 macro_rules! as_binary_mod {
     ($feat:meta, $uu:path) => {
@@ -542,81 +708,6 @@ pub mod uuid_1_as_c_sharp_legacy_binary {
     );
 }
 
-/// Contains functions to serialize a u32 as a bson::Timestamp and deserialize a u32 from a
-/// bson::Timestamp. The u32 should represent seconds since the Unix epoch.
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::serde_helpers::u32_as_timestamp;
-/// #[derive(Serialize, Deserialize)]
-/// struct Event {
-///     #[serde(with = "u32_as_timestamp")]
-///     pub time: u32,
-/// }
-/// ```
-pub mod u32_as_timestamp {
-    use crate::{Bson, Timestamp};
-    use serde::{Deserialize, Deserializer, Serialize, Serializer};
-    use std::result::Result;
-
-    /// Serializes a u32 as a bson::Timestamp.
-    pub fn serialize<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> {
-        let timestamp = Bson::Timestamp(Timestamp {
-            time: *val,
-            increment: 0,
-        });
-        timestamp.serialize(serializer)
-    }
-
-    /// Deserializes a u32 from a bson::Timestamp.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let timestamp = Timestamp::deserialize(deserializer)?;
-        Ok(timestamp.time)
-    }
-}
-
-/// Contains functions to serialize a bson::Timestamp as a u32 and deserialize a bson::Timestamp
-/// from a u32. The u32 should represent seconds since the Unix epoch. Serialization will return an
-/// error if the Timestamp has a non-zero increment.
-///
-/// ```rust
-/// # use serde::{Serialize, Deserialize};
-/// # use bson::{serde_helpers::timestamp_as_u32, Timestamp};
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "timestamp_as_u32")]
-///     pub timestamp: Timestamp,
-/// }
-/// ```
-pub mod timestamp_as_u32 {
-    use crate::Timestamp;
-    use serde::{ser, Deserialize, Deserializer, Serializer};
-    use std::result::Result;
-
-    /// Serializes a bson::Timestamp as a u32. Returns an error if the conversion is lossy (i.e. the
-    /// Timestamp has a non-zero increment).
-    pub fn serialize<S: Serializer>(val: &Timestamp, serializer: S) -> Result<S::Ok, S::Error> {
-        if val.increment != 0 {
-            return Err(ser::Error::custom(
-                "Cannot convert Timestamp with a non-zero increment to u32",
-            ));
-        }
-        serializer.serialize_u32(val.time)
-    }
-
-    /// Deserializes a bson::Timestamp from a u32.
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<Timestamp, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let time = u32::deserialize(deserializer)?;
-        Ok(Timestamp { time, increment: 0 })
-    }
-}
-
 /// Wrapping a type in `HumanReadable` signals to the BSON serde integration that it and all
 /// recursively contained types should be serialized to and deserialized from their human-readable
 /// formats.
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 1bbde432..b395ef6b 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -7,7 +7,7 @@ use crate::{
     deserialize_from_document,
     doc,
     oid::ObjectId,
-    serde_helpers::{self, datetime, object_id, timestamp_as_u32, u32_as_timestamp},
+    serde_helpers::{self, datetime, object_id, timestamp, u32, u64},
     serialize_to_bson,
     serialize_to_document,
     spec::BinarySubtype,
@@ -651,95 +651,6 @@ fn test_serialize_deserialize_unsigned_numbers() {
     assert!(doc_result.is_err());
 }
 
-#[test]
-fn test_unsigned_helpers() {
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Serialize)]
-    struct A {
-        #[serde(serialize_with = "serde_helpers::serialize_u32_as_i32")]
-        num_1: u32,
-        #[serde(serialize_with = "serde_helpers::serialize_u64_as_i32")]
-        num_2: u64,
-    }
-
-    let a = A { num_1: 1, num_2: 2 };
-    let doc = serialize_to_document(&a).unwrap();
-    assert!(doc.get_i32("num_1").unwrap() == 1);
-    assert!(doc.get_i32("num_2").unwrap() == 2);
-
-    let a = A {
-        num_1: u32::MAX,
-        num_2: 1,
-    };
-    let doc_result = serialize_to_document(&a);
-    assert!(doc_result.is_err());
-
-    let a = A {
-        num_1: 1,
-        num_2: u64::MAX,
-    };
-    let doc_result = serialize_to_document(&a);
-    assert!(doc_result.is_err());
-
-    #[derive(Serialize)]
-    struct B {
-        #[serde(serialize_with = "serde_helpers::serialize_u32_as_i64")]
-        num_1: u32,
-        #[serde(serialize_with = "serde_helpers::serialize_u64_as_i64")]
-        num_2: u64,
-    }
-
-    let b = B {
-        num_1: u32::MAX,
-        num_2: i64::MAX as u64,
-    };
-    let doc = serialize_to_document(&b).unwrap();
-    assert!(doc.get_i64("num_1").unwrap() == u32::MAX as i64);
-    assert!(doc.get_i64("num_2").unwrap() == i64::MAX);
-
-    let b = B {
-        num_1: 1,
-        num_2: i64::MAX as u64 + 1,
-    };
-    let doc_result = serialize_to_document(&b);
-    assert!(doc_result.is_err());
-
-    #[derive(Deserialize, Serialize, Debug, PartialEq)]
-    struct F {
-        #[serde(with = "serde_helpers::u32_as_f64")]
-        num_1: u32,
-        #[serde(with = "serde_helpers::u64_as_f64")]
-        num_2: u64,
-    }
-
-    let f = F {
-        num_1: 101,
-        num_2: 12345,
-    };
-    let doc = serialize_to_document(&f).unwrap();
-    assert!((doc.get_f64("num_1").unwrap() - 101.0).abs() < f64::EPSILON);
-    assert!((doc.get_f64("num_2").unwrap() - 12345.0).abs() < f64::EPSILON);
-
-    let back: F = deserialize_from_document(doc).unwrap();
-    assert_eq!(back, f);
-
-    let f = F {
-        num_1: 1,
-        // f64 cannot represent many large integers exactly, u64::MAX included
-        num_2: u64::MAX,
-    };
-    let doc_result = serialize_to_document(&f);
-    assert!(doc_result.is_err());
-
-    let f = F {
-        num_1: 1,
-        num_2: u64::MAX - 255,
-    };
-    let doc_result = serialize_to_document(&f);
-    assert!(doc_result.is_err());
-}
-
 #[test]
 #[cfg(feature = "serde_with-3")]
 fn test_datetime_rfc3339_string_helpers() {
@@ -1120,6 +1031,755 @@ fn test_datetime_time03_offset_datetime_helper() {
     );
 }
 
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_timestamp_u32_helpers() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "timestamp::AsU32")]
+        pub timestamp: Timestamp,
+
+        #[serde_as(as = "Option<timestamp::AsU32>")]
+        pub timestamp_optional_none: Option<Timestamp>,
+
+        #[serde_as(as = "Option<timestamp::AsU32>")]
+        pub timestamp_optional_some: Option<Timestamp>,
+
+        #[serde_as(as = "Vec<timestamp::AsU32>")]
+        pub timestamp_vector: Vec<Timestamp>,
+    }
+
+    let time = 12345;
+    let timestamp = Timestamp { time, increment: 0 };
+    let a = A {
+        timestamp,
+        timestamp_optional_none: None,
+        timestamp_optional_some: Some(timestamp),
+        timestamp_vector: vec![timestamp],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get("timestamp").unwrap(),
+        &Bson::Int64(time as i64),
+        "Expected serialized time to match the original."
+    );
+
+    assert_eq!(
+        doc.get("timestamp_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized timestamp_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("timestamp_optional_some"),
+        Some(&Bson::Int64(time as i64)),
+        "Expected serialized timestamp_optional_some to match original time."
+    );
+
+    let timestamp_vector = doc
+        .get_array("timestamp_vector")
+        .expect("Expected serialized timestamp_vector to be a BSON array.");
+    let expected_timestamp_vector: Vec<Bson> = vec![Bson::Int64(time as i64)];
+    assert_eq!(
+        timestamp_vector, &expected_timestamp_vector,
+        "Expected each serialized element in timestamp_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+
+    // Validate serializing error case with an invalid Timestamp
+    let invalid_timestamp_for_serializing = Timestamp {
+        time: 0,
+        increment: 2,
+    };
+    let bad_a: A = A {
+        timestamp: invalid_timestamp_for_serializing,
+        timestamp_optional_none: None,
+        timestamp_optional_some: Some(invalid_timestamp_for_serializing),
+        timestamp_vector: vec![invalid_timestamp_for_serializing],
+    };
+    let result = serialize_to_document(&bad_a);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for Timestamp with increment != 0"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert Timestamp with a non-zero increment to u32"),
+        "Expected error message to mention non-zero increment: {}",
+        err_string
+    );
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct B {
+        #[serde_as(as = "timestamp::FromU32")]
+        pub time: u32,
+
+        #[serde_as(as = "Option<timestamp::FromU32>")]
+        pub time_optional_none: Option<u32>,
+
+        #[serde_as(as = "Option<timestamp::FromU32>")]
+        pub time_optional_some: Option<u32>,
+
+        #[serde_as(as = "Vec<timestamp::FromU32>")]
+        pub time_vector: Vec<u32>,
+    }
+
+    let time = 12345;
+    let b = B {
+        time,
+        time_optional_none: None,
+        time_optional_some: Some(time),
+        time_vector: vec![time],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&b).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_timestamp("time").unwrap(),
+        Timestamp { time, increment: 0 },
+        "Expected serialized time to match the original."
+    );
+
+    assert_eq!(
+        doc.get("time_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized time_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("time_optional_some"),
+        Some(&Bson::Timestamp(Timestamp { time, increment: 0 })),
+        "Expected serialized time_optional_some to match original."
+    );
+
+    let time_vector = doc
+        .get_array("time_vector")
+        .expect("Expected serialized time_vector to be a BSON array.");
+    let expected_time_vector: Vec<Bson> = vec![Bson::Timestamp(Timestamp { time, increment: 0 })];
+    assert_eq!(
+        time_vector, &expected_time_vector,
+        "Expected each serialized element in time_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let b_deserialized: B = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        b_deserialized, b,
+        "Deserialized struct does not match original."
+    );
+
+    // Validate deserializing error case with an invalid Timestamp
+    let invalid_timestamp_for_deserializing = Timestamp {
+        time: 0,
+        increment: 2,
+    };
+    let invalid_doc = doc! {
+        "time": invalid_timestamp_for_deserializing,
+        "time_optional_none": Bson::Null,
+        "time_optional_some": Some(invalid_timestamp_for_deserializing),
+        "time_vector": [invalid_timestamp_for_deserializing]
+    };
+    let result: Result<B, _> = deserialize_from_document(invalid_doc);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for Timestamp with increment != 0"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert Timestamp with a non-zero increment to u32"),
+        "Expected error message to mention non-zero increment: {}",
+        err_string
+    );
+}
+
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_u32_f64_helper() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "u32::AsF64")]
+        pub value: u32,
+
+        #[serde_as(as = "Option<u32::AsF64>")]
+        pub value_optional_none: Option<u32>,
+
+        #[serde_as(as = "Option<u32::AsF64>")]
+        pub value_optional_some: Option<u32>,
+
+        #[serde_as(as = "Vec<u32::AsF64>")]
+        pub value_vector: Vec<u32>,
+    }
+
+    let value = 12345;
+    let a = A {
+        value,
+        value_optional_none: None,
+        value_optional_some: Some(value),
+        value_vector: vec![value],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get("value"),
+        Some(&Bson::Double(value as f64)),
+        "Expected serialized value to match the original."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized value_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_some"),
+        Some(&Bson::Double(value as f64)),
+        "Expected serialized value_optional_some to match original."
+    );
+
+    let value_vector = doc
+        .get_array("value_vector")
+        .expect("Expected serialized value_vector to be a BSON array.");
+    let expected_value_vector: Vec<Bson> = vec![Bson::Double(value as f64)];
+    assert_eq!(
+        value_vector, &expected_value_vector,
+        "Expected each serialized element in value_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+}
+
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_u32_i32_helper() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    struct A {
+        #[serde_as(as = "u32::AsI32")]
+        value: u32,
+
+        #[serde_as(as = "Option<u32::AsI32>")]
+        value_optional_none: Option<u32>,
+
+        #[serde_as(as = "Option<u32::AsI32>")]
+        value_optional_some: Option<u32>,
+
+        #[serde_as(as = "Vec<u32::AsI32>")]
+        value_vector: Vec<u32>,
+    }
+
+    let value = 1;
+    let a = A {
+        value,
+        value_optional_none: None,
+        value_optional_some: Some(value),
+        value_vector: vec![value],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_i32("value").unwrap(),
+        value as i32,
+        "Expected serialized value to match original."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized value_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_some"),
+        Some(&Bson::Int32(value as i32)),
+        "Expected serialized value_optional_some to match original."
+    );
+
+    let value_vector = doc
+        .get_array("value_vector")
+        .expect("Expected serialized value_vector to be a BSON array.");
+    let expected_value_vector: Vec<Bson> = vec![Bson::Int32(value as i32)];
+    assert_eq!(
+        value_vector, &expected_value_vector,
+        "Expected each serialized element in value_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+
+    // Validate serialization fails because u32::MAX is too large to fit in i32
+    let invalid_value_for_serializing = u32::MAX;
+    let bad_a: A = A {
+        value: invalid_value_for_serializing,
+        value_optional_none: None,
+        value_optional_some: Some(invalid_value_for_serializing),
+        value_vector: vec![invalid_value_for_serializing],
+    };
+    let result = serialize_to_document(&bad_a);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for u32::MAX since it can't be exactly represented as i32"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert u32"),
+        "Expected error message to mention failed u32 to i32 conversion, got: {}",
+        err_string
+    );
+
+    // Validate deserialization fails for i32::MIN because negative values can't be converted to
+    // u32
+    let invalid_value_for_deserializing = i32::MIN;
+    let bad_a = doc! {
+        "value": invalid_value_for_deserializing,
+        "value_optional_none": Bson::Null,
+        "value_optional_some": Some(invalid_value_for_deserializing),
+        "value_vector": [invalid_value_for_deserializing],
+    };
+    let result: Result<A, _> = deserialize_from_document(bad_a);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for i32::MIN since it can't be exactly represented as u32"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert i32"),
+        "Expected error message to mention failed i32 to u32 conversion, got: {}",
+        err_string
+    );
+}
+
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_u32_i64_helper() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    struct A {
+        #[serde_as(as = "u32::AsI64")]
+        value: u32,
+
+        #[serde_as(as = "Option<u32::AsI64>")]
+        value_optional_none: Option<u32>,
+
+        #[serde_as(as = "Option<u32::AsI64>")]
+        value_optional_some: Option<u32>,
+
+        #[serde_as(as = "Vec<u32::AsI64>")]
+        value_vector: Vec<u32>,
+    }
+
+    let value = u32::MAX;
+    let a = A {
+        value,
+        value_optional_none: None,
+        value_optional_some: Some(value),
+        value_vector: vec![value],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_i64("value").unwrap(),
+        value as i64,
+        "Expected serialized value to match original."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized value_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_some"),
+        Some(&Bson::Int64(value as i64)),
+        "Expected serialized value_optional_some to match original."
+    );
+
+    let value_vector = doc
+        .get_array("value_vector")
+        .expect("Expected serialized value_vector to be a BSON array.");
+    let expected_value_vector: Vec<Bson> = vec![Bson::Int64(value as i64)];
+    assert_eq!(
+        value_vector, &expected_value_vector,
+        "Expected each serialized element in value_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Round-trip failed: deserialized struct did not match original."
+    );
+
+    // Validate deserialization fails for i64::MIN because negative values can't be converted to
+    // u32
+    let invalid_value_for_deserializing = i64::MIN;
+    let bad_a = doc! {
+        "value": invalid_value_for_deserializing,
+        "value_optional_none": Bson::Null,
+        "value_optional_some": Some(invalid_value_for_deserializing),
+        "value_vector": [invalid_value_for_deserializing],
+    };
+    let result: Result<A, _> = deserialize_from_document(bad_a);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for i64::MIN since it can't be exactly represented as u32"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert i64"),
+        "Expected error message to mention failed i64 to u32 conversion, got: {}",
+        err_string
+    );
+}
+
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_u64_f64_helper() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "u64::AsF64")]
+        pub value: u64,
+
+        #[serde_as(as = "Option<u64::AsF64>")]
+        pub value_optional_none: Option<u64>,
+
+        #[serde_as(as = "Option<u64::AsF64>")]
+        pub value_optional_some: Option<u64>,
+
+        #[serde_as(as = "Vec<u64::AsF64>")]
+        pub value_vector: Vec<u64>,
+    }
+
+    let value = 12345;
+    let a = A {
+        value,
+        value_optional_none: None,
+        value_optional_some: Some(value),
+        value_vector: vec![value],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get("value"),
+        Some(&Bson::Double(value as f64)),
+        "Expected serialized value to match the original."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized value_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_some"),
+        Some(&Bson::Double(value as f64)),
+        "Expected serialized value_optional_some to match original."
+    );
+
+    let value_vector = doc
+        .get_array("value_vector")
+        .expect("Expected serialized value_vector to be a BSON array.");
+    let expected_value_vector: Vec<Bson> = vec![Bson::Double(value as f64)];
+    assert_eq!(
+        value_vector, &expected_value_vector,
+        "Expected each serialized element in value_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+
+    // Validate serializing error case with u64 over size limit
+    let invalid_value_for_serializing = u64::MAX;
+    let bad_a: A = A {
+        value: invalid_value_for_serializing,
+        value_optional_none: None,
+        value_optional_some: Some(invalid_value_for_serializing),
+        value_vector: vec![invalid_value_for_serializing],
+    };
+    let result = serialize_to_document(&bad_a);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for u64::MAX since it can't be exactly represented as f64"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert u64"),
+        "Expected error message to mention failed u64 to f64 conversion, got: {}",
+        err_string
+    );
+}
+
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_u64_i32_helper() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    struct A {
+        #[serde_as(as = "u64::AsI32")]
+        value: u64,
+
+        #[serde_as(as = "Option<u64::AsI32>")]
+        value_optional_none: Option<u64>,
+
+        #[serde_as(as = "Option<u64::AsI32>")]
+        value_optional_some: Option<u64>,
+
+        #[serde_as(as = "Vec<u64::AsI32>")]
+        value_vector: Vec<u64>,
+    }
+
+    let value = 1;
+    let a = A {
+        value,
+        value_optional_none: None,
+        value_optional_some: Some(value),
+        value_vector: vec![value],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_i32("value").unwrap(),
+        value as i32,
+        "Expected serialized value to match original."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized value_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_some"),
+        Some(&Bson::Int32(value as i32)),
+        "Expected serialized value_optional_some to match original."
+    );
+
+    let value_vector = doc
+        .get_array("value_vector")
+        .expect("Expected serialized value_vector to be a BSON array.");
+    let expected_value_vector: Vec<Bson> = vec![Bson::Int32(value as i32)];
+    assert_eq!(
+        value_vector, &expected_value_vector,
+        "Expected each serialized element in value_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Round-trip failed: deserialized struct did not match original."
+    );
+
+    // Validate serialization fails because i32::MAX + 1 is too large to fit in i32
+    let invalid_value_for_serializing = i32::MAX as u64 + 1;
+    let bad_a: A = A {
+        value: invalid_value_for_serializing,
+        value_optional_none: None,
+        value_optional_some: Some(invalid_value_for_serializing),
+        value_vector: vec![invalid_value_for_serializing],
+    };
+    let result = serialize_to_document(&bad_a);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for u64::MAX since it can't be exactly represented as i32"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert u64"),
+        "Expected error message to mention failed u64 to i32 conversion, got: {}",
+        err_string
+    );
+
+    // Validate deserialization fails for i32::MIN because negative values can't be converted to
+    // u64
+    let invalid_value_for_deserializing = i32::MIN;
+    let bad_a = doc! {
+        "value": invalid_value_for_deserializing,
+        "value_optional_none": Bson::Null,
+        "value_optional_some": Some(invalid_value_for_deserializing),
+        "value_vector": [invalid_value_for_deserializing],
+    };
+    let result: Result<A, _> = deserialize_from_document(bad_a);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for i32::MIN since it can't be exactly represented as u64"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert i32"),
+        "Expected error message to mention failed i32 to u64 conversion, got: {}",
+        err_string
+    );
+}
+
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_u64_i64_helper() {
+    let _guard = LOCK.run_concurrently();
+    #[serde_as]
+    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    struct A {
+        #[serde_as(as = "u64::AsI64")]
+        value: u64,
+
+        #[serde_as(as = "Option<u64::AsI64>")]
+        value_optional_none: Option<u64>,
+
+        #[serde_as(as = "Option<u64::AsI64>")]
+        value_optional_some: Option<u64>,
+
+        #[serde_as(as = "Vec<u64::AsI64>")]
+        value_vector: Vec<u64>,
+    }
+
+    let value = i64::MAX as u64;
+    let a = A {
+        value,
+        value_optional_none: None,
+        value_optional_some: Some(value),
+        value_vector: vec![value],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_i64("value").unwrap(),
+        value as i64,
+        "Expected serialized value to match original."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized value_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("value_optional_some"),
+        Some(&Bson::Int64(value as i64)),
+        "Expected serialized value_optional_some to match original."
+    );
+
+    let value_vector = doc
+        .get_array("value_vector")
+        .expect("Expected serialized value_vector to be a BSON array.");
+    let expected_value_vector: Vec<Bson> = vec![Bson::Int64(value as i64)];
+    assert_eq!(
+        value_vector, &expected_value_vector,
+        "Expected each serialized element in value_vector to match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Round-trip failed: deserialized struct did not match original."
+    );
+
+    // Validate serialization fails because i64::MAX + 1 is too large to fit in i64
+    let invalid_value_for_serializing = i64::MAX as u64 + 1;
+    let bad_a: A = A {
+        value: invalid_value_for_serializing,
+        value_optional_none: None,
+        value_optional_some: Some(invalid_value_for_serializing),
+        value_vector: vec![invalid_value_for_serializing],
+    };
+    let result = serialize_to_document(&bad_a);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for (i64::MAX as u64) + 1 since it can't be exactly \
+         represented as i64"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert u64"),
+        "Expected error message to mention failed u64 to i64 conversion, got: {}",
+        err_string
+    );
+
+    // Validate deserialization fails for i64::MIN because negative values can't be converted to
+    // u64
+    let invalid_value_for_deserializing = i64::MIN;
+    let bad_a = doc! {
+        "value": invalid_value_for_deserializing,
+        "value_optional_none": Bson::Null,
+        "value_optional_some": Some(invalid_value_for_deserializing),
+        "value_vector": [invalid_value_for_deserializing],
+    };
+    let result: Result<A, _> = deserialize_from_document(bad_a);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for i64::MIN since it can't be exactly represented as u64"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("Cannot convert i64"),
+        "Expected error message to mention failed i64 to u64 conversion, got: {}",
+        err_string
+    );
+}
+
 #[test]
 fn test_oid_helpers() {
     let _guard = LOCK.run_concurrently();
@@ -1374,47 +2034,6 @@ fn test_uuid_1_helpers() {
     assert_eq!(a.uuid, uuid);
 }
 
-#[test]
-fn test_timestamp_helpers() {
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Deserialize, Serialize)]
-    struct A {
-        #[serde(with = "u32_as_timestamp")]
-        pub time: u32,
-    }
-
-    let time = 12345;
-    let a = A { time };
-    let doc = serialize_to_document(&a).unwrap();
-    let timestamp = doc.get_timestamp("time").unwrap();
-    assert_eq!(timestamp.time, time);
-    assert_eq!(timestamp.increment, 0);
-    let a: A = deserialize_from_document(doc).unwrap();
-    assert_eq!(a.time, time);
-
-    #[derive(Deserialize, Serialize)]
-    struct B {
-        #[serde(with = "timestamp_as_u32")]
-        pub timestamp: Timestamp,
-    }
-
-    let time = 12345;
-    let timestamp = Timestamp { time, increment: 0 };
-    let b = B { timestamp };
-    let val = serde_json::to_value(b).unwrap();
-    assert_eq!(val["timestamp"], time);
-    let b: B = serde_json::from_value(val).unwrap();
-    assert_eq!(b.timestamp, timestamp);
-
-    let timestamp = Timestamp {
-        time: 12334,
-        increment: 1,
-    };
-    let b = B { timestamp };
-    assert!(serde_json::to_value(b).is_err());
-}
-
 #[test]
 fn large_dates() {
     let _guard = LOCK.run_concurrently();

From aa25c26a8ec6449327a39c32c3043b86a5360e55 Mon Sep 17 00:00:00 2001
From: Jamie Tsai <49384456+JamieTsai1024@users.noreply.github.com>
Date: Mon, 21 Jul 2025 17:21:53 -0400
Subject: [PATCH 141/156] RUST-1748 Apply formatting changes to ObjectId (#578)

---
 src/serde_helpers.rs |  30 ++--
 src/tests/serde.rs   | 403 +++++++++++++++++++------------------------
 2 files changed, 190 insertions(+), 243 deletions(-)

diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 017c18d5..a17d2eea 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -31,22 +31,27 @@ pub use uuid_1_as_python_legacy_binary::{
     serialize as serialize_uuid_1_as_python_legacy_binary,
 };
 
+/// Type converters for serializing and deserializing [`crate::oid::ObjectId`] using
+/// [`serde_with::serde_as`].
+///
+/// ## Available converters
+/// - [`object_id::AsHexString`] — converts an [`crate::oid::ObjectId`] to and from a hex string.
+/// - [`object_id::FromHexString`] — converts a hex string to and from an [`crate::oid::ObjectId`].
 #[cfg(feature = "serde_with-3")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
 pub mod object_id {
     use crate::{macros::serde_conv_doc, oid::ObjectId};
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
 
     serde_conv_doc!(
-        /// Contains functions to serialize an ObjectId as a hex string and deserialize an
-        /// ObjectId from a hex string
+        /// Converts an [`ObjectId`] to and from a hex string.
         /// ```rust
         /// # #[cfg(feature = "serde_with-3")]
-        /// {
-        /// # use serde::{Serialize, Deserialize};
-        /// # use bson::serde_helpers::object_id;
-        /// # use serde_with::serde_as;
-        /// # use bson::oid::ObjectId;
+        /// # {
+        /// use bson::{serde_helpers::object_id, oid::ObjectId};
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
         /// #[serde_as]
         /// #[derive(Serialize, Deserialize)]
         /// struct Item {
@@ -66,14 +71,13 @@ pub mod object_id {
     );
 
     serde_conv_doc!(
-        /// Contains functions to serialize a hex string as an ObjectId and deserialize a
-        /// hex string from an ObjectId
+        /// Converts a hex string to and from an [`ObjectId`].
         /// ```rust
         /// # #[cfg(feature = "serde_with-3")]
-        /// {
-        /// # use serde::{Serialize, Deserialize};
-        /// # use bson::serde_helpers::object_id;
-        /// # use serde_with::serde_as;
+        /// # {
+        /// use bson::serde_helpers::object_id;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
         /// #[serde_as]
         /// #[derive(Serialize, Deserialize)]
         /// struct Item {
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index b395ef6b..cb063a34 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -651,6 +651,175 @@ fn test_serialize_deserialize_unsigned_numbers() {
     assert!(doc_result.is_err());
 }
 
+#[test]
+#[cfg(feature = "serde_with-3")]
+fn test_oid_helpers() {
+    let _guard = LOCK.run_concurrently();
+
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "object_id::AsHexString")]
+        oid: ObjectId,
+
+        #[serde_as(as = "Option<object_id::AsHexString>")]
+        oid_optional_none: Option<ObjectId>,
+
+        #[serde_as(as = "Option<object_id::AsHexString>")]
+        oid_optional_some: Option<ObjectId>,
+
+        #[serde_as(as = "Vec<object_id::AsHexString>")]
+        oid_vector: Vec<ObjectId>,
+    }
+
+    let oid = ObjectId::new();
+    let a = A {
+        oid,
+        oid_optional_none: None,
+        oid_optional_some: Some(oid),
+        oid_vector: vec![oid],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_str("oid").unwrap(),
+        oid.to_hex(),
+        "Expected serialized oid to match original ObjectId as hex string."
+    );
+
+    assert_eq!(
+        doc.get("oid_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized oid_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("oid_optional_some"),
+        Some(&Bson::String(oid.to_hex())),
+        "Expected serialized oid_optional_some to match original."
+    );
+
+    let oid_vector = doc
+        .get_array("oid_vector")
+        .expect("Expected serialized oid_vector to be a BSON array.");
+    let expected_oid_vector: Vec<Bson> = vec![Bson::String(oid.to_hex())];
+    assert_eq!(
+        oid_vector, &expected_oid_vector,
+        "Expected each serialized element in oid_vector match the original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+
+    // Validate deserializing error case with an invalid ObjectId string
+    let invalid_doc = doc! {
+        "oid": "not_a_valid_oid",
+        "oid_optional_none": Bson::Null,
+        "oid_optional_some": "also_invalid_oid",
+        "oid_vector": ["bad1", "bad2"]
+    };
+    let result: Result<A, _> = deserialize_from_document(invalid_doc);
+    assert!(
+        result.is_err(),
+        "Deserialization should fail for invalid ObjectId strings"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("BSON error"),
+        "Expected error message to mention BSON error: {}",
+        err_string
+    );
+
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    struct B {
+        #[serde_as(as = "object_id::FromHexString")]
+        oid: String,
+
+        #[serde_as(as = "Option<object_id::FromHexString>")]
+        oid_optional_none: Option<String>,
+
+        #[serde_as(as = "Option<object_id::FromHexString>")]
+        oid_optional_some: Option<String>,
+
+        #[serde_as(as = "Vec<object_id::FromHexString>")]
+        oid_vector: Vec<String>,
+    }
+
+    let oid = ObjectId::new();
+    let b = B {
+        oid: oid.to_string(),
+        oid_optional_none: None,
+        oid_optional_some: Some(oid.to_string()),
+        oid_vector: vec![oid.to_string()],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&b).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_object_id("oid").unwrap(),
+        oid,
+        "Expected serialized oid to match original ObjectId."
+    );
+
+    assert_eq!(
+        doc.get("oid_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized oid_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("oid_optional_some"),
+        Some(&Bson::ObjectId(oid)),
+        "Expected serialized oid_optional_some to match original."
+    );
+
+    let oid_vector = doc
+        .get_array("oid_vector")
+        .expect("Expected serialized oid_vector to be a BSON array.");
+    let expected_oid_vector: Vec<Bson> = vec![Bson::ObjectId(oid)];
+    assert_eq!(
+        oid_vector, &expected_oid_vector,
+        "Expected each serialized element in oid_vector match the original."
+    );
+
+    // Validate deserialized data
+    let b_deserialized: B = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        b_deserialized, b,
+        "Deserialized struct does not match original."
+    );
+
+    // Validate serializing error case with an invalid ObjectId string
+    let invalid_oid = "invalid_oid";
+    let bad_b = B {
+        oid: invalid_oid.to_string(),
+        oid_optional_none: None,
+        oid_optional_some: Some(invalid_oid.to_string()),
+        oid_vector: vec![invalid_oid.to_string()],
+    };
+    let result = serialize_to_document(&bad_b);
+    assert!(
+        result.is_err(),
+        "Serialization should fail for invalid ObjectId strings"
+    );
+    let err_string = format!("{:?}", result.unwrap_err());
+    assert!(
+        err_string.contains("BSON error"),
+        "Expected error message to mention BSON error: {}",
+        err_string
+    );
+}
+
 #[test]
 #[cfg(feature = "serde_with-3")]
 fn test_datetime_rfc3339_string_helpers() {
@@ -1282,7 +1451,7 @@ fn test_u32_i32_helper() {
     let _guard = LOCK.run_concurrently();
 
     #[serde_as]
-    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
     struct A {
         #[serde_as(as = "u32::AsI32")]
         value: u32,
@@ -1391,7 +1560,7 @@ fn test_u32_i64_helper() {
     let _guard = LOCK.run_concurrently();
 
     #[serde_as]
-    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
     struct A {
         #[serde_as(as = "u32::AsI64")]
         value: u32,
@@ -1568,7 +1737,7 @@ fn test_u64_i32_helper() {
     let _guard = LOCK.run_concurrently();
 
     #[serde_as]
-    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
     struct A {
         #[serde_as(as = "u64::AsI32")]
         value: u64,
@@ -1676,7 +1845,7 @@ fn test_u64_i32_helper() {
 fn test_u64_i64_helper() {
     let _guard = LOCK.run_concurrently();
     #[serde_as]
-    #[derive(Deserialize, Serialize, PartialEq, Debug)]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
     struct A {
         #[serde_as(as = "u64::AsI64")]
         value: u64,
@@ -1780,232 +1949,6 @@ fn test_u64_i64_helper() {
     );
 }
 
-#[test]
-fn test_oid_helpers() {
-    let _guard = LOCK.run_concurrently();
-
-    #[cfg(feature = "serde_with-3")]
-    {
-        #[serde_as]
-        #[derive(Serialize, Deserialize)]
-        struct A {
-            #[serde_as(as = "object_id::FromHexString")]
-            oid: String,
-
-            #[serde_as(as = "Option<object_id::FromHexString>")]
-            oid_optional_none: Option<String>,
-
-            #[serde_as(as = "Option<object_id::FromHexString>")]
-            oid_optional_some: Option<String>,
-
-            #[serde_as(as = "Vec<object_id::FromHexString>")]
-            oid_vector: Vec<String>,
-        }
-
-        let oid = ObjectId::new();
-        let a = A {
-            oid: oid.to_string(),
-            oid_optional_none: None,
-            oid_optional_some: Some(oid.to_string()),
-            oid_vector: vec![oid.to_string()],
-        };
-
-        // Serialize the struct to BSON
-        let doc = serialize_to_document(&a).unwrap();
-
-        // Validate serialized data
-        assert_eq!(
-            doc.get_object_id("oid").unwrap(),
-            oid,
-            "Expected serialized oid to match original ObjectId."
-        );
-
-        assert_eq!(
-            doc.get("oid_optional_none"),
-            Some(&Bson::Null),
-            "Expected serialized oid_optional_none to be None."
-        );
-
-        match doc.get("oid_optional_some") {
-            Some(Bson::ObjectId(value)) => {
-                assert_eq!(
-                    *value, oid,
-                    "Expected serialized oid_optional_some to match original ObjectId."
-                )
-            }
-            _ => {
-                panic!("Expected serialized oid_optional_some to be a BSON ObjectId.")
-            }
-        }
-
-        let oid_vector = doc
-            .get_array("oid_vector")
-            .expect("Expected serialized oid_vector to be a BSON array.");
-        let expected_oid_vector: Vec<Bson> = a
-            .oid_vector
-            .into_iter()
-            .map(|oid| Bson::ObjectId(ObjectId::parse_str(oid).unwrap()))
-            .collect();
-        assert_eq!(
-            oid_vector, &expected_oid_vector,
-            "Expected each serialized element in oid_vector match the original."
-        );
-
-        // Deserialize the BSON back to the struct
-        let a_deserialized: A = deserialize_from_document(doc).unwrap();
-
-        // Validate deserialized data
-        assert_eq!(
-            a_deserialized.oid,
-            oid.to_string(),
-            "Expected deserialized oid to match the original."
-        );
-
-        assert_eq!(
-            a_deserialized.oid_optional_some,
-            Some(oid.to_string()),
-            "Expected deserialized oid_optional_some to match the original."
-        );
-
-        assert_eq!(
-            a_deserialized.oid_vector,
-            vec![oid.to_string()],
-            "Expected deserialized oid_vector to match the original."
-        );
-
-        // Validate serializing error case with an invalid ObjectId string
-        let invalid_oid = "invalid_oid";
-        let bad_a = A {
-            oid: invalid_oid.to_string(),
-            oid_optional_none: None,
-            oid_optional_some: Some(invalid_oid.to_string()),
-            oid_vector: vec![invalid_oid.to_string()],
-        };
-        let result = serialize_to_document(&bad_a);
-        assert!(
-            result.is_err(),
-            "Deserialization should fail for invalid ObjectId strings"
-        );
-        let err_string = format!("{:?}", result.unwrap_err());
-        assert!(
-            err_string.contains("BSON error"),
-            "Expected error message to mention BSON error: {}",
-            err_string
-        );
-
-        #[serde_as]
-        #[derive(Serialize, Deserialize, Debug)]
-        struct B {
-            #[serde_as(as = "object_id::AsHexString")]
-            oid: ObjectId,
-
-            #[serde_as(as = "Option<object_id::AsHexString>")]
-            oid_optional_none: Option<ObjectId>,
-
-            #[serde_as(as = "Option<object_id::AsHexString>")]
-            oid_optional_some: Option<ObjectId>,
-
-            #[serde_as(as = "Vec<object_id::AsHexString>")]
-            oid_vector: Vec<ObjectId>,
-        }
-
-        let oid = ObjectId::new();
-        let b = B {
-            oid,
-            oid_optional_none: None,
-            oid_optional_some: Some(oid),
-            oid_vector: vec![oid],
-        };
-
-        // Serialize the struct to BSON
-        let doc = serialize_to_document(&b).unwrap();
-
-        // Validate serialized data
-        assert_eq!(
-            doc.get_str("oid").unwrap(),
-            oid.to_hex(),
-            "Expected serialized oid to match original ObjectId as hex string."
-        );
-
-        assert_eq!(
-            doc.get("oid_optional_none"),
-            Some(&Bson::Null),
-            "Expected serialized oid_optional_none to be None."
-        );
-
-        match doc.get("oid_optional_some") {
-            Some(Bson::String(value)) => {
-                assert_eq!(
-                    *value,
-                    oid.to_hex(),
-                    "Expected serialized oid_optional_some to match original ObjectId."
-                )
-            }
-            _ => {
-                panic!("Expected serialized oid_optional_some to be a BSON String.")
-            }
-        }
-
-        let oid_vector = doc
-            .get_array("oid_vector")
-            .expect("Expected serialized oid_vector to be a BSON array.");
-        let expected_oid_vector: Vec<Bson> = b
-            .oid_vector
-            .into_iter()
-            .map(|oid| Bson::String(oid.to_hex()))
-            .collect();
-        assert_eq!(
-            oid_vector, &expected_oid_vector,
-            "Expected each serialized element in oid_vector match the original."
-        );
-
-        // Deserialize the BSON back to the struct
-        let b_deserialized: B = deserialize_from_document(doc).unwrap();
-
-        // Validate deserialized data
-        assert_eq!(
-            b_deserialized.oid, oid,
-            "Expected deserialized oid to match the original."
-        );
-
-        assert_eq!(
-            b_deserialized.oid_optional_none, None,
-            "Expected deserialized oid_optional_none to be None."
-        );
-
-        assert_eq!(
-            b_deserialized.oid_optional_some,
-            Some(oid),
-            "Expected deserialized oid_optional_some to match the original."
-        );
-
-        assert_eq!(
-            b_deserialized.oid_vector,
-            vec![oid],
-            "Expected deserialized oid_vector to match the original.."
-        );
-
-        // Validate deserializing error case with an invalid ObjectId string
-        let invalid_doc = doc! {
-            "oid": "not_a_valid_oid",
-            "oid_optional_none": Bson::Null,
-            "oid_optional_some": "also_invalid_oid",
-            "oid_vector": ["bad1", "bad2"]
-        };
-        let result: Result<B, _> = deserialize_from_document(invalid_doc);
-        assert!(
-            result.is_err(),
-            "Deserialization should fail for invalid ObjectId strings"
-        );
-        let err_string = format!("{:?}", result.unwrap_err());
-        assert!(
-            err_string.contains("BSON error"),
-            "Expected error message to mention BSON error: {}",
-            err_string
-        );
-    }
-}
-
 #[test]
 #[cfg(feature = "uuid-1")]
 fn test_uuid_1_helpers() {

From e4601171fcf2182126e58ca7ae2e684448458c42 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 22 Jul 2025 09:36:44 +0100
Subject: [PATCH 142/156] Bump the rust-dependencies group with 4 updates
 (#577)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 21613b68..8448aa4e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -160,9 +160,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.29"
+version = "1.2.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
+checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
 dependencies = [
  "shlex",
 ]
@@ -708,9 +708,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
 
 [[package]]
 name = "rand"
-version = "0.9.1"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
 dependencies = [
  "rand_chacha",
  "rand_core",
@@ -815,9 +815,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "rustix"
-version = "1.0.7"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
 dependencies = [
  "bitflags 2.9.0",
  "errno",
@@ -924,9 +924,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.140"
+version = "1.0.141"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
 dependencies = [
  "indexmap 2.10.0",
  "itoa",

From 266aa3039e603cad96a5dde377aaf8251be76c79 Mon Sep 17 00:00:00 2001
From: Jamie Tsai <49384456+JamieTsai1024@users.noreply.github.com>
Date: Wed, 23 Jul 2025 11:54:59 -0400
Subject: [PATCH 143/156] RUST-1748 Convert UUID serde helpers to use
 serde_conv (#579)

---
 src/serde_helpers.rs | 288 ++++++++++++++++++-----------------
 src/tests/serde.rs   | 348 +++++++++++++++++++++++++++++++++++--------
 src/uuid.rs          |  11 +-
 3 files changed, 445 insertions(+), 202 deletions(-)

diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index a17d2eea..78c7ad9b 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -6,31 +6,6 @@ use std::{
     result::Result,
 };
 
-#[cfg(feature = "uuid-1")]
-#[doc(inline)]
-pub use uuid_1_as_binary::{
-    deserialize as deserialize_uuid_1_from_binary,
-    serialize as serialize_uuid_1_as_binary,
-};
-#[cfg(feature = "uuid-1")]
-#[doc(inline)]
-pub use uuid_1_as_c_sharp_legacy_binary::{
-    deserialize as deserialize_uuid_1_from_c_sharp_legacy_binary,
-    serialize as serialize_uuid_1_as_c_sharp_legacy_binary,
-};
-#[cfg(feature = "uuid-1")]
-#[doc(inline)]
-pub use uuid_1_as_java_legacy_binary::{
-    deserialize as deserialize_uuid_1_from_java_legacy_binary,
-    serialize as serialize_uuid_1_as_java_legacy_binary,
-};
-#[cfg(feature = "uuid-1")]
-#[doc(inline)]
-pub use uuid_1_as_python_legacy_binary::{
-    deserialize as deserialize_uuid_1_from_python_legacy_binary,
-    serialize as serialize_uuid_1_as_python_legacy_binary,
-};
-
 /// Type converters for serializing and deserializing [`crate::oid::ObjectId`] using
 /// [`serde_with::serde_as`].
 ///
@@ -116,7 +91,6 @@ pub mod datetime {
     use chrono::Utc;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
-    use std::result::Result;
 
     serde_conv_doc!(
         /// Converts a [`DateTime`] to and from an RFC 3339 (ISO 8601) formatted string.
@@ -270,7 +244,6 @@ pub mod timestamp {
     use crate::{macros::serde_conv_doc, Timestamp};
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
-    use std::result::Result;
 
     serde_conv_doc!(
         /// Converts a [`Timestamp`] to and from a `u32`.
@@ -351,7 +324,6 @@ pub mod u32 {
     use crate::macros::serde_conv_doc;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
-    use std::result::Result;
 
     serde_conv_doc!(
         /// Converts a `u32` to and from an `f64`.
@@ -454,7 +426,6 @@ pub mod u64 {
     use crate::macros::serde_conv_doc;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
     use serde_with::{DeserializeAs, SerializeAs};
-    use std::result::Result;
 
     serde_conv_doc!(
         /// Converts a `u64` to and from an `f64`.
@@ -550,6 +521,158 @@ pub mod u64 {
     );
 }
 
+/// Type converters for serializing and deserializing [`uuid::Uuid`] using
+/// [`serde_with::serde_as`].
+///
+/// ## Available converters
+/// - [`uuid_1::AsBinary`] — serializes a [`uuid::Uuid`] as a [`crate::Binary`].
+/// - [`uuid_1::AsCSharpLegacyBinary`] — serializes a [`uuid::Uuid`] as a [`crate::Binary`] in the
+///   legacy C# driver UUID format.
+/// - [`uuid_1::AsJavaLegacyBinary`] — serializes a [`uuid::Uuid`] as a [`crate::Binary`] in the
+///   legacy Java driver UUID format.
+/// - [`uuid_1::AsPythonLegacyBinary`] — serializes a [`uuid::Uuid`] as a [`crate::Binary`] in the
+///   legacy Python driver UUID format.
+#[cfg(all(feature = "serde_with-3", feature = "uuid-1"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "serde_with-3", feature = "uuid-1"))))]
+pub mod uuid_1 {
+    use crate::macros::serde_conv_doc;
+    use serde::{Deserialize, Deserializer, Serialize, Serializer};
+    use serde_with::{DeserializeAs, SerializeAs};
+    use uuid::Uuid;
+
+    serde_conv_doc!(
+        /// Serializes a [`Uuid`] as a [`crate::Binary`] and deserializes a [`Uuid`] from a [`crate::Binary`].
+        /// ```rust
+        /// # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::uuid_1;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// use uuid::Uuid;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "uuid_1::AsBinary")]
+        ///     pub id: Uuid,
+        /// }
+        /// # }
+        /// ```
+        pub AsBinary,
+        Uuid,
+        |uuid: &Uuid| -> Result<crate::uuid::Uuid, String> {
+            Ok(crate::uuid::Uuid::from(*uuid))
+        },
+        |bson_uuid: crate::uuid::Uuid| -> Result<Uuid, String> {
+            Ok(bson_uuid.into())
+        }
+    );
+
+    serde_conv_doc!(
+        /// Serializes a [`Uuid`] to a [`crate::Binary`] in the legacy C# driver UUID format and
+        /// deserializes [`Uuid`] from a [`crate::Binary`] in the legacy C# driver format.
+        /// ```rust
+        /// # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::uuid_1;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// use uuid::Uuid;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "uuid_1::AsCSharpLegacyBinary")]
+        ///     pub id: Uuid,
+        /// }
+        /// # }
+        /// ```
+        pub AsCSharpLegacyBinary,
+        Uuid,
+        |uuid: &Uuid| -> Result<crate::Binary, String> {
+            let inner = crate::uuid::Uuid::from(*uuid);
+            Ok(crate::Binary::from_uuid_with_representation(
+                inner,
+                crate::uuid::UuidRepresentation::CSharpLegacy,
+            ))
+        },
+        |binary: crate::Binary| -> Result<Uuid, String> {
+            let inner = binary
+                .to_uuid_with_representation(crate::uuid::UuidRepresentation::CSharpLegacy)
+                .map_err(|e| e.to_string())?;
+            Ok(inner.into())
+        }
+    );
+
+    serde_conv_doc!(
+        /// Serializes a [`Uuid`] to a [`crate::Binary`] in the legacy Java driver UUID format and
+        /// deserializes [`Uuid`] from a [`crate::Binary`] in the legacy Java driver format.
+        /// ```rust
+        /// # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::uuid_1;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// use uuid::Uuid;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "uuid_1::AsJavaLegacyBinary")]
+        ///     pub id: Uuid,
+        /// }
+        /// # }
+        /// ```
+        pub AsJavaLegacyBinary,
+        Uuid,
+        |uuid: &Uuid| -> Result<crate::Binary, String> {
+            let inner = crate::uuid::Uuid::from(*uuid);
+            Ok(crate::Binary::from_uuid_with_representation(
+                inner,
+                crate::uuid::UuidRepresentation::JavaLegacy,
+            ))
+        },
+        |binary: crate::Binary| -> Result<Uuid, String> {
+            let inner = binary
+                .to_uuid_with_representation(crate::uuid::UuidRepresentation::JavaLegacy)
+                .map_err(|e| e.to_string())?;
+            Ok(inner.into())
+        }
+    );
+
+    serde_conv_doc!(
+        /// Serializes a [`Uuid`] to a [`crate::Binary`] in the legacy Python driver UUID format and
+        /// deserializes [`Uuid`] from a [`crate::Binary`] in the legacy Python driver format.
+        /// ```rust
+        /// # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::uuid_1;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// use uuid::Uuid;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Item {
+        ///     #[serde_as(as = "uuid_1::AsPythonLegacyBinary")]
+        ///     pub id: Uuid,
+        /// }
+        /// # }
+        /// ```
+        pub AsPythonLegacyBinary,
+        Uuid,
+        |uuid: &Uuid| -> Result<crate::Binary, String> {
+            let inner = crate::uuid::Uuid::from(*uuid);
+            Ok(crate::Binary::from_uuid_with_representation(
+                inner,
+                crate::uuid::UuidRepresentation::PythonLegacy,
+            ))
+        },
+        |binary: crate::Binary| -> Result<Uuid, String> {
+            let inner = binary
+                .to_uuid_with_representation(crate::uuid::UuidRepresentation::PythonLegacy)
+                .map_err(|e| e.to_string())?;
+            Ok(inner.into())
+        }
+    );
+}
+
 #[allow(unused_macros)]
 macro_rules! as_binary_mod {
     ($feat:meta, $uu:path) => {
@@ -575,29 +698,6 @@ macro_rules! as_binary_mod {
     };
 }
 
-/// Contains functions to serialize a [`uuid::Uuid`] as a [`crate::Binary`] and deserialize a
-/// [`uuid::Uuid`] from a [`crate::Binary`].
-///
-/// ```rust
-/// # #[cfg(feature = "uuid-1")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid::Uuid;
-/// use bson::serde_helpers::uuid_1_as_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_1_as_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-1")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
-pub mod uuid_1_as_binary {
-    as_binary_mod!(cfg(feature = "uuid-1"), uuid::Uuid);
-}
-
 #[allow(unused_macros)]
 macro_rules! as_legacy_binary_mod {
     ($feat:meta, $uu:path, $rep:path) => {
@@ -628,90 +728,6 @@ macro_rules! as_legacy_binary_mod {
     };
 }
 
-/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy
-/// Java driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy
-/// Java driver format.
-///
-/// ```rust
-/// #[cfg(feature = "uuid-1")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid::Uuid;
-/// use bson::serde_helpers::uuid_1_as_java_legacy_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_1_as_java_legacy_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-1")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
-pub mod uuid_1_as_java_legacy_binary {
-    as_legacy_binary_mod!(
-        cfg(feature = "uuid-1"),
-        uuid::Uuid,
-        UuidRepresentation::JavaLegacy
-    );
-}
-
-/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy Python
-/// driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy Python
-/// driver format.
-///
-/// ```rust
-/// # #[cfg(feature = "uuid-1")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid::Uuid;
-/// use bson::serde_helpers::uuid_1_as_python_legacy_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_1_as_python_legacy_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-1")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
-pub mod uuid_1_as_python_legacy_binary {
-    as_legacy_binary_mod!(
-        cfg(feature = "uuid-1"),
-        uuid::Uuid,
-        UuidRepresentation::PythonLegacy
-    );
-}
-
-/// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy C# driver
-/// UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy C# driver
-/// format.
-///
-/// ```rust
-/// # #[cfg(feature = "uuid-1")]
-/// # {
-/// use serde::{Serialize, Deserialize};
-/// use uuid::Uuid;
-/// use bson::serde_helpers::uuid_1_as_c_sharp_legacy_binary;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct Item {
-///     #[serde(with = "uuid_1_as_c_sharp_legacy_binary")]
-///     pub id: Uuid,
-/// }
-/// # }
-/// ```
-#[cfg(feature = "uuid-1")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
-pub mod uuid_1_as_c_sharp_legacy_binary {
-    as_legacy_binary_mod!(
-        cfg(feature = "uuid-1"),
-        uuid::Uuid,
-        UuidRepresentation::CSharpLegacy
-    );
-}
-
 /// Wrapping a type in `HumanReadable` signals to the BSON serde integration that it and all
 /// recursively contained types should be serialized to and deserialized from their human-readable
 /// formats.
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index cb063a34..08c22421 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -24,7 +24,6 @@ use crate::{
 use serde::{Deserialize, Serialize};
 use serde_json::json;
 use serde_with::serde_as;
-
 use std::{
     collections::BTreeMap,
     convert::{TryFrom, TryInto},
@@ -541,54 +540,6 @@ fn test_de_db_pointer() {
     assert_eq!(foo.db_pointer, db_pointer.clone());
 }
 
-#[cfg(feature = "uuid-1")]
-#[test]
-fn test_serde_legacy_uuid_1() {
-    use uuid::Uuid;
-
-    let _guard = LOCK.run_concurrently();
-
-    #[derive(Serialize, Deserialize)]
-    struct Foo {
-        #[serde(with = "serde_helpers::uuid_1_as_java_legacy_binary")]
-        java_legacy: Uuid,
-        #[serde(with = "serde_helpers::uuid_1_as_python_legacy_binary")]
-        python_legacy: Uuid,
-        #[serde(with = "serde_helpers::uuid_1_as_c_sharp_legacy_binary")]
-        csharp_legacy: Uuid,
-    }
-    let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap();
-    let foo = Foo {
-        java_legacy: uuid,
-        python_legacy: uuid,
-        csharp_legacy: uuid,
-    };
-
-    let x = serialize_to_bson(&foo).unwrap();
-    assert_eq!(
-        x.as_document().unwrap(),
-        &doc! {
-            "java_legacy": Bson::Binary(Binary{
-                subtype:BinarySubtype::UuidOld,
-                bytes: hex::decode("7766554433221100FFEEDDCCBBAA9988").unwrap(),
-            }),
-            "python_legacy": Bson::Binary(Binary{
-                subtype:BinarySubtype::UuidOld,
-                bytes: hex::decode("00112233445566778899AABBCCDDEEFF").unwrap(),
-            }),
-            "csharp_legacy": Bson::Binary(Binary{
-                subtype:BinarySubtype::UuidOld,
-                bytes: hex::decode("33221100554477668899AABBCCDDEEFF").unwrap(),
-            })
-        }
-    );
-
-    let foo: Foo = deserialize_from_bson(x).unwrap();
-    assert_eq!(foo.java_legacy, uuid);
-    assert_eq!(foo.python_legacy, uuid);
-    assert_eq!(foo.csharp_legacy, uuid);
-}
-
 #[test]
 fn test_de_uuid_extjson_string() {
     let _guard = LOCK.run_concurrently();
@@ -1950,31 +1901,304 @@ fn test_u64_i64_helper() {
 }
 
 #[test]
-#[cfg(feature = "uuid-1")]
+#[cfg(all(feature = "serde_with-3", feature = "uuid-1"))]
 fn test_uuid_1_helpers() {
-    use serde_helpers::uuid_1_as_binary;
+    use crate::uuid::UuidRepresentation;
+    use serde_helpers::uuid_1;
     use uuid::Uuid;
 
     let _guard = LOCK.run_concurrently();
 
-    #[derive(Serialize, Deserialize)]
+    fn assert_binary_match(
+        actual: &Bson,
+        uuid: &Uuid,
+        expected_subtype: BinarySubtype,
+        uuid_representation: UuidRepresentation,
+    ) {
+        match actual {
+            Bson::Binary(Binary { subtype, bytes }) => {
+                assert_eq!(
+                    subtype, &expected_subtype,
+                    "Expected subtype {:?}, but got {:?}",
+                    expected_subtype, subtype
+                );
+                let expected_bytes = {
+                    let uuid: crate::Uuid = crate::uuid::Uuid::from(*uuid);
+                    crate::Binary::from_uuid_with_representation(uuid, uuid_representation).bytes
+                };
+                assert_eq!(
+                    bytes, &expected_bytes,
+                    "Serialized binary bytes did not match for representation {:?}",
+                    uuid_representation
+                );
+            }
+            other => panic!("Expected Bson::Binary, got {:?}", other),
+        }
+    }
+
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
     struct A {
-        #[serde(with = "uuid_1_as_binary")]
+        #[serde_as(as = "uuid_1::AsBinary")]
         uuid: Uuid,
+
+        #[serde_as(as = "Option<uuid_1::AsBinary>")]
+        uuid_optional_none: Option<Uuid>,
+
+        #[serde_as(as = "Option<uuid_1::AsBinary>")]
+        uuid_optional_some: Option<Uuid>,
+
+        #[serde_as(as = "Vec<uuid_1::AsBinary>")]
+        uuid_vector: Vec<Uuid>,
     }
 
     let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
-    let a = A { uuid };
+    let a: A = A {
+        uuid,
+        uuid_optional_none: None,
+        uuid_optional_some: Some(uuid),
+        uuid_vector: vec![uuid],
+    };
+
+    // Serialize the struct to BSON
     let doc = serialize_to_document(&a).unwrap();
-    match doc.get("uuid").unwrap() {
-        Bson::Binary(bin) => {
-            assert_eq!(bin.subtype, BinarySubtype::Uuid);
-            assert_eq!(bin.bytes, uuid.as_bytes());
-        }
-        _ => panic!("expected Bson::Binary"),
+
+    // Validate serialized data
+    assert_binary_match(
+        doc.get("uuid").unwrap(),
+        &uuid,
+        BinarySubtype::Uuid,
+        UuidRepresentation::Standard,
+    );
+
+    assert_eq!(
+        doc.get("uuid_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized uuid_optional_none to be None."
+    );
+
+    assert_binary_match(
+        doc.get("uuid_optional_some").unwrap(),
+        &uuid,
+        BinarySubtype::Uuid,
+        UuidRepresentation::Standard,
+    );
+
+    let uuid_vector = doc
+        .get_array("uuid_vector")
+        .expect("Expected serialized uuid_vector to be a BSON array.");
+    assert_eq!(uuid_vector.len(), 1);
+    assert_binary_match(
+        &uuid_vector[0],
+        &uuid,
+        BinarySubtype::Uuid,
+        UuidRepresentation::Standard,
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    struct B {
+        #[serde_as(as = "uuid_1::AsCSharpLegacyBinary")]
+        uuid: Uuid,
+
+        #[serde_as(as = "Option<uuid_1::AsCSharpLegacyBinary>")]
+        uuid_optional_none: Option<Uuid>,
+
+        #[serde_as(as = "Option<uuid_1::AsCSharpLegacyBinary>")]
+        uuid_optional_some: Option<Uuid>,
+
+        #[serde_as(as = "Vec<uuid_1::AsCSharpLegacyBinary>")]
+        uuid_vector: Vec<Uuid>,
+    }
+
+    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
+    let b: B = B {
+        uuid,
+        uuid_optional_none: None,
+        uuid_optional_some: Some(uuid),
+        uuid_vector: vec![uuid],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&b).unwrap();
+
+    // Validate serialized data
+    assert_binary_match(
+        doc.get("uuid").unwrap(),
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::CSharpLegacy,
+    );
+
+    assert_eq!(
+        doc.get("uuid_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized uuid_optional_none to be None."
+    );
+
+    assert_binary_match(
+        doc.get("uuid_optional_some").unwrap(),
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::CSharpLegacy,
+    );
+
+    let uuid_vector = doc
+        .get_array("uuid_vector")
+        .expect("Expected uuid_vector to be a BSON array");
+    assert_eq!(uuid_vector.len(), 1);
+    assert_binary_match(
+        &uuid_vector[0],
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::CSharpLegacy,
+    );
+
+    // Validate deserialized data
+    let b_deserialized: B = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        b_deserialized, b,
+        "Deserialized struct does not match original."
+    );
+
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    struct C {
+        #[serde_as(as = "uuid_1::AsJavaLegacyBinary")]
+        uuid: Uuid,
+
+        #[serde_as(as = "Option<uuid_1::AsJavaLegacyBinary>")]
+        uuid_optional_none: Option<Uuid>,
+
+        #[serde_as(as = "Option<uuid_1::AsJavaLegacyBinary>")]
+        uuid_optional_some: Option<Uuid>,
+
+        #[serde_as(as = "Vec<uuid_1::AsJavaLegacyBinary>")]
+        uuid_vector: Vec<Uuid>,
+    }
+
+    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
+    let c: C = C {
+        uuid,
+        uuid_optional_none: None,
+        uuid_optional_some: Some(uuid),
+        uuid_vector: vec![uuid],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&c).unwrap();
+
+    // Validate serialized data
+    assert_binary_match(
+        doc.get("uuid").unwrap(),
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::JavaLegacy,
+    );
+
+    assert_eq!(
+        doc.get("uuid_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized uuid_optional_none to be None."
+    );
+
+    assert_binary_match(
+        doc.get("uuid_optional_some").unwrap(),
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::JavaLegacy,
+    );
+
+    let uuid_vector = doc
+        .get_array("uuid_vector")
+        .expect("Expected uuid_vector to be a BSON array");
+    assert_eq!(uuid_vector.len(), 1);
+    assert_binary_match(
+        &uuid_vector[0],
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::JavaLegacy,
+    );
+
+    // Validate deserialized data
+    let c_deserialized: C = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        c_deserialized, c,
+        "Deserialized struct does not match original."
+    );
+
+    #[serde_as]
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    struct D {
+        #[serde_as(as = "uuid_1::AsPythonLegacyBinary")]
+        uuid: Uuid,
+
+        #[serde_as(as = "Option<uuid_1::AsPythonLegacyBinary>")]
+        uuid_optional_none: Option<Uuid>,
+
+        #[serde_as(as = "Option<uuid_1::AsPythonLegacyBinary>")]
+        uuid_optional_some: Option<Uuid>,
+
+        #[serde_as(as = "Vec<uuid_1::AsPythonLegacyBinary>")]
+        uuid_vector: Vec<Uuid>,
     }
-    let a: A = deserialize_from_document(doc).unwrap();
-    assert_eq!(a.uuid, uuid);
+
+    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
+    let d: D = D {
+        uuid,
+        uuid_optional_none: None,
+        uuid_optional_some: Some(uuid),
+        uuid_vector: vec![uuid],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&d).unwrap();
+
+    // Validate serialized data
+    assert_binary_match(
+        doc.get("uuid").unwrap(),
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::PythonLegacy,
+    );
+
+    assert_eq!(
+        doc.get("uuid_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized uuid_optional_none to be None."
+    );
+
+    assert_binary_match(
+        doc.get("uuid_optional_some").unwrap(),
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::PythonLegacy,
+    );
+
+    let uuid_vector = doc
+        .get_array("uuid_vector")
+        .expect("Expected uuid_vector to be a BSON array");
+    assert_eq!(uuid_vector.len(), 1);
+    assert_binary_match(
+        &uuid_vector[0],
+        &uuid,
+        BinarySubtype::UuidOld,
+        UuidRepresentation::PythonLegacy,
+    );
+
+    // Validate deserialized data
+    let d_deserialized: D = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        d_deserialized, d,
+        "Deserialized struct does not match original."
+    );
 }
 
 #[test]
diff --git a/src/uuid.rs b/src/uuid.rs
index c747fffb..64cad341 100644
--- a/src/uuid.rs
+++ b/src/uuid.rs
@@ -19,12 +19,15 @@
 //! e.g.
 //!
 //! ``` rust
-//! # #[cfg(feature = "uuid-1")]
+//! # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
 //! # {
 //! # use uuid as uuid;
-//! use serde::{Serialize, Deserialize};
 //! use bson::doc;
+//! use serde::{Serialize, Deserialize};
+//! use serde_with::serde_as;
+//!
 //!
+//! #[serde_as]
 //! #[derive(Serialize, Deserialize)]
 //! struct Foo {
 //!     /// serializes as a String or subtype 0 BSON binary, depending
@@ -35,8 +38,8 @@
 //!     bson_uuid: bson::Uuid,
 //!
 //!     /// serializes as a BSON binary with subtype 4 when either is used.
-//!     /// this requires the "uuid-1" feature flag
-//!     #[serde(with = "bson::serde_helpers::uuid_1_as_binary")]
+//!     /// this requires the "uuid-1" and "serde_with-3" feature flags
+//!     #[serde_as(as = "bson::serde_helpers::uuid_1::AsBinary")]
 //!     uuid_as_bson: uuid::Uuid,
 //! }
 //! # };

From 2e4f285a5d6b54ece5ffd85db198dca0ac5f695b Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 24 Jul 2025 16:19:18 -0400
Subject: [PATCH 144/156] RUST-998 / RUST-2244 Documentation improvements
 (#581)

---
 src/binary.rs           |  3 ++-
 src/bson.rs             |  3 ---
 src/datetime.rs         | 14 --------------
 src/error.rs            |  1 +
 src/lib.rs              |  5 +++--
 src/macros.rs           |  1 +
 src/raw/document_buf.rs | 18 ++++++++++++++++++
 src/raw/iter.rs         | 28 +++++++++++++++++++---------
 src/serde_helpers.rs    | 12 ------------
 src/spec.rs             | 35 +++++++++++++++++++----------------
 src/uuid.rs             |  4 ----
 11 files changed, 63 insertions(+), 61 deletions(-)

diff --git a/src/binary.rs b/src/binary.rs
index 9c874d96..3fd0db95 100644
--- a/src/binary.rs
+++ b/src/binary.rs
@@ -1,4 +1,5 @@
-#! Module containing functionality related to BSON binary values.
+//! Contains functionality related to BSON binary values.
+
 mod vector;
 
 use std::fmt::{self, Display};
diff --git a/src/bson.rs b/src/bson.rs
index 69ec9d6d..7a0105e6 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -395,7 +395,6 @@ impl From<oid::ObjectId> for Bson {
 }
 
 #[cfg(feature = "time-0_3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
 impl From<time::OffsetDateTime> for Bson {
     fn from(a: time::OffsetDateTime) -> Bson {
         Bson::DateTime(crate::DateTime::from(a))
@@ -403,7 +402,6 @@ impl From<time::OffsetDateTime> for Bson {
 }
 
 #[cfg(feature = "chrono-0_4")]
-#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
 impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for Bson {
     fn from(a: chrono::DateTime<T>) -> Bson {
         Bson::DateTime(crate::DateTime::from(a))
@@ -411,7 +409,6 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for Bson {
 }
 
 #[cfg(feature = "uuid-1")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
 impl From<uuid::Uuid> for Bson {
     fn from(uuid: uuid::Uuid) -> Self {
         Bson::Binary(uuid.into())
diff --git a/src/datetime.rs b/src/datetime.rs
index 3fc7a20c..c6430016 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -211,7 +211,6 @@ impl crate::DateTime {
     /// Convert the given [`chrono::DateTime`] into a [`bson::DateTime`](DateTime), truncating it to
     /// millisecond precision.
     #[cfg(feature = "chrono-0_4")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
     pub fn from_chrono<T: chrono::TimeZone>(dt: chrono::DateTime<T>) -> Self {
         Self::from_millis(dt.timestamp_millis())
     }
@@ -241,7 +240,6 @@ impl crate::DateTime {
     /// assert_eq!(chrono_big, chrono::DateTime::<chrono::Utc>::MAX_UTC)
     /// ```
     #[cfg(feature = "chrono-0_4")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
     pub fn to_chrono(self) -> chrono::DateTime<Utc> {
         match Utc.timestamp_millis_opt(self.0) {
             LocalResult::Single(dt) => dt,
@@ -324,7 +322,6 @@ impl crate::DateTime {
     /// assert_eq!(time_big, time::PrimitiveDateTime::MIN.assume_utc())
     /// ```
     #[cfg(feature = "time-0_3")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
     pub fn to_time_0_3(self) -> time::OffsetDateTime {
         self.to_time_private()
     }
@@ -453,7 +450,6 @@ impl From<crate::DateTime> for SystemTime {
 }
 
 #[cfg(feature = "chrono-0_4")]
-#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
 impl From<crate::DateTime> for chrono::DateTime<Utc> {
     fn from(bson_dt: DateTime) -> Self {
         bson_dt.to_chrono()
@@ -461,7 +457,6 @@ impl From<crate::DateTime> for chrono::DateTime<Utc> {
 }
 
 #[cfg(feature = "chrono-0_4")]
-#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
 impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
     fn from(x: chrono::DateTime<T>) -> Self {
         Self::from_chrono(x)
@@ -469,10 +464,6 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
 }
 
 #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
-#[cfg_attr(
-    docsrs,
-    doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3")))
-)]
 impl<'de> serde_with::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateTime {
     fn deserialize_as<D>(deserializer: D) -> std::result::Result<chrono::DateTime<Utc>, D::Error>
     where
@@ -484,7 +475,6 @@ impl<'de> serde_with::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateT
 }
 
 #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))]
 impl serde_with::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
     fn serialize_as<S>(
         source: &chrono::DateTime<Utc>,
@@ -499,7 +489,6 @@ impl serde_with::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
 }
 
 #[cfg(feature = "time-0_3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
 impl From<crate::DateTime> for time::OffsetDateTime {
     fn from(bson_dt: DateTime) -> Self {
         bson_dt.to_time_0_3()
@@ -507,7 +496,6 @@ impl From<crate::DateTime> for time::OffsetDateTime {
 }
 
 #[cfg(feature = "time-0_3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
 impl From<time::OffsetDateTime> for crate::DateTime {
     fn from(x: time::OffsetDateTime) -> Self {
         Self::from_time_0_3(x)
@@ -515,7 +503,6 @@ impl From<time::OffsetDateTime> for crate::DateTime {
 }
 
 #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with-3"))))]
 impl<'de> serde_with::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime {
     fn deserialize_as<D>(deserializer: D) -> std::result::Result<time::OffsetDateTime, D::Error>
     where
@@ -527,7 +514,6 @@ impl<'de> serde_with::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTi
 }
 
 #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))]
 impl serde_with::SerializeAs<time::OffsetDateTime> for crate::DateTime {
     fn serialize_as<S>(
         source: &time::OffsetDateTime,
diff --git a/src/error.rs b/src/error.rs
index 9dd62185..fc5ef6dc 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -12,6 +12,7 @@ pub use oid::ObjectIdErrorKind;
 pub use uuid::UuidErrorKind;
 pub use value_access::ValueAccessErrorKind;
 
+/// The result type for all methods that can return an error in the `bson` crate.
 pub type Result<T> = std::result::Result<T, Error>;
 
 /// An error that can occur in the `bson` crate.
diff --git a/src/lib.rs b/src/lib.rs
index 53f72fb8..a5845903 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -373,8 +373,9 @@
 //! is, it will only happen in a minor or major version release.
 
 #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)]
-#![doc(html_root_url = "https://docs.rs/bson/2.6.0")]
-#![cfg_attr(docsrs, feature(doc_cfg))]
+#![doc(html_root_url = "https://docs.rs/bson/3.0.0")]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+#![warn(missing_docs)]
 
 #[doc(inline)]
 pub use self::{
diff --git a/src/macros.rs b/src/macros.rs
index 278ea34a..c66f9e0c 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -449,6 +449,7 @@ macro_rules! serde_conv_doc {
         // https://github.com/jonasbb/serde_with/pull/320
         // https://github.com/jonasbb/serde_with/pull/729
         #[allow(clippy::all)]
+        #[allow(missing_docs)]
         const _:() = {
             impl $m {
                 $vis fn serialize<S>(x: &$t, serializer: S) -> Result<S::Ok, S::Error>
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index 277b5a9a..e167f336 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -85,6 +85,23 @@ impl RawDocumentBuf {
         Ok(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)
+    ///   * the initial four bytes of `data` accurately represent the length of the bytes as
+    ///     required by the BSON spec.
+    ///   * the last byte of `data` is a 0
+    ///
+    /// Note that the internal structure of the bytes representing the
+    /// BSON elements is _not_ validated at all by this method. If the
+    /// bytes do not conform to the BSON spec, then method calls on
+    /// the RawDocument will return Errors where appropriate.
+    ///
+    /// ```
+    /// # use bson::raw::RawDocumentBuf;
+    /// let doc = RawDocumentBuf::decode_from_reader(b"\x05\0\0\0\0".as_slice())?;
+    /// # Ok::<(), bson::error::Error>(())
+    /// ```
     pub fn decode_from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
         let buf = crate::raw::reader_to_vec(reader)?;
         Self::decode_from_bytes(buf)
@@ -333,6 +350,7 @@ impl Borrow<RawDocument> for RawDocumentBuf {
 ///   type Target = BindValue<Self>;
 /// }
 /// ```
+#[allow(missing_docs)]
 pub trait BindRawBsonRef: Sized {
     type Target: BindHelper<Target = Self>;
 
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index ee9d5c27..395f889f 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -109,6 +109,9 @@ impl<'a> RawIter<'a> {
     }
 }
 
+/// A view into a value contained in a [`RawDocument`] or [`RawDocumentBuf`](crate::RawDocumentBuf).
+/// The underlying bytes of the element are not parsed or validated; call [`RawElement::value`] or
+/// one of the `TryFrom` implementations to convert the element into a BSON value.
 #[derive(Clone)]
 pub struct RawElement<'a> {
     key: &'a CStr,
@@ -118,27 +121,27 @@ pub struct RawElement<'a> {
     size: usize,
 }
 
-impl<'a> TryInto<RawBsonRef<'a>> for RawElement<'a> {
+impl<'a> TryFrom<RawElement<'a>> for RawBsonRef<'a> {
     type Error = Error;
 
-    fn try_into(self) -> Result<RawBsonRef<'a>> {
-        self.value()
+    fn try_from(element: RawElement<'a>) -> Result<Self> {
+        element.value()
     }
 }
 
-impl TryInto<RawBson> for RawElement<'_> {
+impl TryFrom<RawElement<'_>> for RawBson {
     type Error = Error;
 
-    fn try_into(self) -> Result<RawBson> {
-        Ok(self.value()?.to_raw_bson())
+    fn try_from(element: RawElement<'_>) -> Result<Self> {
+        Ok(element.value()?.to_raw_bson())
     }
 }
 
-impl TryInto<Bson> for RawElement<'_> {
+impl TryFrom<RawElement<'_>> for Bson {
     type Error = Error;
 
-    fn try_into(self) -> Result<Bson> {
-        self.value()?.to_raw_bson().try_into()
+    fn try_from(element: RawElement<'_>) -> Result<Self> {
+        element.value()?.to_raw_bson().try_into()
     }
 }
 
@@ -157,18 +160,23 @@ impl<'a> RawElement<'a> {
         })
     }
 
+    /// The size of the element.
     pub fn size(&self) -> usize {
         self.size
     }
 
+    /// The document key the element corresponds to.
     pub fn key(&self) -> &'a CStr {
         self.key
     }
 
+    /// The type of the element.
     pub fn element_type(&self) -> ElementType {
         self.kind
     }
 
+    /// Parses this element into a [`RawBsonRef`] and returns an error if the underlying bytes are
+    /// invalid.
     pub fn value(&self) -> Result<RawBsonRef<'a>> {
         Ok(match self.kind {
             ElementType::Null => RawBsonRef::Null,
@@ -270,6 +278,8 @@ impl<'a> RawElement<'a> {
         })
     }
 
+    /// Parses this element into [`RawBson`], replacing any invalid UTF-8 strings with the Unicode
+    /// replacement character. Returns an error if the underlying bytes are invalid.
     pub fn value_utf8_lossy(&self) -> Result<RawBson> {
         match self.value_utf8_lossy_inner()? {
             Some(v) => Ok(v.into()),
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 78c7ad9b..e49caaf0 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -13,7 +13,6 @@ use std::{
 /// - [`object_id::AsHexString`] — converts an [`crate::oid::ObjectId`] to and from a hex string.
 /// - [`object_id::FromHexString`] — converts a hex string to and from an [`crate::oid::ObjectId`].
 #[cfg(feature = "serde_with-3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
 pub mod object_id {
     use crate::{macros::serde_conv_doc, oid::ObjectId};
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -85,7 +84,6 @@ pub mod object_id {
 /// - [`datetime::FromTime03OffsetDateTime`] — converts a [`time::OffsetDateTime`] to and from a
 ///   [`crate::DateTime`].
 #[cfg(feature = "serde_with-3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
 pub mod datetime {
     use crate::{macros::serde_conv_doc, DateTime};
     use chrono::Utc;
@@ -177,7 +175,6 @@ pub mod datetime {
 
     #[cfg(feature = "chrono-0_4")]
     serde_conv_doc!(
-        #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
         /// Converts a [`chrono::DateTime`] to and from a [`DateTime`].
         /// ```rust
         /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
@@ -205,7 +202,6 @@ pub mod datetime {
 
     #[cfg(feature = "time-0_3")]
     serde_conv_doc!(
-        #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))]
         /// Converts a [`time::OffsetDateTime`] to and from a [`DateTime`].
         /// ```rust
         /// # #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
@@ -239,7 +235,6 @@ pub mod datetime {
 /// - [`timestamp::AsU32`] — converts a [`crate::Timestamp`] to and from a `u32`.
 /// - [`timestamp::FromU32`] — converts a `u32` to and from a [`crate::Timestamp`].
 #[cfg(feature = "serde_with-3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
 pub mod timestamp {
     use crate::{macros::serde_conv_doc, Timestamp};
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -319,7 +314,6 @@ pub mod timestamp {
 /// - [`u32::AsI32`] — converts a `u32` to and from an `i32`.
 /// - [`u32::AsI64`] — converts a `u32` to and from an `i64`.
 #[cfg(feature = "serde_with-3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
 pub mod u32 {
     use crate::macros::serde_conv_doc;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -421,7 +415,6 @@ pub mod u32 {
 /// - [`u64::AsI32`] — converts a `u64` to and from an `i32`.
 /// - [`u64::AsI64`] — converts a `u64` to and from an `i64`.
 #[cfg(feature = "serde_with-3")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde_with-3")))]
 pub mod u64 {
     use crate::macros::serde_conv_doc;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -533,7 +526,6 @@ pub mod u64 {
 /// - [`uuid_1::AsPythonLegacyBinary`] — serializes a [`uuid::Uuid`] as a [`crate::Binary`] in the
 ///   legacy Python driver UUID format.
 #[cfg(all(feature = "serde_with-3", feature = "uuid-1"))]
-#[cfg_attr(docsrs, doc(cfg(all(feature = "serde_with-3", feature = "uuid-1"))))]
 pub mod uuid_1 {
     use crate::macros::serde_conv_doc;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -681,13 +673,11 @@ macro_rules! as_binary_mod {
         use $uu;
 
         /// Serializes a Uuid as a Binary.
-        #[cfg_attr(docsrs, doc($feat))]
         pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
             crate::uuid::Uuid::from(*val).serialize(serializer)
         }
 
         /// Deserializes a Uuid from a Binary.
-        #[cfg_attr(docsrs, doc($feat))]
         pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
         where
             D: Deserializer<'de>,
@@ -707,14 +697,12 @@ macro_rules! as_legacy_binary_mod {
         use $uu;
 
         /// Serializes a Uuid as a Binary in the legacy UUID format.
-        #[cfg_attr(docsrs, doc($feat))]
         pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
             let binary = Binary::from_uuid_with_representation(crate::uuid::Uuid::from(*val), $rep);
             binary.serialize(serializer)
         }
 
         /// Deserializes a Uuid from a Binary in the legacy UUID format.
-        #[cfg_attr(docsrs, doc($feat))]
         pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
         where
             D: Deserializer<'de>,
diff --git a/src/spec.rs b/src/spec.rs
index a7b07200..724644b8 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -71,25 +71,25 @@ const BINARY_SUBTYPE_USER_DEFINED: u8 = 0x80;
 #[repr(u8)]
 #[derive(Debug, Eq, PartialEq, Clone, Copy)]
 pub enum ElementType {
-    /// 64-bit binary floating point
+    /// 64-bit binary floating point.
     Double = ELEMENT_TYPE_FLOATING_POINT,
-    /// UTF-8 string
+    /// UTF-8 string.
     String = ELEMENT_TYPE_UTF8_STRING,
-    /// Embedded document
+    /// Embedded document.
     EmbeddedDocument = ELEMENT_TYPE_EMBEDDED_DOCUMENT,
-    /// Array
+    /// Array.
     Array = ELEMENT_TYPE_ARRAY,
-    /// Binary data
+    /// Binary data.
     Binary = ELEMENT_TYPE_BINARY,
-    /// Deprecated. Undefined (value)
+    /// Deprecated.
     Undefined = ELEMENT_TYPE_UNDEFINED,
-    /// [ObjectId](http://dochub.mongodb.org/core/objectids)
+    /// [ObjectId](http://dochub.mongodb.org/core/objectids).
     ObjectId = ELEMENT_TYPE_OBJECT_ID,
-    /// Bool value
+    /// Boolean value.
     Boolean = ELEMENT_TYPE_BOOLEAN,
-    /// UTC datetime
+    /// UTC datetime.
     DateTime = ELEMENT_TYPE_UTC_DATETIME,
-    /// Null value
+    /// Null value.
     Null = ELEMENT_TYPE_NULL_VALUE,
     /// Regular expression - The first cstring is the regex pattern, the second is the regex
     /// options string. Options are identified by characters, which must be stored in
@@ -100,21 +100,23 @@ pub enum ElementType {
     RegularExpression = ELEMENT_TYPE_REGULAR_EXPRESSION,
     /// Deprecated.
     DbPointer = ELEMENT_TYPE_DBPOINTER,
-    /// JavaScript code
+    /// JavaScript code.
     JavaScriptCode = ELEMENT_TYPE_JAVASCRIPT_CODE,
     /// Deprecated.
     Symbol = ELEMENT_TYPE_SYMBOL,
-    /// JavaScript code w/ scope
+    /// JavaScript code with scope.
     JavaScriptCodeWithScope = ELEMENT_TYPE_JAVASCRIPT_CODE_WITH_SCOPE,
-    /// 32-bit integer
+    /// 32-bit integer.
     Int32 = ELEMENT_TYPE_32BIT_INTEGER,
-    /// Timestamp
+    /// Timestamp.
     Timestamp = ELEMENT_TYPE_TIMESTAMP,
-    /// 64-bit integer
+    /// 64-bit integer.
     Int64 = ELEMENT_TYPE_64BIT_INTEGER,
-    /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst)
+    /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst).
     Decimal128 = ELEMENT_TYPE_128BIT_DECIMAL,
+    /// Maximum key.
     MaxKey = ELEMENT_TYPE_MAXKEY,
+    /// Minimum key.
     MinKey = ELEMENT_TYPE_MINKEY,
 }
 
@@ -180,6 +182,7 @@ impl ElementType {
 /// The available binary subtypes, plus a user-defined slot.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 #[non_exhaustive]
+#[allow(missing_docs)]
 pub enum BinarySubtype {
     Generic,
     Function,
diff --git a/src/uuid.rs b/src/uuid.rs
index 64cad341..dcf0cbff 100644
--- a/src/uuid.rs
+++ b/src/uuid.rs
@@ -225,7 +225,6 @@ impl FromStr for Uuid {
 }
 
 #[cfg(feature = "uuid-1")]
-#[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))]
 impl Uuid {
     /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
     /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
@@ -457,7 +456,6 @@ impl Binary {
 macro_rules! trait_impls {
     ($feat:meta, $u:ty) => {
         #[cfg($feat)]
-        #[cfg_attr(docsrs, doc(cfg($feat)))]
         impl From<$u> for Binary {
             fn from(uuid: $u) -> Self {
                 Binary {
@@ -468,7 +466,6 @@ macro_rules! trait_impls {
         }
 
         #[cfg(all($feat, feature = "serde_with-3"))]
-        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))]
         impl<'de> serde_with::DeserializeAs<'de, $u> for crate::Uuid {
             fn deserialize_as<D>(deserializer: D) -> std::result::Result<$u, D::Error>
             where
@@ -481,7 +478,6 @@ macro_rules! trait_impls {
         }
 
         #[cfg(all($feat, feature = "serde_with-3"))]
-        #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))]
         impl serde_with::SerializeAs<$u> for crate::Uuid {
             fn serialize_as<S>(source: &$u, serializer: S) -> std::result::Result<S::Ok, S::Error>
             where

From 3b7e988d83216b8f089814bb995344cf27b52fa3 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Fri, 25 Jul 2025 14:56:46 -0400
Subject: [PATCH 145/156] RUST-2229 Expose raw deserializer (#584)

---
 src/de.rs                |  9 +++------
 src/de/raw.rs            | 20 +++++++++++---------
 src/de/serde.rs          |  4 ++--
 src/lib.rs               |  1 +
 src/tests/spec/corpus.rs |  6 +++---
 5 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/src/de.rs b/src/de.rs
index 969e6a50..d67530da 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -21,7 +21,7 @@
 
 //! Deserializer
 
-mod raw;
+pub(crate) mod raw;
 mod serde;
 
 pub use self::serde::Deserializer;
@@ -40,9 +40,6 @@ use ::serde::{de::DeserializeOwned, Deserialize};
 
 pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor};
 
-#[cfg(test)]
-pub(crate) use self::raw::Deserializer as RawDeserializer;
-
 /// Hint provided to the deserializer via `deserialize_newtype_struct` as to the type of thing
 /// being deserialized.
 #[derive(Debug, Clone, Copy)]
@@ -108,11 +105,11 @@ pub fn deserialize_from_slice<'de, T>(bytes: &'de [u8]) -> Result<T>
 where
     T: Deserialize<'de>,
 {
-    deserialize_from_raw(raw::Deserializer::new(bytes)?)
+    deserialize_from_raw(raw::RawDeserializer::new(bytes)?)
 }
 
 pub(crate) fn deserialize_from_raw<'de, T: Deserialize<'de>>(
-    deserializer: raw::Deserializer<'de>,
+    deserializer: raw::RawDeserializer<'de>,
 ) -> Result<T> {
     #[cfg(feature = "serde_path_to_error")]
     {
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 84ab1ae0..6645c496 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -37,8 +37,8 @@ use crate::{
 use super::{DeserializerHint, Error, Result};
 use crate::de::serde::MapDeserializer;
 
-/// Deserializer mapping from raw bson to serde's data model.
-pub(crate) struct Deserializer<'de> {
+/// Deserializer for deserializing raw BSON bytes.
+pub struct RawDeserializer<'de> {
     element: RawElement<'de>,
     options: DeserializerOptions,
 }
@@ -49,8 +49,10 @@ struct DeserializerOptions {
     human_readable: bool,
 }
 
-impl<'de> Deserializer<'de> {
-    pub(crate) fn new(buf: &'de [u8]) -> Result<Self> {
+impl<'de> RawDeserializer<'de> {
+    /// Construct a `RawDeserializer` with the provided bytes. Returns an error if the basic
+    /// structure of the bytes is invalid.
+    pub fn new(buf: &'de [u8]) -> Result<Self> {
         Ok(Self {
             element: RawElement::toplevel(buf)?,
             options: DeserializerOptions {
@@ -199,7 +201,7 @@ impl<'de> Deserializer<'de> {
     }
 }
 
-impl<'de> serde::de::Deserializer<'de> for Deserializer<'de> {
+impl<'de> serde::de::Deserializer<'de> for RawDeserializer<'de> {
     type Error = Error;
 
     #[inline]
@@ -336,7 +338,7 @@ impl<'de> DocumentAccess<'de> {
         Ok(())
     }
 
-    fn deserializer(self) -> Result<Deserializer<'de>> {
+    fn deserializer(self) -> Result<RawDeserializer<'de>> {
         let elem = match self.elem {
             Some(e) => e,
             None => {
@@ -345,7 +347,7 @@ impl<'de> DocumentAccess<'de> {
                 ))
             }
         };
-        Ok(Deserializer {
+        Ok(RawDeserializer {
             element: elem,
             options: self.options,
         })
@@ -374,7 +376,7 @@ impl<'de> serde::de::MapAccess<'de> for DocumentAccess<'de> {
     {
         match &self.elem {
             None => Err(Error::deserialization("too many values requested")),
-            Some(elem) => seed.deserialize(Deserializer {
+            Some(elem) => seed.deserialize(RawDeserializer {
                 element: elem.clone(),
                 options: self.options.clone(),
             }),
@@ -396,7 +398,7 @@ impl<'de> serde::de::SeqAccess<'de> for DocumentAccess<'de> {
         match &self.elem {
             None => Ok(None),
             Some(elem) => seed
-                .deserialize(Deserializer {
+                .deserialize(RawDeserializer {
                     element: elem.clone(),
                     options: self.options.clone(),
                 })
diff --git a/src/de/serde.rs b/src/de/serde.rs
index 47af21fc..6002f07d 100644
--- a/src/de/serde.rs
+++ b/src/de/serde.rs
@@ -588,7 +588,7 @@ where
     }
 }
 
-/// Serde Deserializer
+/// Deserializer for deserializing a [`Bson`] value.
 pub struct Deserializer {
     value: Option<Bson>,
     options: DeserializerOptions,
@@ -604,7 +604,7 @@ pub(crate) struct DeserializerOptions {
 }
 
 impl Deserializer {
-    /// Construct a new [`Deserializer`] using the default options.
+    /// Construct a `Deserializer` with the provided [`Bson`] value.
     pub fn new(value: Bson) -> Deserializer {
         Deserializer::new_with_options(value, Default::default())
     }
diff --git a/src/lib.rs b/src/lib.rs
index a5845903..ee876ca3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -407,6 +407,7 @@ pub use self::{
         deserialize_from_document,
         deserialize_from_reader,
         deserialize_from_slice,
+        raw::RawDeserializer,
         Deserializer,
     },
     ser::{
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index dccf3e0c..e639a201 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -185,7 +185,7 @@ fn run_test(test: TestFile) {
             if !description.contains("$regex query operator") {
                 // deserialize the field from raw Bytes into a RawBson
                 let deserializer_raw =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
+                    crate::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
                 let raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBsonRef>))
                     .expect(&description);
@@ -197,7 +197,7 @@ fn run_test(test: TestFile) {
 
                 // deserialize the field from raw Bytes into an OwnedRawBson
                 let deserializer_raw =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
+                    crate::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
                 let owned_raw_bson_field = deserializer_raw
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
                     .expect(&description);
@@ -207,7 +207,7 @@ fn run_test(test: TestFile) {
 
                 // deserialize the field from raw Bytes into a Bson
                 let deserializer_value =
-                    crate::de::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
+                    crate::RawDeserializer::new(canonical_bson.as_slice()).unwrap();
                 let bson_field = deserializer_value
                     .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<Bson>))
                     .expect(&description);

From 5f5e41d7cc8c93bb5f89d75f5c81573b58d556e8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 28 Jul 2025 09:57:30 +0100
Subject: [PATCH 146/156] Bump dyn-clone from 1.0.19 to 1.0.20 in the
 rust-dependencies group (#585)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8448aa4e..e3919189 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -348,9 +348,9 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 
 [[package]]
 name = "dyn-clone"
-version = "1.0.19"
+version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
 
 [[package]]
 name = "either"

From 5622ad47769ac039d32701b493927a735a6467d2 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Mon, 28 Jul 2025 17:10:04 +0100
Subject: [PATCH 147/156] RUST-2228 Normalize conversions between raw types and
 base crate types (#580)

---
 fuzz/fuzz_targets/decode.rs                   |   4 +-
 fuzz/fuzz_targets/encoding.rs                 |   4 +-
 fuzz/fuzz_targets/iterate.rs                  |   2 +-
 .../raw_deserialize_utf8_lossy.rs             |   4 +-
 fuzz/fuzz_targets/string_handling.rs          |   2 +-
 fuzz/fuzz_targets/type_markers.rs             |   2 +-
 fuzz/generate_corpus.rs                       |  12 +-
 serde-tests/test.rs                           |  22 +--
 src/de/raw.rs                                 |   3 +-
 src/document.rs                               |  20 +--
 src/lib.rs                                    |   4 +-
 src/raw.rs                                    |  44 +++---
 src/raw/array.rs                              |  15 +-
 src/raw/bson.rs                               |   2 +-
 src/raw/bson_ref.rs                           |  93 ++++++------
 src/raw/document.rs                           | 140 ++++++++++--------
 src/raw/document_buf.rs                       |  55 +++----
 src/raw/iter.rs                               |  22 +--
 src/raw/serde.rs                              |  12 +-
 src/raw/serde/bson_visitor.rs                 |   4 +-
 src/raw/test.rs                               |  10 +-
 src/raw/test/append.rs                        |   2 +-
 src/ser.rs                                    |   2 +-
 src/ser/raw/value_serializer.rs               |   2 +-
 src/ser/serde.rs                              |   3 +-
 src/serde_helpers.rs                          |  96 +-----------
 src/tests/modules/ser.rs                      |   2 +-
 src/tests/modules/serializer_deserializer.rs  | 102 ++++++-------
 src/tests/serde.rs                            |   2 +-
 src/tests/serde_helpers.rs                    |  23 +--
 src/tests/spec/corpus.rs                      |  46 +++---
 src/tests/spec/vector.rs                      |   4 +-
 src/utf8_lossy.rs                             | 100 +++++++++++++
 33 files changed, 430 insertions(+), 430 deletions(-)
 create mode 100644 src/utf8_lossy.rs

diff --git a/fuzz/fuzz_targets/decode.rs b/fuzz/fuzz_targets/decode.rs
index ef71f959..4995394d 100644
--- a/fuzz/fuzz_targets/decode.rs
+++ b/fuzz/fuzz_targets/decode.rs
@@ -7,8 +7,8 @@ use bson::Document;
 use std::io::Cursor;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = Document::decode_from_reader(&mut Cursor::new(&buf[..])) {
+    if let Ok(doc) = Document::from_reader(&mut Cursor::new(&buf[..])) {
         let mut vec = Vec::with_capacity(buf.len());
-        let _ = doc.encode_to_writer(&mut vec);
+        let _ = doc.to_writer(&mut vec);
     }
 });
diff --git a/fuzz/fuzz_targets/encoding.rs b/fuzz/fuzz_targets/encoding.rs
index 99e66cda..d6a7f70f 100644
--- a/fuzz/fuzz_targets/encoding.rs
+++ b/fuzz/fuzz_targets/encoding.rs
@@ -45,12 +45,12 @@ fn compare_values(val1: &Bson, val2: &Bson) -> bool {
 }
 
 fuzz_target!(|input: &[u8]| {
-    if let Ok(rawdoc) = RawDocument::decode_from_bytes(&input) {
+    if let Ok(rawdoc) = RawDocument::from_bytes(&input) {
         if let Ok(doc) = Document::try_from(rawdoc) {
             let out = RawDocumentBuf::try_from(&doc).unwrap();
             let out_bytes = out.as_bytes();
             if input != out_bytes {
-                let reencoded = RawDocument::decode_from_bytes(&out_bytes).unwrap();
+                let reencoded = RawDocument::from_bytes(&out_bytes).unwrap();
                 let reencoded_doc = Document::try_from(reencoded).unwrap();
                 // Ensure that the re-encoded document is the same as the original document, the
                 // bytes can differ while still resulting in the same Document.
diff --git a/fuzz/fuzz_targets/iterate.rs b/fuzz/fuzz_targets/iterate.rs
index 8dc9404a..7dece7ca 100644
--- a/fuzz/fuzz_targets/iterate.rs
+++ b/fuzz/fuzz_targets/iterate.rs
@@ -5,7 +5,7 @@ extern crate bson;
 use bson::RawDocument;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
+    if let Ok(doc) = RawDocument::from_bytes(buf) {
         for _ in doc {}
     }
 });
diff --git a/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs b/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
index cf872965..e44d1f7b 100644
--- a/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
+++ b/fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
@@ -2,10 +2,10 @@
 #[macro_use]
 extern crate libfuzzer_sys;
 extern crate bson;
-use bson::{serde_helpers::Utf8LossyDeserialization, Document};
+use bson::{Document, Utf8Lossy};
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = bson::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(buf) {
+    if let Ok(doc) = bson::deserialize_from_slice::<Utf8Lossy<Document>>(buf) {
         let _ = bson::serialize_to_vec(&doc.0);
     }
 });
diff --git a/fuzz/fuzz_targets/string_handling.rs b/fuzz/fuzz_targets/string_handling.rs
index 3b403bd0..090d132f 100644
--- a/fuzz/fuzz_targets/string_handling.rs
+++ b/fuzz/fuzz_targets/string_handling.rs
@@ -6,7 +6,7 @@ use bson::{RawBsonRef, RawDocument};
 use std::convert::TryInto;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
+    if let Ok(doc) = RawDocument::from_bytes(buf) {
         for elem in doc.iter_elements().flatten() {
             // Convert to RawBsonRef and check string-related types
             if let Ok(bson) = elem.try_into() {
diff --git a/fuzz/fuzz_targets/type_markers.rs b/fuzz/fuzz_targets/type_markers.rs
index f6dd7aa7..3506b96e 100644
--- a/fuzz/fuzz_targets/type_markers.rs
+++ b/fuzz/fuzz_targets/type_markers.rs
@@ -6,7 +6,7 @@ use bson::{RawBsonRef, RawDocument};
 use std::convert::TryInto;
 
 fuzz_target!(|buf: &[u8]| {
-    if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
+    if let Ok(doc) = RawDocument::from_bytes(buf) {
         for elem in doc.iter_elements().flatten() {
             let _: Result<RawBsonRef, _> = elem.try_into();
         }
diff --git a/fuzz/generate_corpus.rs b/fuzz/generate_corpus.rs
index fe5d70b0..ed633684 100644
--- a/fuzz/generate_corpus.rs
+++ b/fuzz/generate_corpus.rs
@@ -30,7 +30,7 @@ fn generate_length_edge_cases(dir: &Path) -> std::io::Result<()> {
     fs::write(
         target_dir.join("min_doc"),
         min_doc
-            .encode_to_vec()
+            .to_vec()
             .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
@@ -39,7 +39,7 @@ fn generate_length_edge_cases(dir: &Path) -> std::io::Result<()> {
     fs::write(
         target_dir.join("large_doc"),
         large_doc
-            .encode_to_vec()
+            .to_vec()
             .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
@@ -78,7 +78,7 @@ fn generate_type_marker_cases(dir: &Path) -> std::io::Result<()> {
     fs::write(
         target_dir.join("all_types"),
         all_types
-            .encode_to_vec()
+            .to_vec()
             .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
@@ -107,7 +107,7 @@ fn generate_string_edge_cases(dir: &Path) -> std::io::Result<()> {
     fs::write(
         target_dir.join("utf8_cases"),
         utf8_cases
-            .encode_to_vec()
+            .to_vec()
             .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
@@ -133,7 +133,7 @@ fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
     fs::write(
         target_dir.join("nested_doc"),
         nested_doc
-            .encode_to_vec()
+            .to_vec()
             .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
@@ -147,7 +147,7 @@ fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
     fs::write(
         target_dir.join("large_binary"),
         large_binary
-            .encode_to_vec()
+            .to_vec()
             .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
     )?;
 
diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index bc8c5e2c..44a6697d 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -21,7 +21,6 @@ use bson::{
     cstr,
     doc,
     oid::ObjectId,
-    serde_helpers::Utf8LossyDeserialization,
     spec::BinarySubtype,
     Binary,
     Bson,
@@ -43,6 +42,7 @@ use bson::{
     RawRegexRef,
     Regex,
     Timestamp,
+    Utf8Lossy,
     Uuid,
 };
 
@@ -59,7 +59,7 @@ fn run_test<T>(expected_value: &T, expected_doc: &Document, description: &str)
 where
     T: Serialize + DeserializeOwned + PartialEq + std::fmt::Debug,
 {
-    let expected_bytes = expected_doc.encode_to_vec().expect(description);
+    let expected_bytes = expected_doc.to_vec().expect(description);
 
     let expected_bytes_serde = bson::serialize_to_vec(&expected_value).expect(description);
 
@@ -104,7 +104,7 @@ fn run_deserialize_test<T>(expected_value: &T, expected_doc: &Document, descript
 where
     T: DeserializeOwned + PartialEq + std::fmt::Debug,
 {
-    let expected_bytes = expected_doc.encode_to_vec().expect(description);
+    let expected_bytes = expected_doc.to_vec().expect(description);
 
     assert_eq!(
         &bson::deserialize_from_document::<T>(expected_doc.clone()).expect(description),
@@ -445,7 +445,7 @@ fn type_conversion() {
     let deserialized: Foo = bson::deserialize_from_document(doc.clone()).unwrap();
     assert_eq!(deserialized, v);
 
-    let bytes = doc.encode_to_vec().unwrap();
+    let bytes = doc.to_vec().unwrap();
 
     let bson_deserialized: Foo = bson::deserialize_from_reader(bytes.as_slice()).unwrap();
     assert_eq!(bson_deserialized, v);
@@ -462,7 +462,7 @@ fn missing_errors() {
 
     bson::deserialize_from_document::<Foo>(doc.clone()).unwrap_err();
 
-    let bytes = doc.encode_to_vec().unwrap();
+    let bytes = doc.to_vec().unwrap();
 
     bson::deserialize_from_reader::<_, Foo>(bytes.as_slice()).unwrap_err();
 }
@@ -681,7 +681,7 @@ fn unused_fields_deny() {
     bson::deserialize_from_document::<Foo>(doc.clone())
         .expect_err("extra fields should cause failure");
 
-    let bytes = doc.encode_to_vec().unwrap();
+    let bytes = doc.to_vec().unwrap();
     bson::deserialize_from_reader::<_, Foo>(bytes.as_slice())
         .expect_err("extra fields should cause failure");
 }
@@ -946,7 +946,7 @@ impl AllTypes {
 
         let decimal = {
             let bytes = hex::decode("18000000136400D0070000000000000000000000003A3000").unwrap();
-            let d = Document::decode_from_reader(bytes.as_slice()).unwrap();
+            let d = Document::from_reader(bytes.as_slice()).unwrap();
             match d.get("d") {
                 Some(Bson::Decimal128(d)) => *d,
                 c => panic!("expected decimal128, got {:?}", c),
@@ -1065,7 +1065,7 @@ fn all_raw_types_rmp() {
         }
     })
     .unwrap();
-    let doc_buf = RawDocumentBuf::decode_from_bytes(doc_bytes).unwrap();
+    let doc_buf = RawDocumentBuf::from_bytes(doc_bytes).unwrap();
     let document = &doc_buf;
     let array = document.get_array("array").unwrap();
 
@@ -1121,7 +1121,7 @@ fn borrowed() {
         "cow": "cow",
         "array": ["borrowed string"],
     };
-    let bson = doc.encode_to_vec().unwrap();
+    let bson = doc.to_vec().unwrap();
 
     let s = "borrowed string".to_string();
     let ss = "another borrowed string".to_string();
@@ -1315,7 +1315,7 @@ fn hint_cleared() {
 
     let bytes = bson::serialize_to_vec(&doc_value).unwrap();
 
-    let doc = RawDocument::decode_from_bytes(&bytes).unwrap();
+    let doc = RawDocument::from_bytes(&bytes).unwrap();
     let binary = doc.get_binary("binary").unwrap();
 
     let f = Foo { doc, binary };
@@ -1336,5 +1336,5 @@ fn invalid_length() {
 fn code_with_scope_too_long() {
     // This is a regression test for fuzzer-generated input (RUST-2241).
     let bytes = base64::decode("KAAAAAsBCRwPAAAACwFAAAAEAA8AEAAAAAYAAAAA9wD5/wAABgALAA==").unwrap();
-    assert!(bson::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(&bytes).is_err());
+    assert!(bson::deserialize_from_slice::<Utf8Lossy<Document>>(&bytes).is_err());
 }
diff --git a/src/de/raw.rs b/src/de/raw.rs
index 6645c496..b8516cf8 100644
--- a/src/de/raw.rs
+++ b/src/de/raw.rs
@@ -19,8 +19,9 @@ use crate::{
         RAW_BSON_NEWTYPE,
         RAW_DOCUMENT_NEWTYPE,
     },
-    serde_helpers::{HUMAN_READABLE_NEWTYPE, UTF8_LOSSY_NEWTYPE},
+    serde_helpers::HUMAN_READABLE_NEWTYPE,
     spec::{BinarySubtype, ElementType},
+    utf8_lossy::UTF8_LOSSY_NEWTYPE,
     uuid::UUID_NEWTYPE_NAME,
     DateTime,
     DbPointer,
diff --git a/src/document.rs b/src/document.rs
index 6069f8d7..95d8b1ac 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -674,8 +674,8 @@ impl Document {
     }
 
     /// Attempt to encode the [`Document`] into a byte [`Vec`].
-    pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
-        Ok(crate::RawDocumentBuf::from_document(self)?.into_bytes())
+    pub fn to_vec(&self) -> Result<Vec<u8>> {
+        Ok(crate::RawDocumentBuf::try_from(self)?.into_bytes())
     }
 
     /// Attempts to encode the [`Document`] into a byte stream.
@@ -690,12 +690,12 @@ impl Document {
     ///
     /// let mut v: Vec<u8> = Vec::new();
     /// let doc = doc! { "x" : 1 };
-    /// doc.encode_to_writer(&mut v)?;
+    /// doc.to_writer(&mut v)?;
     /// # Ok(())
     /// # }
     /// ```
-    pub fn encode_to_writer<W: Write>(&self, mut writer: W) -> crate::error::Result<()> {
-        let buf = crate::RawDocumentBuf::from_document(self)?;
+    pub fn to_writer<W: Write>(&self, mut writer: W) -> crate::error::Result<()> {
+        let buf = crate::RawDocumentBuf::try_from(self)?;
         writer.write_all(buf.as_bytes())?;
         Ok(())
     }
@@ -714,22 +714,22 @@ impl Document {
     ///
     /// let mut v: Vec<u8> = Vec::new();
     /// let doc = doc! { "x" : 1 };
-    /// doc.encode_to_writer(&mut v)?;
+    /// doc.to_writer(&mut v)?;
     ///
     /// // read from mutable reference
     /// let mut reader = Cursor::new(v.clone());
-    /// let doc1 = Document::decode_from_reader(&mut reader)?;
+    /// let doc1 = Document::from_reader(&mut reader)?;
     ///
     /// // read from owned value
-    /// let doc2 = Document::decode_from_reader(Cursor::new(v))?;
+    /// let doc2 = Document::from_reader(Cursor::new(v))?;
     ///
     /// assert_eq!(doc, doc1);
     /// assert_eq!(doc, doc2);
     /// # Ok(())
     /// # }
     /// ```
-    pub fn decode_from_reader<R: Read>(reader: R) -> crate::error::Result<Document> {
-        let raw = crate::raw::RawDocumentBuf::decode_from_reader(reader)?;
+    pub fn from_reader<R: Read>(reader: R) -> crate::error::Result<Document> {
+        let raw = crate::raw::RawDocumentBuf::from_reader(reader)?;
         raw.try_into()
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index ee876ca3..ce6af55c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -133,7 +133,7 @@
 //! use std::io::Read;
 //!
 //! let mut bytes = hex::decode("0C0000001069000100000000").unwrap();
-//! let doc = Document::decode_from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 }
+//! let doc = Document::from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 }
 //!
 //! let doc = doc! {
 //!    "hello": "world",
@@ -396,6 +396,7 @@ pub use self::{
         RawJavaScriptCodeWithScopeRef,
         RawRegexRef,
     },
+    utf8_lossy::Utf8Lossy,
     uuid::{Uuid, UuidRepresentation},
 };
 
@@ -439,6 +440,7 @@ pub mod ser;
 #[cfg(feature = "serde")]
 pub mod serde_helpers;
 pub mod spec;
+mod utf8_lossy;
 pub mod uuid;
 
 #[cfg(test)]
diff --git a/src/raw.rs b/src/raw.rs
index ea802113..74d66a2c 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -1,20 +1,22 @@
 //! An API for interacting with raw BSON bytes.
 //!
-//! This module provides two document types, [`RawDocumentBuf`] and [`RawDocument`] (akin to
-//! [`std::string::String`] and [`str`]), for working with raw BSON documents. These types differ
-//! from the regular [`crate::Document`] type in that their storage is BSON bytes rather than a
-//! hash-map like Rust type. In certain circumstances, these types can be leveraged for increased
+//! This module provides two document types, [`RawDocumentBuf`] and [`&RawDocument`](RawDocument)
+//! (an owned buffer and a reference respectively, akin to [`String`] and [`&str`](str)), for
+//! working with raw BSON documents. These types differ from the regular
+//! [`Document`](crate::Document) type in that their storage is BSON bytes rather than a hash-map
+//! like Rust type. In certain circumstances, these types can be leveraged for increased
 //! performance.
 //!
 //! This module also provides a [`RawBson`] type for modeling any borrowed BSON element and a
 //! [`RawArray`] type for modeling a borrowed slice of a document containing a BSON array element.
 //!
 //! A [`RawDocumentBuf`] can be created from a `Vec<u8>` containing raw BSON data. A
-//! [`RawDocument`] can be created from anything that can be borrowed as a `&[u8]`. Both types
-//! can access elements via methods similar to those available on the [`crate::Document`] type.
-//! Note that [`RawDocument::get`] (which [`RawDocument`] calls through to via its
-//! [`Deref`](std::ops::Deref) implementation) returns a [`Result`], since the bytes contained in
-//! the document are not fully validated until trying to access the contained data.
+//! [`&RawDocument`](RawDocument) can be created from anything that can be borrowed as a `&[u8]`.
+//! Both types can access elements via methods similar to those available on the
+//! [`Document`](crate::Document) type. Note that [`RawDocument::get`] (which [`RawDocumentBuf`]
+//! calls through to via its [`Deref`](std::ops::Deref) implementation) returns a [`Result`], since
+//! the bytes contained in the document are not fully validated until trying to access the contained
+//! data.
 //!
 //! ```rust
 //! use bson::raw::{
@@ -23,7 +25,7 @@
 //! };
 //!
 //! // See http://bsonspec.org/spec.html for details on the binary encoding of BSON.
-//! let doc = RawDocumentBuf::decode_from_bytes(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!(
@@ -33,11 +35,12 @@
 //! # Ok::<(), bson::error::Error>(())
 //! ```
 //!
-//! ### [`crate::Document`] interop
+//! ### [`Document`](crate::Document) interop
 //!
-//! A [`RawDocument`] can be created from a [`crate::Document`]. Internally, this
-//! serializes the [`crate::Document`] to a `Vec<u8>`, and then includes those bytes in the
-//! [`RawDocument`].
+//! A [`RawDocumentBuf`] can be created from a [`Document`](crate::Document) via its [`TryFrom`]
+//! impl. This encodes the `Document` as a byte buffer, and then returns those bytes as a
+//! `RawDocumentBuf`; this will fail if the `Document` contains values not allowed in encoded BSON
+//! (such as embedded nul bytes in string keys).
 //!
 //! ```rust
 //! use bson::{
@@ -51,7 +54,7 @@
 //!    }
 //! };
 //!
-//! let raw = RawDocumentBuf::from_document(&document)?;
+//! let raw = RawDocumentBuf::try_from(&document)?;
 //! let value = raw
 //!     .get_document("goodbye")?
 //!     .get_str("cruel")?;
@@ -63,6 +66,13 @@
 //! # Ok::<(), Box<dyn std::error::Error>>(())
 //! ```
 //!
+//! Conversion in the other direction, from [`&RawDocument`](RawDocument) to
+//! [`Document`](crate::Document), can also be done via [`TryFrom`].  This will fail if the byte
+//! buffer in the `&RawDocument` contains invalid BSON.
+//!
+//! [`RawBson`] and [`RawArrayBuf`] can similary be constructed from their equivalent base crate
+//! types, and their corresponding reference types can be converted to the base crate types.
+//!
 //! ### Reference type ([`RawDocument`])
 //!
 //! A BSON document can also be accessed with the [`RawDocument`] type, which is an
@@ -76,7 +86,7 @@
 //! use bson::raw::RawDocument;
 //!
 //! let bytes = b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00";
-//! assert_eq!(RawDocument::decode_from_bytes(bytes)?.get_str("hi")?, "y'all");
+//! assert_eq!(RawDocument::from_bytes(bytes)?.get_str("hi")?, "y'all");
 //! # Ok::<(), Box<dyn std::error::Error>>(())
 //! ```
 //!
@@ -101,7 +111,7 @@
 //!     "year": "2021",
 //! };
 //!
-//! let doc = RawDocumentBuf::from_document(&original_doc)?;
+//! let doc = RawDocumentBuf::try_from(&original_doc)?;
 //! let mut doc_iter = doc.iter();
 //!
 //! let (key, value): (&CStr, RawBsonRef) = doc_iter.next().unwrap()?;
diff --git a/src/raw/array.rs b/src/raw/array.rs
index 0c6020d3..6be175d3 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -39,7 +39,7 @@ use crate::{
 /// };
 /// let bytes = bson::serialize_to_vec(&doc)?;
 ///
-/// let rawdoc = RawDocument::decode_from_bytes(bytes.as_slice())?;
+/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?;
 /// let rawarray = rawdoc.get_array("x")?;
 ///
 /// for v in rawarray {
@@ -59,9 +59,9 @@ use crate::{
 /// let doc = doc! {
 ///     "x": [1, true, "two", 5.5]
 /// };
-/// let bytes = doc.encode_to_vec()?;
+/// let bytes = doc.to_vec()?;
 ///
-/// let rawdoc = RawDocument::decode_from_bytes(bytes.as_slice())?;
+/// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?;
 /// let rawarray = rawdoc.get_array("x")?;
 ///
 /// assert_eq!(rawarray.get_bool(1)?, true);
@@ -92,13 +92,6 @@ impl RawArray {
         &self.doc
     }
 
-    /// 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_raw_document_buf(self.doc.to_raw_document_buf())
-    }
-
     /// Gets a reference to the value at the given index.
     pub fn get(&self, index: usize) -> RawResult<Option<RawBsonRef<'_>>> {
         self.into_iter().nth(index).transpose()
@@ -250,7 +243,7 @@ impl ToOwned for RawArray {
     type Owned = RawArrayBuf;
 
     fn to_owned(&self) -> Self::Owned {
-        self.to_raw_array_buf()
+        RawArrayBuf::from_raw_document_buf(self.doc.to_owned())
     }
 }
 
diff --git a/src/raw/bson.rs b/src/raw/bson.rs
index e07d8459..5ae88d99 100644
--- a/src/raw/bson.rs
+++ b/src/raw/bson.rs
@@ -429,7 +429,7 @@ impl<'de> serde::Deserialize<'de> for RawBson {
             OwnedOrBorrowedRawBsonVisitor,
         )? {
             OwnedOrBorrowedRawBson::Owned(o) => Ok(o),
-            OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_raw_bson()),
+            OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.into()),
         }
     }
 }
diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs
index 3b50f145..a53fbbe4 100644
--- a/src/raw/bson_ref.rs
+++ b/src/raw/bson_ref.rs
@@ -246,9 +246,53 @@ impl<'a> RawBsonRef<'a> {
         }
     }
 
-    /// Convert this [`RawBsonRef`] to the equivalent [`RawBson`].
-    pub fn to_raw_bson(self) -> RawBson {
+    #[inline]
+    pub(crate) fn append_to(self, dest: &mut Vec<u8>) {
         match self {
+            Self::Int32(val) => dest.extend(val.to_le_bytes()),
+            Self::Int64(val) => dest.extend(val.to_le_bytes()),
+            Self::Double(val) => dest.extend(val.to_le_bytes()),
+            Self::Binary(b @ RawBinaryRef { subtype, bytes }) => {
+                let len = b.len();
+                dest.extend(len.to_le_bytes());
+                dest.push(subtype.into());
+                if let BinarySubtype::BinaryOld = subtype {
+                    dest.extend((len - 4).to_le_bytes())
+                }
+                dest.extend(bytes);
+            }
+            Self::String(s) => write_string(dest, s),
+            Self::Array(raw_array) => dest.extend(raw_array.as_bytes()),
+            Self::Document(raw_document) => dest.extend(raw_document.as_bytes()),
+            Self::Boolean(b) => dest.push(b as u8),
+            Self::RegularExpression(re) => {
+                re.pattern.append_to(dest);
+                re.options.append_to(dest);
+            }
+            Self::JavaScriptCode(js) => write_string(dest, js),
+            Self::JavaScriptCodeWithScope(code_w_scope) => {
+                let len = code_w_scope.len();
+                dest.extend(len.to_le_bytes());
+                write_string(dest, code_w_scope.code);
+                dest.extend(code_w_scope.scope.as_bytes());
+            }
+            Self::Timestamp(ts) => dest.extend(ts.to_le_bytes()),
+            Self::ObjectId(oid) => dest.extend(oid.bytes()),
+            Self::DateTime(dt) => dest.extend(dt.timestamp_millis().to_le_bytes()),
+            Self::Symbol(s) => write_string(dest, s),
+            Self::Decimal128(d) => dest.extend(d.bytes()),
+            Self::DbPointer(dbp) => {
+                write_string(dest, dbp.namespace);
+                dest.extend(dbp.id.bytes());
+            }
+            Self::Null | Self::Undefined | Self::MinKey | Self::MaxKey => {}
+        }
+    }
+}
+
+impl<'a> From<RawBsonRef<'a>> for RawBson {
+    fn from(value: RawBsonRef<'a>) -> Self {
+        match value {
             RawBsonRef::Double(d) => RawBson::Double(d),
             RawBsonRef::String(s) => RawBson::String(s.to_string()),
             RawBsonRef::Array(a) => RawBson::Array(a.to_owned()),
@@ -291,49 +335,6 @@ impl<'a> RawBsonRef<'a> {
             }),
         }
     }
-
-    #[inline]
-    pub(crate) fn append_to(self, dest: &mut Vec<u8>) {
-        match self {
-            Self::Int32(val) => dest.extend(val.to_le_bytes()),
-            Self::Int64(val) => dest.extend(val.to_le_bytes()),
-            Self::Double(val) => dest.extend(val.to_le_bytes()),
-            Self::Binary(b @ RawBinaryRef { subtype, bytes }) => {
-                let len = b.len();
-                dest.extend(len.to_le_bytes());
-                dest.push(subtype.into());
-                if let BinarySubtype::BinaryOld = subtype {
-                    dest.extend((len - 4).to_le_bytes())
-                }
-                dest.extend(bytes);
-            }
-            Self::String(s) => write_string(dest, s),
-            Self::Array(raw_array) => dest.extend(raw_array.as_bytes()),
-            Self::Document(raw_document) => dest.extend(raw_document.as_bytes()),
-            Self::Boolean(b) => dest.push(b as u8),
-            Self::RegularExpression(re) => {
-                re.pattern.append_to(dest);
-                re.options.append_to(dest);
-            }
-            Self::JavaScriptCode(js) => write_string(dest, js),
-            Self::JavaScriptCodeWithScope(code_w_scope) => {
-                let len = code_w_scope.len();
-                dest.extend(len.to_le_bytes());
-                write_string(dest, code_w_scope.code);
-                dest.extend(code_w_scope.scope.as_bytes());
-            }
-            Self::Timestamp(ts) => dest.extend(ts.to_le_bytes()),
-            Self::ObjectId(oid) => dest.extend(oid.bytes()),
-            Self::DateTime(dt) => dest.extend(dt.timestamp_millis().to_le_bytes()),
-            Self::Symbol(s) => write_string(dest, s),
-            Self::Decimal128(d) => dest.extend(d.bytes()),
-            Self::DbPointer(dbp) => {
-                write_string(dest, dbp.namespace);
-                dest.extend(dbp.id.bytes());
-            }
-            Self::Null | Self::Undefined | Self::MinKey | Self::MaxKey => {}
-        }
-    }
 }
 
 #[cfg(feature = "serde")]
@@ -412,7 +413,7 @@ impl<'a> TryFrom<RawBsonRef<'a>> for Bson {
     type Error = Error;
 
     fn try_from(rawbson: RawBsonRef<'a>) -> Result<Bson> {
-        rawbson.to_raw_bson().try_into()
+        RawBson::from(rawbson).try_into()
     }
 }
 
diff --git a/src/raw/document.rs b/src/raw/document.rs
index 8809ceb8..c07e8984 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -12,6 +12,7 @@ use crate::{
     RawBson,
     RawJavaScriptCodeWithScope,
     Timestamp,
+    Utf8Lossy,
 };
 
 use super::{
@@ -47,7 +48,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document};
 /// # use bson::error::Error;
 /// use bson::raw::RawDocument;
 ///
-/// let doc = RawDocument::decode_from_bytes(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");
@@ -64,7 +65,7 @@ use crate::{oid::ObjectId, spec::ElementType, Document};
 /// ```
 /// use bson::raw::RawDocument;
 ///
-/// let doc = RawDocument::decode_from_bytes(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<dyn std::error::Error>>(())
 /// ```
@@ -90,10 +91,10 @@ impl RawDocument {
     /// ```
     /// use bson::raw::RawDocument;
     ///
-    /// let doc = RawDocument::decode_from_bytes(b"\x05\0\0\0\0")?;
+    /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn decode_from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
+    pub fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &D) -> RawResult<&RawDocument> {
         let data = data.as_ref();
 
         if data.len() < 5 {
@@ -127,20 +128,6 @@ impl RawDocument {
         unsafe { &*(data.as_ref() as *const [u8] as *const RawDocument) }
     }
 
-    /// Creates a new [`RawDocumentBuf`] with an owned copy of the BSON bytes.
-    ///
-    /// ```
-    /// use bson::raw::{RawDocument, RawDocumentBuf};
-    ///
-    /// let data = b"\x05\0\0\0\0";
-    /// let doc_ref = RawDocument::decode_from_bytes(data)?;
-    /// let doc: RawDocumentBuf = doc_ref.to_raw_document_buf();
-    /// # Ok::<(), bson::error::Error>(())
-    pub fn to_raw_document_buf(&self) -> RawDocumentBuf {
-        // unwrap is ok here because we already verified the bytes in `RawDocumentRef::new`
-        RawDocumentBuf::decode_from_bytes(self.data.to_owned()).unwrap()
-    }
-
     /// Gets a reference to the value corresponding to the given key by iterating until the key is
     /// found.
     ///
@@ -512,11 +499,6 @@ impl RawDocument {
         s.try_into()
     }
 
-    /// Copy this into a [`Document`], returning an error if invalid BSON is encountered.
-    pub fn to_document(&self) -> RawResult<Document> {
-        self.try_into()
-    }
-
     /// Copy this into a [`Document`], returning an error if invalid BSON is encountered.  Any
     /// invalid UTF-8 sequences will be replaced with the Unicode replacement character.
     pub fn to_document_utf8_lossy(&self) -> RawResult<Document> {
@@ -530,44 +512,6 @@ impl RawDocument {
     }
 }
 
-fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
-    match src {
-        RawBson::Array(arr) => {
-            let mut tmp = vec![];
-            for elem in arr.iter_elements() {
-                tmp.push(deep_utf8_lossy(elem?.value_utf8_lossy()?)?);
-            }
-            Ok(Bson::Array(tmp))
-        }
-        RawBson::Document(doc) => {
-            let mut tmp = doc! {};
-            for elem in doc.iter_elements() {
-                let elem = elem?;
-                tmp.insert(
-                    elem.key().as_str(),
-                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
-                );
-            }
-            Ok(Bson::Document(tmp))
-        }
-        RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code, scope }) => {
-            let mut tmp = doc! {};
-            for elem in scope.iter_elements() {
-                let elem = elem?;
-                tmp.insert(
-                    elem.key().as_str(),
-                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
-                );
-            }
-            Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
-                code,
-                scope: tmp,
-            }))
-        }
-        v => v.try_into(),
-    }
-}
-
 #[cfg(feature = "serde")]
 impl<'de: 'a, 'a> serde::Deserialize<'de> for &'a RawDocument {
     fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
@@ -633,7 +577,9 @@ impl ToOwned for RawDocument {
     type Owned = RawDocumentBuf;
 
     fn to_owned(&self) -> Self::Owned {
-        self.to_raw_document_buf()
+        // unwrap is ok here because we already verified the bytes in
+        // `RawDocument::from_bytes`
+        RawDocumentBuf::from_bytes(self.data.to_owned()).unwrap()
     }
 }
 
@@ -643,7 +589,7 @@ impl<'a> From<&'a RawDocument> for Cow<'a, RawDocument> {
     }
 }
 
-impl TryFrom<&RawDocument> for crate::Document {
+impl TryFrom<&RawDocument> for Document {
     type Error = RawError;
 
     fn try_from(rawdoc: &RawDocument) -> RawResult<Document> {
@@ -654,6 +600,58 @@ impl TryFrom<&RawDocument> for crate::Document {
     }
 }
 
+impl TryFrom<&RawDocument> for Utf8Lossy<Document> {
+    type Error = RawError;
+
+    fn try_from(rawdoc: &RawDocument) -> RawResult<Utf8Lossy<Document>> {
+        let mut out = Document::new();
+        for elem in rawdoc.iter_elements() {
+            let elem = elem?;
+            let value = deep_utf8_lossy(elem.value_utf8_lossy()?)?;
+            out.insert(elem.key().as_str(), value);
+        }
+        Ok(Utf8Lossy(out))
+    }
+}
+
+fn deep_utf8_lossy(src: RawBson) -> RawResult<Bson> {
+    match src {
+        RawBson::Array(arr) => {
+            let mut tmp = vec![];
+            for elem in arr.iter_elements() {
+                tmp.push(deep_utf8_lossy(elem?.value_utf8_lossy()?)?);
+            }
+            Ok(Bson::Array(tmp))
+        }
+        RawBson::Document(doc) => {
+            let mut tmp = doc! {};
+            for elem in doc.iter_elements() {
+                let elem = elem?;
+                tmp.insert(
+                    elem.key().as_str(),
+                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
+                );
+            }
+            Ok(Bson::Document(tmp))
+        }
+        RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code, scope }) => {
+            let mut tmp = doc! {};
+            for elem in scope.iter_elements() {
+                let elem = elem?;
+                tmp.insert(
+                    elem.key().as_str(),
+                    deep_utf8_lossy(elem.value_utf8_lossy()?)?,
+                );
+            }
+            Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
+                code,
+                scope: tmp,
+            }))
+        }
+        v => v.try_into(),
+    }
+}
+
 impl TryFrom<RawDocumentBuf> for Document {
     type Error = crate::error::Error;
 
@@ -662,6 +660,14 @@ impl TryFrom<RawDocumentBuf> for Document {
     }
 }
 
+impl TryFrom<RawDocumentBuf> for Utf8Lossy<Document> {
+    type Error = crate::error::Error;
+
+    fn try_from(raw: RawDocumentBuf) -> Result<Utf8Lossy<Document>> {
+        Utf8Lossy::<Document>::try_from(raw.as_ref())
+    }
+}
+
 impl TryFrom<&RawDocumentBuf> for Document {
     type Error = crate::error::Error;
 
@@ -670,6 +676,14 @@ impl TryFrom<&RawDocumentBuf> for Document {
     }
 }
 
+impl TryFrom<&RawDocumentBuf> for Utf8Lossy<Document> {
+    type Error = crate::error::Error;
+
+    fn try_from(raw: &RawDocumentBuf) -> Result<Utf8Lossy<Document>> {
+        Utf8Lossy::<Document>::try_from(raw.as_ref())
+    }
+}
+
 impl<'a> IntoIterator for &'a RawDocument {
     type IntoIter = Iter<'a>;
     type Item = RawResult<(&'a CStr, RawBsonRef<'a>)>;
diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs
index e167f336..7d949f45 100644
--- a/src/raw/document_buf.rs
+++ b/src/raw/document_buf.rs
@@ -27,7 +27,7 @@ mod raw_writer;
 /// # use bson::error::Error;
 /// use bson::raw::RawDocumentBuf;
 ///
-/// let doc = RawDocumentBuf::decode_from_bytes(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");
@@ -45,7 +45,7 @@ mod raw_writer;
 /// ```
 /// use bson::raw::RawDocumentBuf;
 ///
-/// let doc = RawDocumentBuf::decode_from_bytes(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<dyn std::error::Error>>(())
 /// ```
@@ -77,11 +77,11 @@ impl RawDocumentBuf {
     ///
     /// ```
     /// # use bson::raw::RawDocumentBuf;
-    /// let doc = RawDocumentBuf::decode_from_bytes(b"\x05\0\0\0\0".to_vec())?;
+    /// let doc = RawDocumentBuf::from_bytes(b"\x05\0\0\0\0".to_vec())?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn decode_from_bytes(data: Vec<u8>) -> Result<Self> {
-        let _ = RawDocument::decode_from_bytes(data.as_slice())?;
+    pub fn from_bytes(data: Vec<u8>) -> Result<Self> {
+        let _ = RawDocument::from_bytes(data.as_slice())?;
         Ok(Self { data })
     }
 
@@ -99,35 +99,12 @@ impl RawDocumentBuf {
     ///
     /// ```
     /// # use bson::raw::RawDocumentBuf;
-    /// let doc = RawDocumentBuf::decode_from_reader(b"\x05\0\0\0\0".as_slice())?;
+    /// let doc = RawDocumentBuf::from_reader(b"\x05\0\0\0\0".as_slice())?;
     /// # Ok::<(), bson::error::Error>(())
     /// ```
-    pub fn decode_from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
+    pub fn from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
         let buf = crate::raw::reader_to_vec(reader)?;
-        Self::decode_from_bytes(buf)
-    }
-
-    /// Create a [`RawDocumentBuf`] from a [`Document`].
-    ///
-    /// ```
-    /// use bson::{doc, oid::ObjectId, raw::RawDocumentBuf};
-    ///
-    /// let document = doc! {
-    ///     "_id": ObjectId::new(),
-    ///     "name": "Herman Melville",
-    ///     "title": "Moby-Dick",
-    /// };
-    /// let doc = RawDocumentBuf::from_document(&document)?;
-    /// # Ok::<(), bson::error::Error>(())
-    /// ```
-    pub fn from_document(doc: impl Borrow<Document>) -> Result<Self> {
-        let mut out = RawDocumentBuf::new();
-        for (k, v) in doc.borrow() {
-            let k: &CStr = k.as_str().try_into()?;
-            let val: RawBson = v.clone().try_into()?;
-            out.append(k, val);
-        }
-        Ok(out)
+        Self::from_bytes(buf)
     }
 
     /// Gets an iterator over the elements in the [`RawDocumentBuf`], which yields
@@ -136,7 +113,7 @@ impl RawDocumentBuf {
     /// ```
     /// use bson::{doc, raw::RawDocumentBuf};
     ///
-    /// let doc = RawDocumentBuf::from_document(&doc! { "ferris": true })?;
+    /// let doc = RawDocumentBuf::try_from(&doc! { "ferris": true })?;
     ///
     /// for element in doc.iter() {
     ///     let (key, value) = element?;
@@ -180,7 +157,7 @@ impl RawDocumentBuf {
     /// ```
     /// use bson::{doc, raw::RawDocumentBuf};
     ///
-    /// let doc = RawDocumentBuf::from_document(&doc!{})?;
+    /// let doc = RawDocumentBuf::try_from(&doc!{})?;
     /// assert_eq!(doc.into_bytes(), b"\x05\x00\x00\x00\x00".to_vec());
     /// # Ok::<(), bson::error::Error>(())
     /// ```
@@ -200,7 +177,7 @@ impl RawDocumentBuf {
     /// the documentation for [BindRawBsonRef] for more details.
     /// ```
     /// # use bson::error::Error;
-    /// use bson::{doc, raw::{cstr, RawBsonRef, RawDocumentBuf}};
+    /// use bson::{Document, doc, raw::{cstr, RawBsonRef, RawDocumentBuf}};
     ///
     /// let mut doc = RawDocumentBuf::new();
     /// // `&str` and `i32` both convert to `RawBsonRef`
@@ -219,7 +196,7 @@ impl RawDocumentBuf {
     ///     "an owned document": { "a key": true },
     /// };
     ///
-    /// assert_eq!(doc.to_document()?, expected);
+    /// assert_eq!(Document::try_from(doc)?, expected);
     /// # Ok::<(), Error>(())
     /// ```
     pub fn append(&mut self, key: impl AsRef<CStr>, value: impl BindRawBsonRef) {
@@ -289,7 +266,13 @@ impl TryFrom<&Document> for RawDocumentBuf {
     type Error = crate::error::Error;
 
     fn try_from(doc: &Document) -> std::result::Result<Self, Self::Error> {
-        RawDocumentBuf::from_document(doc)
+        let mut out = RawDocumentBuf::new();
+        for (k, v) in doc {
+            let k: &CStr = k.as_str().try_into()?;
+            let val: RawBson = v.clone().try_into()?;
+            out.append(k, val);
+        }
+        Ok(out)
     }
 }
 
diff --git a/src/raw/iter.rs b/src/raw/iter.rs
index 395f889f..e7611029 100644
--- a/src/raw/iter.rs
+++ b/src/raw/iter.rs
@@ -133,7 +133,7 @@ impl TryFrom<RawElement<'_>> for RawBson {
     type Error = Error;
 
     fn try_from(element: RawElement<'_>) -> Result<Self> {
-        Ok(element.value()?.to_raw_bson())
+        Ok(element.value()?.into())
     }
 }
 
@@ -141,7 +141,7 @@ impl TryFrom<RawElement<'_>> for Bson {
     type Error = Error;
 
     fn try_from(element: RawElement<'_>) -> Result<Self> {
-        element.value()?.to_raw_bson().try_into()
+        element.value()?.try_into()
     }
 }
 
@@ -150,7 +150,7 @@ impl<'a> RawElement<'a> {
     pub(crate) fn toplevel(bytes: &'a [u8]) -> Result<Self> {
         use crate::raw::cstr;
 
-        let doc = RawDocument::decode_from_bytes(bytes)?;
+        let doc = RawDocument::from_bytes(bytes)?;
         Ok(Self {
             key: cstr!("TOPLEVEL"),
             kind: ElementType::EmbeddedDocument,
@@ -189,11 +189,11 @@ impl<'a> RawElement<'a> {
             ElementType::Double => RawBsonRef::Double(f64_from_slice(self.slice())?),
             ElementType::String => RawBsonRef::String(self.read_str()?),
             ElementType::EmbeddedDocument => {
-                RawBsonRef::Document(RawDocument::decode_from_bytes(self.slice())?)
+                RawBsonRef::Document(RawDocument::from_bytes(self.slice())?)
+            }
+            ElementType::Array => {
+                RawBsonRef::Array(RawArray::from_doc(RawDocument::from_bytes(self.slice())?))
             }
-            ElementType::Array => RawBsonRef::Array(RawArray::from_doc(
-                RawDocument::decode_from_bytes(self.slice())?,
-            )),
             ElementType::Boolean => RawBsonRef::Boolean(
                 bool_from_slice(self.slice()).map_err(|e| self.malformed_error(e))?,
             ),
@@ -271,7 +271,7 @@ impl<'a> RawElement<'a> {
                 let slice = self.slice();
                 let code = read_lenencode(&slice[4..])?;
                 let scope_start = 4 + 4 + code.len() + 1;
-                let scope = RawDocument::decode_from_bytes(&slice[scope_start..])?;
+                let scope = RawDocument::from_bytes(&slice[scope_start..])?;
 
                 RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { code, scope })
             }
@@ -283,7 +283,7 @@ impl<'a> RawElement<'a> {
     pub fn value_utf8_lossy(&self) -> Result<RawBson> {
         match self.value_utf8_lossy_inner()? {
             Some(v) => Ok(v.into()),
-            None => Ok(self.value()?.to_raw_bson()),
+            None => Ok(self.value()?.into()),
         }
     }
 
@@ -302,7 +302,7 @@ impl<'a> RawElement<'a> {
                 if scope_start >= slice.len() {
                     return Err(self.malformed_error("code with scope length overrun"));
                 }
-                let scope = RawDocument::decode_from_bytes(&slice[scope_start..])?;
+                let scope = RawDocument::from_bytes(&slice[scope_start..])?;
 
                 Utf8LossyBson::JavaScriptCodeWithScope(Utf8LossyJavaScriptCodeWithScope {
                     code,
@@ -489,7 +489,7 @@ impl<'a> From<Utf8LossyBson<'a>> for RawBson {
                 scope,
             }) => RawBson::JavaScriptCodeWithScope(super::RawJavaScriptCodeWithScope {
                 code,
-                scope: scope.to_raw_document_buf(),
+                scope: scope.to_owned(),
             }),
             Utf8LossyBson::Symbol(s) => RawBson::Symbol(s),
             Utf8LossyBson::DbPointer(p) => RawBson::DbPointer(p),
diff --git a/src/raw/serde.rs b/src/raw/serde.rs
index 6e2da2e2..40dc03fb 100644
--- a/src/raw/serde.rs
+++ b/src/raw/serde.rs
@@ -108,8 +108,8 @@ impl<'a, 'de: 'a> TryFrom<CowByteBuffer<'de>> for OwnedOrBorrowedRawDocument<'a>
 
     fn try_from(buffer: CowByteBuffer<'de>) -> Result<Self, Self::Error> {
         let doc = match buffer.0 {
-            Some(Cow::Borrowed(borrowed)) => RawDocument::decode_from_bytes(borrowed)?.into(),
-            Some(Cow::Owned(owned)) => RawDocumentBuf::decode_from_bytes(owned)?.into(),
+            Some(Cow::Borrowed(borrowed)) => RawDocument::from_bytes(borrowed)?.into(),
+            Some(Cow::Owned(owned)) => RawDocumentBuf::from_bytes(owned)?.into(),
             None => RawDocumentBuf::new().into(),
         };
         Ok(doc)
@@ -134,14 +134,14 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> {
                 if b.subtype == BinarySubtype::Generic =>
             {
                 Ok(Self::Borrowed(
-                    RawDocument::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?,
+                    RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?,
                 ))
             }
             OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
                 Ok(Self::Owned(
-                    RawDocumentBuf::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?,
+                    RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?,
                 ))
             }
 
@@ -186,13 +186,13 @@ impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> {
             OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
-                let doc = RawDocument::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?;
+                let doc = RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?;
                 Ok(Self::Borrowed(RawArray::from_doc(doc)))
             }
             OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b))
                 if b.subtype == BinarySubtype::Generic =>
             {
-                let doc = RawDocumentBuf::decode_from_bytes(b.bytes).map_err(SerdeError::custom)?;
+                let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?;
                 Ok(Self::Owned(RawArrayBuf::from_raw_document_buf(doc)))
             }
 
diff --git a/src/raw/serde/bson_visitor.rs b/src/raw/serde/bson_visitor.rs
index 436b873e..18db60da 100644
--- a/src/raw/serde/bson_visitor.rs
+++ b/src/raw/serde/bson_visitor.rs
@@ -185,12 +185,12 @@ impl OwnedOrBorrowedRawBsonVisitor {
             }
             RAW_DOCUMENT_NEWTYPE => {
                 let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::decode_from_bytes(bson).map_err(SerdeError::custom)?;
+                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
                 RawBsonRef::Document(doc).into()
             }
             RAW_ARRAY_NEWTYPE => {
                 let bson = map.next_value::<&[u8]>()?;
-                let doc = RawDocument::decode_from_bytes(bson).map_err(SerdeError::custom)?;
+                let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?;
                 RawBsonRef::Array(RawArray::from_doc(doc)).into()
             }
             _ => return Ok(MapParse::Aggregate(first_key)),
diff --git a/src/raw/test.rs b/src/raw/test.rs
index b2c731dc..92311d1d 100644
--- a/src/raw/test.rs
+++ b/src/raw/test.rs
@@ -124,7 +124,7 @@ fn rawdoc_to_doc() {
         assert_eq!(round_tripped_bytes.as_slice(), rawdoc.as_bytes());
     }
 
-    let vec_writer_bytes = doc.encode_to_vec().expect("encode should work");
+    let vec_writer_bytes = doc.to_vec().expect("encode should work");
     assert_eq!(vec_writer_bytes, rawdoc.into_bytes());
 }
 
@@ -429,7 +429,7 @@ fn into_bson_conversion() {
         "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] },
         "boolean": false,
     };
-    let rawbson = RawBsonRef::Document(RawDocument::decode_from_bytes(rawdoc.as_bytes()).unwrap());
+    let rawbson = RawBsonRef::Document(RawDocument::from_bytes(rawdoc.as_bytes()).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));
@@ -485,13 +485,13 @@ use std::convert::TryInto;
 proptest! {
     #[test]
     fn no_crashes(s: Vec<u8>) {
-        let _ = RawDocumentBuf::decode_from_bytes(s);
+        let _ = RawDocumentBuf::from_bytes(s);
     }
 
     #[test]
     fn roundtrip_bson(bson in arbitrary_bson()) {
         let doc = doc! { "bson": bson };
-        let bytes = doc.encode_to_vec();
+        let bytes = doc.to_vec();
         prop_assert!(bytes.is_ok());
         let bytes = bytes.unwrap();
         #[cfg(feature = "serde")]
@@ -499,7 +499,7 @@ proptest! {
             let raw = crate::serialize_to_vec(&doc);
             prop_assert!(raw.is_ok());
         }
-        let raw = RawDocumentBuf::decode_from_bytes(bytes);
+        let raw = RawDocumentBuf::from_bytes(bytes);
         prop_assert!(raw.is_ok());
         let raw = raw.unwrap();
         let roundtrip: Result<crate::Document> = raw.try_into();
diff --git a/src/raw/test/append.rs b/src/raw/test/append.rs
index e530ab7f..f4201c28 100644
--- a/src/raw/test/append.rs
+++ b/src/raw/test/append.rs
@@ -20,7 +20,7 @@ use crate::{
 use pretty_assertions::assert_eq;
 
 fn append_test(expected: Document, append: impl FnOnce(&mut RawDocumentBuf)) {
-    let bytes = expected.encode_to_vec().unwrap();
+    let bytes = expected.to_vec().unwrap();
     let mut buf = RawDocumentBuf::new();
     append(&mut buf);
     assert_eq!(buf.as_bytes(), bytes);
diff --git a/src/ser.rs b/src/ser.rs
index 4100d40e..ca829448 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -123,5 +123,5 @@ pub fn serialize_to_raw_document_buf<T>(value: &T) -> Result<RawDocumentBuf>
 where
     T: Serialize,
 {
-    RawDocumentBuf::decode_from_bytes(serialize_to_vec(value)?).map_err(Error::custom)
+    RawDocumentBuf::from_bytes(serialize_to_vec(value)?).map_err(Error::custom)
 }
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 3b661b00..5df7f4f4 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -337,7 +337,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::CodeWithScopeScope { ref code, raw } if raw => {
                 let raw = RawJavaScriptCodeWithScopeRef {
                     code,
-                    scope: RawDocument::decode_from_bytes(v).map_err(Error::custom)?,
+                    scope: RawDocument::from_bytes(v).map_err(Error::custom)?,
                 };
                 RawBsonRef::JavaScriptCodeWithScope(raw).append_to(&mut self.root_serializer.bytes);
                 self.state = SerializationStep::Done;
diff --git a/src/ser/serde.rs b/src/ser/serde.rs
index ee47fb4f..e649519b 100644
--- a/src/ser/serde.rs
+++ b/src/ser/serde.rs
@@ -306,8 +306,7 @@ impl ser::Serializer for Serializer {
                 .serialize(self)?
             {
                 Bson::Binary(b) => {
-                    let doc =
-                        Document::decode_from_reader(b.bytes.as_slice()).map_err(Error::custom)?;
+                    let doc = Document::from_reader(b.bytes.as_slice()).map_err(Error::custom)?;
 
                     if name == RAW_DOCUMENT_NEWTYPE {
                         Ok(Bson::Document(doc))
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index e49caaf0..24774e86 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -1,5 +1,5 @@
 //! Collection of helper functions for serializing to and deserializing from BSON using Serde
-use serde::{de::Visitor, Deserialize, Serialize, Serializer};
+use serde::{de::Visitor, Deserialize, Serialize};
 use std::{
     marker::PhantomData,
     ops::{Deref, DerefMut},
@@ -800,97 +800,3 @@ where
         self.deref_mut().as_mut()
     }
 }
-
-// One could imagine passthrough Borrow impls; however, it turns out that can't be made to work
-// because of the existing base library impl of Borrow<T> for T will conflict despite that not
-// actually being possible to construct (https://github.com/rust-lang/rust/issues/50237).  So,
-// sadly, Borrow impls for HumanReadable are deliberately omitted :(
-
-/// Wrapper type for deserializing BSON bytes with invalid UTF-8 sequences.
-///
-/// Any invalid UTF-8 strings contained in the wrapped type will be replaced with the Unicode
-/// replacement character. This wrapper type only has an effect when deserializing from BSON bytes.
-///
-/// This wrapper type has no impact on serialization. Serializing a `Utf8LossyDeserialization<T>`
-/// will call the `serialize` method for the wrapped `T`.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
-#[repr(transparent)]
-pub struct Utf8LossyDeserialization<T>(pub T);
-
-pub(crate) const UTF8_LOSSY_NEWTYPE: &str = "$__bson_private_utf8_lossy";
-
-impl<T: Serialize> Serialize for Utf8LossyDeserialization<T> {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: Serializer,
-    {
-        self.0.serialize(serializer)
-    }
-}
-
-impl<'de, T: Deserialize<'de>> Deserialize<'de> for Utf8LossyDeserialization<T> {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        struct V<T>(PhantomData<fn() -> T>);
-        impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
-            type Value = Utf8LossyDeserialization<T>;
-            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
-                formatter.write_str("Utf8Lossy wrapper")
-            }
-            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                T::deserialize(deserializer).map(Utf8LossyDeserialization)
-            }
-        }
-        deserializer.deserialize_newtype_struct(UTF8_LOSSY_NEWTYPE, V(PhantomData))
-    }
-}
-
-impl<T: std::fmt::Display> std::fmt::Display for Utf8LossyDeserialization<T> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-impl<T> From<T> for Utf8LossyDeserialization<T> {
-    fn from(value: T) -> Self {
-        Self(value)
-    }
-}
-
-impl<T> Deref for Utf8LossyDeserialization<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<T> DerefMut for Utf8LossyDeserialization<T> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
-    }
-}
-
-impl<T, R> AsRef<R> for Utf8LossyDeserialization<T>
-where
-    R: ?Sized,
-    <Utf8LossyDeserialization<T> as Deref>::Target: AsRef<R>,
-{
-    fn as_ref(&self) -> &R {
-        self.deref().as_ref()
-    }
-}
-
-impl<T, R: ?Sized> AsMut<R> for Utf8LossyDeserialization<T>
-where
-    <Utf8LossyDeserialization<T> as Deref>::Target: AsMut<R>,
-{
-    fn as_mut(&mut self) -> &mut R {
-        self.deref_mut().as_mut()
-    }
-}
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
index 468fcd12..3037c4f5 100644
--- a/src/tests/modules/ser.rs
+++ b/src/tests/modules/ser.rs
@@ -162,7 +162,7 @@ fn cstring_null_bytes_error() {
     verify_doc(doc);
 
     fn verify_doc(doc: Document) {
-        let result = doc.encode_to_vec();
+        let result = doc.to_vec();
         assert!(result.is_err(), "unexpected success");
         let err = result.unwrap_err();
         assert!(err.is_malformed_bytes(), "unexpected error: {:?}", err);
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 01a36f76..b58980fa 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -35,11 +35,11 @@ fn test_serialize_deserialize_floating_point() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -55,11 +55,11 @@ fn test_serialize_deserialize_utf8_string() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -71,10 +71,10 @@ fn test_encode_decode_utf8_string_invalid() {
     let doc = doc! { "key": &src, "subdoc": { "subkey": &src } };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     let expected = doc! { "key": "��", "subdoc": { "subkey": "��" } };
-    let decoded = RawDocumentBuf::decode_from_reader(&mut Cursor::new(buf))
+    let decoded = RawDocumentBuf::from_reader(&mut Cursor::new(buf))
         .unwrap()
         .to_document_utf8_lossy()
         .unwrap();
@@ -93,11 +93,11 @@ fn test_serialize_deserialize_array() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -113,11 +113,11 @@ fn test_serialize_deserialize() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -130,11 +130,11 @@ fn test_serialize_deserialize_boolean() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -147,11 +147,11 @@ fn test_serialize_deserialize_null() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -167,11 +167,11 @@ fn test_serialize_deserialize_regexp() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -184,11 +184,11 @@ fn test_serialize_deserialize_javascript_code() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -206,11 +206,11 @@ fn test_serialize_deserialize_javascript_code_with_scope() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -223,11 +223,11 @@ fn test_serialize_deserialize_i32() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -242,11 +242,11 @@ fn test_serialize_deserialize_i64() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -264,11 +264,11 @@ fn test_serialize_deserialize_timestamp() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -286,11 +286,11 @@ fn test_serialize_binary_generic() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -305,11 +305,11 @@ fn test_serialize_deserialize_object_id() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -334,11 +334,11 @@ fn test_serialize_utc_date_time() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -353,11 +353,11 @@ fn test_serialize_deserialize_symbol() {
     let doc = doc! { "key": symbol };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -375,7 +375,7 @@ fn test_deserialize_utc_date_time_overflows() {
     raw.write_all(&raw0).unwrap();
     raw.write_all(&[0]).unwrap();
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(raw)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(raw)).unwrap();
 
     let expected = doc! { "A": crate::DateTime::from_time_0_3(time::OffsetDateTime::from_unix_timestamp(1_530_492_218).unwrap() + time::Duration::nanoseconds(999 * 1_000_000))};
     assert_eq!(deserialized, expected);
@@ -386,7 +386,7 @@ fn test_deserialize_invalid_utf8_string_issue64() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"\x13\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x00foo\x00\x13\x05\x00\x00\x00";
 
-    assert!(Document::decode_from_reader(&mut Cursor::new(buffer)).is_err());
+    assert!(Document::from_reader(&mut Cursor::new(buffer)).is_err());
 }
 
 #[test]
@@ -394,7 +394,7 @@ fn test_deserialize_multiply_overflows_issue64() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"*\xc9*\xc9\t\x00\x00\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\x01\t\x00\x00\x01\x10";
 
-    assert!(Document::decode_from_reader(&mut Cursor::new(&buffer[..])).is_err());
+    assert!(Document::from_reader(&mut Cursor::new(&buffer[..])).is_err());
 }
 
 #[test]
@@ -410,11 +410,11 @@ fn test_serialize_deserialize_decimal128() {
     let doc = doc! { "key": val };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -424,7 +424,7 @@ fn test_illegal_size() {
     let buffer = [
         0x06, 0xcc, 0xf9, 0x0a, 0x05, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff,
     ];
-    assert!(Document::decode_from_reader(&mut Cursor::new(&buffer[..])).is_err());
+    assert!(Document::from_reader(&mut Cursor::new(&buffer[..])).is_err());
 }
 
 #[test]
@@ -436,11 +436,11 @@ fn test_serialize_deserialize_undefined() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -453,11 +453,11 @@ fn test_serialize_deserialize_min_key() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -470,11 +470,11 @@ fn test_serialize_deserialize_max_key() {
     let doc = doc! {"key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -496,11 +496,11 @@ fn test_serialize_deserialize_db_pointer() {
     let doc = doc! { "key": src };
 
     let mut buf = Vec::new();
-    doc.encode_to_writer(&mut buf).unwrap();
+    doc.to_writer(&mut buf).unwrap();
 
     assert_eq!(buf, dst);
 
-    let deserialized = Document::decode_from_reader(&mut Cursor::new(buf)).unwrap();
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
     assert_eq!(deserialized, doc);
 }
 
@@ -556,7 +556,7 @@ fn test_serialize_deserialize_document() {
 fn test_deserialize_invalid_array_length() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"\n\x00\x00\x00\x04\x00\x00\x00\x00\x00";
-    Document::decode_from_reader(&mut std::io::Cursor::new(buffer))
+    Document::from_reader(&mut std::io::Cursor::new(buffer))
         .expect_err("expected deserialization to fail");
 }
 
@@ -565,10 +565,10 @@ fn test_deserialize_invalid_array_length() {
 fn test_deserialize_invalid_old_binary_length() {
     let _guard = LOCK.run_concurrently();
     let buffer = b"\x0F\x00\x00\x00\x05\x00\x00\x00\x00\x00\x02\xFC\xFF\xFF\xFF";
-    Document::decode_from_reader(&mut std::io::Cursor::new(buffer))
+    Document::from_reader(&mut std::io::Cursor::new(buffer))
         .expect_err("expected deserialization to fail");
 
     let buffer = b".\x00\x00\x00\x05\x01\x00\x00\x00\x00\x00\x02\xfc\xff\xff\xff\xff\xff\xff\xff\x00\x00*\x00h\x0e\x10++\x00h\x0e++\x00\x00\t\x00\x00\x00\x00\x00*\x0e\x10++";
-    Document::decode_from_reader(&mut std::io::Cursor::new(buffer))
+    Document::from_reader(&mut std::io::Cursor::new(buffer))
         .expect_err("expected deserialization to fail");
 }
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 08c22421..403bcbff 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -546,7 +546,7 @@ fn test_de_uuid_extjson_string() {
 
     let uuid_bson_bytes =
         hex::decode("1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400").unwrap();
-    let uuid_document = Document::decode_from_reader(uuid_bson_bytes.as_slice()).unwrap();
+    let uuid_document = Document::from_reader(uuid_bson_bytes.as_slice()).unwrap();
     let expected_uuid_bson = Bson::from_extended_document(uuid_document);
 
     let ext_json_uuid = "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}";
diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs
index 0f74e352..7e683bbe 100644
--- a/src/tests/serde_helpers.rs
+++ b/src/tests/serde_helpers.rs
@@ -2,10 +2,7 @@ use core::str;
 
 use serde::{de::Visitor, Deserialize, Serialize};
 
-use crate::{
-    deserialize_from_slice,
-    serde_helpers::{HumanReadable, Utf8LossyDeserialization},
-};
+use crate::{deserialize_from_slice, serde_helpers::HumanReadable, Utf8Lossy};
 
 #[test]
 fn human_readable_wrapper() {
@@ -144,17 +141,15 @@ fn utf8_lossy_wrapper() {
 
     deserialize_from_slice::<NoUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
 
-    let s = deserialize_from_slice::<Utf8LossyDeserialization<NoUtf8Lossy>>(
-        &both_strings_invalid_bytes,
-    )
-    .unwrap()
-    .0;
+    let s = deserialize_from_slice::<Utf8Lossy<NoUtf8Lossy>>(&both_strings_invalid_bytes)
+        .unwrap()
+        .0;
     assert_eq!(s.s1, expected_replacement);
     assert_eq!(s.s2, expected_replacement);
 
     #[derive(Debug, Deserialize)]
     struct FirstStringUtf8Lossy {
-        s1: Utf8LossyDeserialization<String>,
+        s1: Utf8Lossy<String>,
         s2: String,
     }
 
@@ -164,11 +159,9 @@ fn utf8_lossy_wrapper() {
 
     deserialize_from_slice::<FirstStringUtf8Lossy>(&both_strings_invalid_bytes).unwrap_err();
 
-    let s = deserialize_from_slice::<Utf8LossyDeserialization<FirstStringUtf8Lossy>>(
-        &both_strings_invalid_bytes,
-    )
-    .unwrap()
-    .0;
+    let s = deserialize_from_slice::<Utf8Lossy<FirstStringUtf8Lossy>>(&both_strings_invalid_bytes)
+        .unwrap()
+        .0;
     assert_eq!(s.s1.0, expected_replacement);
     assert_eq!(s.s2, expected_replacement);
 }
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index e639a201..c8bae9c4 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -6,12 +6,12 @@ use std::{
 
 use crate::{
     raw::{RawBsonRef, RawDocument},
-    serde_helpers::Utf8LossyDeserialization,
     tests::LOCK,
     Bson,
     Document,
     RawBson,
     RawDocumentBuf,
+    Utf8Lossy,
 };
 use pretty_assertions::assert_eq;
 use serde::{Deserialize, Deserializer};
@@ -110,7 +110,7 @@ fn run_test(test: TestFile) {
 
         // these four cover the four ways to create a [`Document`] from the provided BSON.
         let documentfromreader_cb =
-            Document::decode_from_reader(canonical_bson.as_slice()).expect(&description);
+            Document::from_reader(canonical_bson.as_slice()).expect(&description);
 
         let fromreader_cb: Document =
             crate::deserialize_from_reader(canonical_bson.as_slice()).expect(&description);
@@ -122,7 +122,7 @@ fn run_test(test: TestFile) {
             crate::serialize_to_document(&documentfromreader_cb).expect(&description);
 
         let canonical_raw_document =
-            RawDocument::decode_from_bytes(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);
 
@@ -143,22 +143,22 @@ fn run_test(test: TestFile) {
         // These cover the ways to serialize those [`Documents`] back to BSON.
         let mut documenttowriter_documentfromreader_cb = Vec::new();
         documentfromreader_cb
-            .encode_to_writer(&mut documenttowriter_documentfromreader_cb)
+            .to_writer(&mut documenttowriter_documentfromreader_cb)
             .expect(&description);
 
         let mut documenttowriter_fromreader_cb = Vec::new();
         fromreader_cb
-            .encode_to_writer(&mut documenttowriter_fromreader_cb)
+            .to_writer(&mut documenttowriter_fromreader_cb)
             .expect(&description);
 
         let mut documenttowriter_fromdocument_documentfromreader_cb = Vec::new();
         fromdocument_documentfromreader_cb
-            .encode_to_writer(&mut documenttowriter_fromdocument_documentfromreader_cb)
+            .to_writer(&mut documenttowriter_fromdocument_documentfromreader_cb)
             .expect(&description);
 
         let mut documenttowriter_todocument_documentfromreader_cb = Vec::new();
         todocument_documentfromreader_cb
-            .encode_to_writer(&mut documenttowriter_todocument_documentfromreader_cb)
+            .to_writer(&mut documenttowriter_todocument_documentfromreader_cb)
             .expect(&description);
 
         let tovec_documentfromreader_cb =
@@ -166,7 +166,7 @@ fn run_test(test: TestFile) {
 
         let mut documenttowriter_document_from_raw_document = Vec::new();
         document_from_raw_document
-            .encode_to_writer(&mut documenttowriter_document_from_raw_document)
+            .to_writer(&mut documenttowriter_document_from_raw_document)
             .expect(&description);
 
         // Serialize the raw versions "back" to BSON also.
@@ -349,11 +349,10 @@ fn run_test(test: TestFile) {
         if let Some(db) = valid.degenerate_bson {
             let db = hex::decode(&db).expect(&description);
 
-            let bson_to_native_db =
-                Document::decode_from_reader(db.as_slice()).expect(&description);
+            let bson_to_native_db = Document::from_reader(db.as_slice()).expect(&description);
             let mut native_to_bson_bson_to_native_db = Vec::new();
             bson_to_native_db
-                .encode_to_writer(&mut native_to_bson_bson_to_native_db)
+                .to_writer(&mut native_to_bson_bson_to_native_db)
                 .unwrap();
             assert_eq!(
                 hex::encode(native_to_bson_bson_to_native_db).to_lowercase(),
@@ -366,7 +365,7 @@ fn run_test(test: TestFile) {
                 crate::deserialize_from_reader(db.as_slice()).expect(&description);
             let mut native_to_bson_bson_to_native_db_serde = Vec::new();
             bson_to_native_db_serde
-                .encode_to_writer(&mut native_to_bson_bson_to_native_db_serde)
+                .to_writer(&mut native_to_bson_bson_to_native_db_serde)
                 .unwrap();
             assert_eq!(
                 hex::encode(native_to_bson_bson_to_native_db_serde).to_lowercase(),
@@ -375,14 +374,13 @@ fn run_test(test: TestFile) {
                 description,
             );
 
-            let document_from_raw_document: Document =
-                RawDocument::decode_from_bytes(db.as_slice())
-                    .expect(&description)
-                    .try_into()
-                    .expect(&description);
+            let document_from_raw_document: Document = RawDocument::from_bytes(db.as_slice())
+                .expect(&description)
+                .try_into()
+                .expect(&description);
             let mut documenttowriter_document_from_raw_document = Vec::new();
             document_from_raw_document
-                .encode_to_writer(&mut documenttowriter_document_from_raw_document)
+                .to_writer(&mut documenttowriter_document_from_raw_document)
                 .expect(&description);
             assert_eq!(
                 hex::encode(documenttowriter_document_from_raw_document).to_lowercase(),
@@ -476,7 +474,7 @@ fn run_test(test: TestFile) {
             json_to_native_cej
                 .as_document()
                 .unwrap()
-                .encode_to_writer(&mut native_to_bson_json_to_native_cej)
+                .to_writer(&mut native_to_bson_json_to_native_cej)
                 .unwrap();
 
             assert_eq!(
@@ -511,7 +509,7 @@ fn run_test(test: TestFile) {
                 json_to_native_dej
                     .as_document()
                     .unwrap()
-                    .encode_to_writer(&mut native_to_bson_json_to_native_dej)
+                    .to_writer(&mut native_to_bson_json_to_native_dej)
                     .unwrap();
 
                 assert_eq!(
@@ -548,7 +546,7 @@ fn run_test(test: TestFile) {
         );
         let bson = hex::decode(&decode_error.bson).expect("should decode from hex");
 
-        if let Ok(doc) = RawDocument::decode_from_bytes(bson.as_slice()) {
+        if let Ok(doc) = RawDocument::from_bytes(bson.as_slice()) {
             Document::try_from(doc).expect_err(description.as_str());
         }
 
@@ -559,12 +557,12 @@ fn run_test(test: TestFile) {
             continue;
         }
 
-        Document::decode_from_reader(bson.as_slice()).expect_err(&description);
+        Document::from_reader(bson.as_slice()).expect_err(&description);
         crate::deserialize_from_reader::<_, Document>(bson.as_slice())
             .expect_err(description.as_str());
 
         if decode_error.description.contains("invalid UTF-8") {
-            RawDocumentBuf::decode_from_reader(bson.as_slice())
+            RawDocumentBuf::from_reader(bson.as_slice())
                 .expect(&description)
                 .to_document_utf8_lossy()
                 .unwrap_or_else(|err| {
@@ -573,7 +571,7 @@ fn run_test(test: TestFile) {
                         description, err
                     )
                 });
-            crate::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(bson.as_slice())
+            crate::deserialize_from_slice::<Utf8Lossy<Document>>(bson.as_slice())
                 .expect(&description);
         }
     }
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
index d25090da..7bd49cb9 100644
--- a/src/tests/spec/vector.rs
+++ b/src/tests/spec/vector.rs
@@ -107,7 +107,7 @@ fn vector_from_numbers(
 // Only return the binary if it represents a valid vector; otherwise, return an error.
 fn binary_from_bytes(bson: &str, test_key: &str, description: &str) -> Result<Binary, String> {
     let bytes = hex::decode(bson).expect(description);
-    let mut test_document = Document::decode_from_reader(bytes.as_slice()).expect(description);
+    let mut test_document = Document::from_reader(bytes.as_slice()).expect(description);
     let bson = test_document.remove(test_key).expect(description);
     let binary = match bson {
         Bson::Binary(binary) => binary,
@@ -175,7 +175,7 @@ fn run_test_file(test_file: TestFile) {
 
         // From<Vector> for RawBson
         let raw_document = rawdoc! { "vector": &test_vector };
-        let test_raw_document = RawDocumentBuf::from_document(&test_document).expect(&description);
+        let test_raw_document = RawDocumentBuf::try_from(&test_document).expect(&description);
         assert_eq!(raw_document, test_raw_document);
 
         #[derive(Debug, Deserialize, PartialEq, Serialize)]
diff --git a/src/utf8_lossy.rs b/src/utf8_lossy.rs
new file mode 100644
index 00000000..6f6115df
--- /dev/null
+++ b/src/utf8_lossy.rs
@@ -0,0 +1,100 @@
+use std::ops::{Deref, DerefMut};
+
+// One could imagine passthrough Borrow impls; however, it turns out that can't be made to work
+// because of the existing base library impl of Borrow<T> for T will conflict despite that not
+// actually being possible to construct (https://github.com/rust-lang/rust/issues/50237).  So,
+// sadly, Borrow impls for HumanReadable are deliberately omitted :(
+
+/// Wrapper type for lossily decoding embedded strings with invalid UTF-8 sequences.
+///
+/// A [`RawDocument`](crate::RawDocument) or [`RawDocumentBuf`](crate::RawDocumentBuf) can be
+/// converted into a `Utf8Lossy<Document>` via `TryFrom`; any invalid UTF-8 sequences contained in
+/// strings in the source buffer will be replaced with the Unicode replacement character.
+///
+/// If the `serde` feature is enabled, this type will also cause the same lossy decoding to apply
+/// to any strings contained in a wrapped deserializable type when deserializing from BSON bytes.
+/// This wrapper has no effect on serialization behavior.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
+#[repr(transparent)]
+pub struct Utf8Lossy<T>(pub T);
+
+impl<T: std::fmt::Display> std::fmt::Display for Utf8Lossy<T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl<T> From<T> for Utf8Lossy<T> {
+    fn from(value: T) -> Self {
+        Self(value)
+    }
+}
+
+impl<T> Deref for Utf8Lossy<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for Utf8Lossy<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T, R> AsRef<R> for Utf8Lossy<T>
+where
+    R: ?Sized,
+    <Utf8Lossy<T> as Deref>::Target: AsRef<R>,
+{
+    fn as_ref(&self) -> &R {
+        self.deref().as_ref()
+    }
+}
+
+impl<T, R: ?Sized> AsMut<R> for Utf8Lossy<T>
+where
+    <Utf8Lossy<T> as Deref>::Target: AsMut<R>,
+{
+    fn as_mut(&mut self) -> &mut R {
+        self.deref_mut().as_mut()
+    }
+}
+
+#[cfg(feature = "serde")]
+pub(crate) const UTF8_LOSSY_NEWTYPE: &str = "$__bson_private_utf8_lossy";
+
+#[cfg(feature = "serde")]
+impl<T: serde::Serialize> serde::Serialize for Utf8Lossy<T> {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        self.0.serialize(serializer)
+    }
+}
+
+#[cfg(feature = "serde")]
+impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Utf8Lossy<T> {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        struct V<T>(std::marker::PhantomData<fn() -> T>);
+        impl<'de, T: serde::Deserialize<'de>> serde::de::Visitor<'de> for V<T> {
+            type Value = Utf8Lossy<T>;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+                formatter.write_str("Utf8Lossy wrapper")
+            }
+            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                T::deserialize(deserializer).map(Utf8Lossy)
+            }
+        }
+        deserializer.deserialize_newtype_struct(UTF8_LOSSY_NEWTYPE, V(std::marker::PhantomData))
+    }
+}

From b0afc83181f7e555ac0b94a2b799f8fcc0621761 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Thu, 31 Jul 2025 11:42:11 -0400
Subject: [PATCH 148/156] RUST-2196 Require ignored bits in packed bit vector
 to be 0 (#586)

---
 src/binary/vector.rs                          | 22 +++++--
 .../spec/json/bson-binary-vector/README.md    | 63 +++++++++++++++++++
 .../json/bson-binary-vector/packed_bit.json   | 16 ++---
 src/tests/spec/vector.rs                      | 20 ++++++
 4 files changed, 108 insertions(+), 13 deletions(-)

diff --git a/src/binary/vector.rs b/src/binary/vector.rs
index a427dfea..6c012406 100644
--- a/src/binary/vector.rs
+++ b/src/binary/vector.rs
@@ -87,7 +87,7 @@ impl PackedBitVector {
     /// ```
     ///
     /// Padding must be within 0-7 inclusive. Padding must be 0 or unspecified if the provided
-    /// vector is empty.
+    /// vector is empty. The ignored bits in the vector must all be 0.
     pub fn new(vector: Vec<u8>, padding: impl Into<Option<u8>>) -> Result<Self> {
         let padding = padding.into().unwrap_or(0);
         if !(0..8).contains(&padding) {
@@ -95,10 +95,22 @@ impl PackedBitVector {
                 "vector padding must be within 0-7 inclusive, got {padding}"
             )));
         }
-        if padding != 0 && vector.is_empty() {
-            return Err(Error::binary(format!(
-                "cannot specify non-zero padding if the provided vector is empty, got {padding}",
-            )));
+        match vector.last() {
+            Some(last) => {
+                if last.trailing_zeros() < u32::from(padding) {
+                    return Err(Error::binary(
+                        "the ignored bits in a packed bit vector must all be 0",
+                    ));
+                }
+            }
+            None => {
+                if padding != 0 {
+                    return Err(Error::binary(format!(
+                        "cannot specify non-zero padding if the provided vector is empty, got \
+                         {padding}"
+                    )));
+                }
+            }
         }
         Ok(Self { vector, padding })
     }
diff --git a/src/tests/spec/json/bson-binary-vector/README.md b/src/tests/spec/json/bson-binary-vector/README.md
index 1a2cd871..3902aa10 100644
--- a/src/tests/spec/json/bson-binary-vector/README.md
+++ b/src/tests/spec/json/bson-binary-vector/README.md
@@ -55,6 +55,69 @@ MUST assert that the input float array is the same after encoding and decoding.
 - if the canonical_bson field is present, raise an exception when attempting to deserialize it into the corresponding
     numeric values, as the field contains corrupted data.
 
+## Prose Tests
+
+### Treatment of non-zero ignored bits
+
+All drivers MUST test encoding and decoding behavior according to their design and version. For drivers that haven't
+been completed, raise exceptions in both cases. For those that have, update to this behavior according to semantic
+versioning rules, and update tests accordingly.
+
+In both cases, [255], a single byte PACKED_BIT vector of length 1 (hence padding of 7) provides a good example to use,
+as all of its bits are ones.
+
+#### 1. Encoding
+
+- Test encoding with non-zero ignored bits. Use the driver API that validates vector metadata.
+- If the driver validates ignored bits are zero (preferred), expect an error. Otherwise expect the ignored bits are
+    preserved.
+
+```python
+with pytest.raises(ValueError):
+    Binary.from_vector([0b11111111], BinaryVectorDtype.PACKED_BIT, padding=7)
+```
+
+### 2. Decoding
+
+- Test the behaviour of your driver when one attempts to decode from binary to vector.
+    - e.g. As of pymongo 4.14, a warning is raised. From 5.0, it will be an exception.
+
+```python
+b = Binary(b'\x10\x07\xff', subtype=9)
+with pytest.warns():
+    Binary.as_vector(b)
+```
+
+Drivers MAY skip this test if they choose not to implement a `Vector` type.
+
+### 3. Comparison
+
+Once we can guarantee that all ignored bits are non-zero, then equality can be tested on the binary subtype. Until then,
+equality is ambiguous, and depends on whether one compares by bits (uint1), or uint8. Drivers SHOULD test equality
+behavior according to their design and version.
+
+For example, in `pymongo < 5.0`, we define equality of a BinaryVector by matching padding, dtype, and integer. This
+means that two single bit vectors in which 7 bits are ignored do not match unless all bits match. This mirrors what the
+server does.
+
+```python
+b1 = Binary(b'\x10\x07\x80', subtype=9) # 1-bit vector with all 0 ignored bits.
+b2 = Binary(b'\x10\x07\xff', subtype=9) # 1-bit vector with all 1 ignored bits.
+b3 = Binary.from_vector([0b10000000], BinaryVectorDtype.PACKED_BIT, padding=7) # Same data as b1.
+
+v1 = Binary.as_vector(b1)
+v2 = Binary.as_vector(b2)
+v3 = Binary.as_vector(b3)
+
+assert b1 != b2  # Unequal at naive Binary level 
+assert v2 != v1  # Also chosen to be unequal at BinaryVector level as [255] != [128]
+assert b1 == b3  # Equal at naive Binary level
+assert v1 == v3  # Equal at the BinaryVector level
+```
+
+Drivers MAY skip this test if they choose not to implement a `Vector` type, or the type does not support comparison, or
+the type cannot be constructed with non-zero ignored bits.
+
 ## FAQ
 
 - What MongoDB Server version does this apply to?
diff --git a/src/tests/spec/json/bson-binary-vector/packed_bit.json b/src/tests/spec/json/bson-binary-vector/packed_bit.json
index a220e7e3..7cc272e3 100644
--- a/src/tests/spec/json/bson-binary-vector/packed_bit.json
+++ b/src/tests/spec/json/bson-binary-vector/packed_bit.json
@@ -21,22 +21,22 @@
       "canonical_bson": "1600000005766563746F7200040000000910007F0700"
     },
     {
-      "description": "Empty Vector PACKED_BIT",
+      "description": "PACKED_BIT with padding",
       "valid": true,
-      "vector": [],
+      "vector": [127, 8],
       "dtype_hex": "0x10",
       "dtype_alias": "PACKED_BIT",
-      "padding": 0,
-      "canonical_bson": "1400000005766563746F72000200000009100000"
+      "padding": 3,
+      "canonical_bson": "1600000005766563746F7200040000000910037F0800"
     },
     {
-      "description": "PACKED_BIT with padding",
+      "description": "Empty Vector PACKED_BIT",
       "valid": true,
-      "vector": [127, 7],
+      "vector": [],
       "dtype_hex": "0x10",
       "dtype_alias": "PACKED_BIT",
-      "padding": 3,
-      "canonical_bson": "1600000005766563746F7200040000000910037F0700"
+      "padding": 0,
+      "canonical_bson": "1400000005766563746F72000200000009100000"
     },
     {
       "description": "Overflow Vector PACKED_BIT",
diff --git a/src/tests/spec/vector.rs b/src/tests/spec/vector.rs
index 7bd49cb9..99063b2c 100644
--- a/src/tests/spec/vector.rs
+++ b/src/tests/spec/vector.rs
@@ -210,3 +210,23 @@ fn run_test_file(test_file: TestFile) {
 fn run_vector_tests() {
     run_spec_test(&["bson-binary-vector"], run_test_file);
 }
+
+#[test]
+fn non_zero_ignored_bits() {
+    // 1. Encoding
+    let error = PackedBitVector::new(vec![u8::MAX], 1).unwrap_err();
+    assert!(error
+        .message
+        .is_some_and(|message| message.contains("must all be 0")));
+
+    // 2. Decoding
+    let bytes = vec![PACKED_BIT, 1, u8::MAX];
+    let error = Vector::from_bytes(bytes).unwrap_err();
+    assert!(error
+        .message
+        .is_some_and(|message| message.contains("must all be 0")));
+
+    // 3. Comparison
+    // This test is not implemented because it is not possible to construct a Vector with non-zero
+    // padding bits.
+}

From 4ddf9fc01510d336910c3169f89bace4ab09d92e Mon Sep 17 00:00:00 2001
From: Guarabot <guarascio.daniele@gmail.com>
Date: Fri, 1 Aug 2025 17:16:24 +0200
Subject: [PATCH 149/156] feat: Add integration with `jiff::Timestamp` (#587)

Co-authored-by: Daniele Guarascio <daniele.guarascio@gridspertise.com>
Co-authored-by: Abraham Egnor <abraham.egnor@mongodb.com>
---
 Cargo.lock                                   | 40 +++++++++++
 Cargo.toml                                   |  4 ++
 src/bson.rs                                  |  7 ++
 src/datetime.rs                              | 74 +++++++++++++++++++-
 src/lib.rs                                   |  1 +
 src/serde_helpers.rs                         | 29 ++++++++
 src/tests/modules/bson.rs                    | 51 ++++++++++++++
 src/tests/modules/serializer_deserializer.rs |  3 +
 src/tests/serde.rs                           | 72 +++++++++++++++++++
 9 files changed, 280 insertions(+), 1 deletion(-)

diff --git a/Cargo.lock b/Cargo.lock
index e3919189..59450fc9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -130,6 +130,7 @@ dependencies = [
  "getrandom 0.3.2",
  "hex",
  "indexmap 2.10.0",
+ "jiff",
  "js-sys",
  "once_cell",
  "pretty_assertions",
@@ -519,6 +520,30 @@ version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
+[[package]]
+name = "jiff"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
 [[package]]
 name = "js-sys"
 version = "0.3.77"
@@ -623,6 +648,21 @@ dependencies = [
  "plotters-backend",
 ]
 
+[[package]]
+name = "portable-atomic"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
 [[package]]
 name = "powerfmt"
 version = "0.2.0"
diff --git a/Cargo.toml b/Cargo.toml
index 307fc803..c540ae22 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,6 +37,8 @@ default = ["compat-3-0-0"]
 compat-3-0-0 = []
 # if enabled, include API for interfacing with chrono 0.4
 chrono-0_4 = ["dep:chrono"]
+# if enabled, include API for interfacing with jiff 0.2
+jiff-0_2 = ["dep:jiff"]
 # enable the large-dates feature for the time crate
 large_dates = ["time/large-dates"]
 # if enabled, include API for interfacing with uuid 1.x
@@ -56,6 +58,7 @@ name = "bson"
 [dependencies]
 ahash = "0.8.0"
 chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
+jiff = { version = "0.2", default-features = false, optional = true }
 rand = "0.9"
 serde = { version = "1.0", features = ["derive"], optional = true }
 serde_json = { version = "1.0", features = ["preserve_order"], optional = true }
@@ -87,6 +90,7 @@ serde_bytes = "0.11"
 serde_path_to_error = "0.1.16"
 serde_json = "1"
 chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false }
+jiff = { version = "0.2", default-features = false, features = ["std"] }
 
 [package.metadata.docs.rs]
 all-features = true
diff --git a/src/bson.rs b/src/bson.rs
index 7a0105e6..b131e5cb 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -408,6 +408,13 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for Bson {
     }
 }
 
+#[cfg(feature = "jiff-0_2")]
+impl From<jiff::Timestamp> for Bson {
+    fn from(a: jiff::Timestamp) -> Bson {
+        Bson::DateTime(crate::DateTime::from(a))
+    }
+}
+
 #[cfg(feature = "uuid-1")]
 impl From<uuid::Uuid> for Bson {
     fn from(uuid: uuid::Uuid) -> Self {
diff --git a/src/datetime.rs b/src/datetime.rs
index c6430016..4175c1a6 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -12,7 +12,7 @@ use std::{
 use chrono::{LocalResult, TimeZone, Utc};
 #[cfg(all(
     feature = "serde_with-3",
-    any(feature = "chrono-0_4", feature = "time-0_3")
+    any(feature = "chrono-0_4", feature = "time-0_3", feature = "jiff-0_2")
 ))]
 use serde::{Deserialize, Deserializer, Serialize};
 use time::format_description::well_known::Rfc3339;
@@ -215,6 +215,13 @@ impl crate::DateTime {
         Self::from_millis(dt.timestamp_millis())
     }
 
+    /// Convert the given [`jiff::Timestamp`] into a [`bson::DateTime`](DateTime), truncating it to
+    /// millisecond precision.
+    #[cfg(feature = "jiff-0_2")]
+    pub fn from_jiff(ts: jiff::Timestamp) -> Self {
+        Self::from_millis(ts.as_millisecond())
+    }
+
     /// Returns a builder used to construct a [`DateTime`] from a given year, month,
     /// day, and optionally, an hour, minute, second and millisecond, which default to
     /// 0 if not explicitly set.
@@ -253,6 +260,32 @@ impl crate::DateTime {
         }
     }
 
+    /// Convert this [`DateTime`] to a [`jiff::Timestamp`].
+    ///
+    /// Note: Not every BSON datetime can be represented as a [`jiff::Timestamp`]. For such dates,
+    /// [`jiff::Timestamp::MIN`] or [`jiff::Timestamp::MAX`] will be returned, whichever
+    /// is closer.
+    ///
+    /// ```
+    /// let bson_dt = bson::DateTime::now();
+    /// let jiff_ts = bson_dt.to_jiff();
+    /// assert_eq!(bson_dt.timestamp_millis(), jiff_ts.as_millisecond());
+    ///
+    /// let big = bson::DateTime::from_millis(i64::MAX);
+    /// let jiff_big = big.to_jiff();
+    /// assert_eq!(jiff_big, jiff::Timestamp::MAX)
+    /// ```
+    #[cfg(feature = "jiff-0_2")]
+    pub fn to_jiff(self) -> jiff::Timestamp {
+        jiff::Timestamp::from_millisecond(self.0).unwrap_or({
+            if self.0 < 0 {
+                jiff::Timestamp::MIN
+            } else {
+                jiff::Timestamp::MAX
+            }
+        })
+    }
+
     fn from_time_private(dt: time::OffsetDateTime) -> Self {
         let millis = dt.unix_timestamp_nanos() / 1_000_000;
         match millis.try_into() {
@@ -488,6 +521,45 @@ impl serde_with::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
     }
 }
 
+#[cfg(feature = "jiff-0_2")]
+impl From<crate::DateTime> for jiff::Timestamp {
+    fn from(bson_dt: DateTime) -> Self {
+        bson_dt.to_jiff()
+    }
+}
+
+#[cfg(feature = "jiff-0_2")]
+impl From<jiff::Timestamp> for crate::DateTime {
+    fn from(x: jiff::Timestamp) -> Self {
+        Self::from_jiff(x)
+    }
+}
+
+#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))]
+impl<'de> serde_with::DeserializeAs<'de, jiff::Timestamp> for crate::DateTime {
+    fn deserialize_as<D>(deserializer: D) -> std::result::Result<jiff::Timestamp, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let dt = DateTime::deserialize(deserializer)?;
+        Ok(dt.to_jiff())
+    }
+}
+
+#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))]
+impl serde_with::SerializeAs<jiff::Timestamp> for crate::DateTime {
+    fn serialize_as<S>(
+        source: &jiff::Timestamp,
+        serializer: S,
+    ) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        let dt = DateTime::from_jiff(*source);
+        dt.serialize(serializer)
+    }
+}
+
 #[cfg(feature = "time-0_3")]
 impl From<crate::DateTime> for time::OffsetDateTime {
     fn from(bson_dt: DateTime) -> Self {
diff --git a/src/lib.rs b/src/lib.rs
index ce6af55c..6ef05641 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -62,6 +62,7 @@
 //! | Feature      | Description                                                                                          | Default |
 //! |:-------------|:-----------------------------------------------------------------------------------------------------|:--------|
 //! | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API.       | no      |
+//! | `jiff-0_2` | Enable support for v0.2 of the [`jiff`](https://docs.rs/jiff/0.2) crate in the public API.             | no      |
 //! | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API.           | no      |
 //! | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.           | no      |
 //! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for [`DateTime`] and [`Uuid`]. | no      |
diff --git a/src/serde_helpers.rs b/src/serde_helpers.rs
index 24774e86..79b0620e 100644
--- a/src/serde_helpers.rs
+++ b/src/serde_helpers.rs
@@ -81,6 +81,8 @@ pub mod object_id {
 /// - [`datetime::FromI64`] — converts an `i64` to and from a [`crate::DateTime`].
 /// - [`datetime::FromChrono04DateTime`] — converts a [`chrono::DateTime`] to and from a
 ///   [`crate::DateTime`].
+/// - [`datetime::FromJiff02Timestamp`] — converts a [`jiff::Timestamp`] to and from a
+///   [`crate::DateTime`].
 /// - [`datetime::FromTime03OffsetDateTime`] — converts a [`time::OffsetDateTime`] to and from a
 ///   [`crate::DateTime`].
 #[cfg(feature = "serde_with-3")]
@@ -200,6 +202,33 @@ pub mod datetime {
         }
     );
 
+    #[cfg(feature = "jiff-0_2")]
+    serde_conv_doc!(
+        /// Converts a [`jiff::Timestamp`] to and from a [`DateTime`].
+        /// ```rust
+        /// # #[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))]
+        /// # {
+        /// use bson::serde_helpers::datetime;
+        /// use serde::{Serialize, Deserialize};
+        /// use serde_with::serde_as;
+        /// #[serde_as]
+        /// #[derive(Serialize, Deserialize)]
+        /// struct Event {
+        ///     #[serde_as(as = "datetime::FromJiff02Timestamp")]
+        ///     pub date: jiff::Timestamp,
+        /// }
+        /// # }
+        /// ```
+        pub FromJiff02Timestamp,
+        jiff::Timestamp,
+        |jiff_ts: &jiff::Timestamp| -> Result<DateTime, String> {
+            Ok(DateTime::from_jiff(*jiff_ts))
+        },
+        |bson_date: DateTime| -> Result<jiff::Timestamp, String> {
+            Ok(bson_date.to_jiff())
+        }
+    );
+
     #[cfg(feature = "time-0_3")]
     serde_conv_doc!(
         /// Converts a [`time::OffsetDateTime`] to and from a [`DateTime`].
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
index f9d3636f..71f6eb7c 100644
--- a/src/tests/modules/bson.rs
+++ b/src/tests/modules/bson.rs
@@ -274,6 +274,15 @@ fn from_external_datetime() {
         let from_chrono = DateTime::from(now);
         assert_millisecond_precision(from_chrono);
     }
+    #[cfg(feature = "jiff-0_2")]
+    {
+        let now = jiff::Timestamp::now();
+        let bson = Bson::from(now);
+        assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+
+        let from_jiff = DateTime::from(now);
+        assert_millisecond_precision(from_jiff);
+    }
 
     let no_subsec_millis = datetime!(2014-11-28 12:00:09 UTC);
     let dt = DateTime::from_time_0_3(no_subsec_millis);
@@ -298,6 +307,17 @@ fn from_external_datetime() {
         assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
         assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 0);
     }
+    #[cfg(feature = "jiff-0_2")]
+    {
+        let no_subsec_millis: jiff::Timestamp = "2014-11-28T12:00:09Z".parse().unwrap();
+        let dt = DateTime::from(no_subsec_millis);
+        assert_millisecond_precision(dt);
+        assert_subsec_millis(dt, 0);
+
+        let bson = Bson::from(dt);
+        assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+        assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 0);
+    }
 
     for s in &[
         "2014-11-28T12:00:09.123Z",
@@ -327,6 +347,17 @@ fn from_external_datetime() {
             assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
             assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 123);
         }
+        #[cfg(feature = "jiff-0_2")]
+        {
+            let jiff_ts: jiff::Timestamp = s.parse().unwrap();
+            let dt = DateTime::from(jiff_ts);
+            assert_millisecond_precision(dt);
+            assert_subsec_millis(dt, 123);
+
+            let bson = Bson::from(jiff_ts);
+            assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+            assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 123);
+        }
     }
 
     #[cfg(feature = "time-0_3")]
@@ -373,6 +404,26 @@ fn from_external_datetime() {
         let bdt = DateTime::MIN;
         assert_eq!(bdt.to_chrono(), chrono::DateTime::<Utc>::MIN_UTC);
     }
+    #[cfg(feature = "jiff-0_2")]
+    {
+        let bdt = DateTime::from(jiff::Timestamp::MAX);
+        assert_eq!(
+            bdt.to_jiff().as_millisecond(),
+            jiff::Timestamp::MAX.as_millisecond()
+        );
+
+        let bdt = DateTime::from(jiff::Timestamp::MIN);
+        assert_eq!(
+            bdt.to_jiff().as_millisecond(),
+            jiff::Timestamp::MIN.as_millisecond()
+        );
+
+        let bdt = DateTime::MAX;
+        assert_eq!(bdt.to_jiff(), jiff::Timestamp::MAX);
+
+        let bdt = DateTime::MIN;
+        assert_eq!(bdt.to_jiff(), jiff::Timestamp::MIN);
+    }
 }
 
 #[test]
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index b58980fa..16b4ba37 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -326,7 +326,10 @@ fn test_serialize_utc_date_time() {
     #[allow(unused)]
     let src = time::OffsetDateTime::from_unix_timestamp(1_286_705_410).unwrap();
     #[cfg(feature = "chrono-0_4")]
+    #[allow(unused)]
     let src = chrono::Utc.timestamp_opt(1_286_705_410, 0).unwrap();
+    #[cfg(feature = "jiff-0_2")]
+    let src = jiff::Timestamp::from_second(1_286_705_410).unwrap();
     let dst = vec![
         18, 0, 0, 0, 9, 107, 101, 121, 0, 208, 111, 158, 149, 43, 1, 0, 0, 0,
     ];
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
index 403bcbff..3996fcee 100644
--- a/src/tests/serde.rs
+++ b/src/tests/serde.rs
@@ -1081,6 +1081,78 @@ fn test_datetime_chrono04_datetime_helper() {
     );
 }
 
+#[test]
+#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))]
+fn test_datetime_jiff02_timestamp_helper() {
+    let _guard = LOCK.run_concurrently();
+
+    use std::str::FromStr;
+
+    #[serde_as]
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct A {
+        #[serde_as(as = "datetime::FromJiff02Timestamp")]
+        pub date: jiff::Timestamp,
+
+        #[serde_as(as = "Option<datetime::FromJiff02Timestamp>")]
+        pub date_optional_none: Option<jiff::Timestamp>,
+
+        #[serde_as(as = "Option<datetime::FromJiff02Timestamp>")]
+        pub date_optional_some: Option<jiff::Timestamp>,
+
+        #[serde_as(as = "Vec<datetime::FromJiff02Timestamp>")]
+        pub date_vector: Vec<jiff::Timestamp>,
+    }
+
+    let iso = "1996-12-20T00:39:57Z";
+    let date: jiff::Timestamp = jiff::Timestamp::from_str(iso).unwrap();
+    let a: A = A {
+        date,
+        date_optional_none: None,
+        date_optional_some: Some(date),
+        date_vector: vec![date],
+    };
+
+    // Serialize the struct to BSON
+    let doc = serialize_to_document(&a).unwrap();
+
+    // Validate serialized data
+    assert_eq!(
+        doc.get_datetime("date").unwrap().to_jiff(),
+        date,
+        "Expected serialized date to match original date."
+    );
+
+    assert_eq!(
+        doc.get("date_optional_none"),
+        Some(&Bson::Null),
+        "Expected serialized date_optional_none to be None."
+    );
+
+    assert_eq!(
+        doc.get("date_optional_some"),
+        Some(&Bson::DateTime(DateTime::from_jiff(date))),
+        "Expected serialized date_optional_some to match original."
+    );
+
+    let date_vector = doc
+        .get_array("date_vector")
+        .expect("Expected serialized date_vector to be a BSON array.");
+    let expected_date_vector: Vec<Bson> = vec![Bson::DateTime(date.into())];
+    assert_eq!(
+        date_vector, &expected_date_vector,
+        "Expected each serialized element in date_vector to be a BSON DateTime matching the \
+         original."
+    );
+
+    // Validate deserialized data
+    let a_deserialized: A = deserialize_from_document(doc).unwrap();
+    assert_eq!(
+        a_deserialized, a,
+        "Deserialized struct does not match original."
+    );
+}
+
 #[test]
 #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
 fn test_datetime_time03_offset_datetime_helper() {

From d7b516d97f9522e8ab91b47294ef08e9ba3d712a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 4 Aug 2025 10:53:30 -0400
Subject: [PATCH 150/156] Bump the rust-dependencies group with 2 updates
 (#588)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 59450fc9..8b70c350 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -161,9 +161,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.30"
+version = "1.2.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
+checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
 dependencies = [
  "shlex",
 ]
@@ -964,9 +964,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.141"
+version = "1.0.142"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
+checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
 dependencies = [
  "indexmap 2.10.0",
  "itoa",

From e13a5886597d23f8039a95225e3bb2c661e4249f Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 5 Aug 2025 17:37:19 +0100
Subject: [PATCH 151/156] RUST-1985 Update bson toplevel rustdoc (#589)

---
 src/lib.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 64 insertions(+), 4 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 6ef05641..ed29e7ff 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -65,9 +65,10 @@
 //! | `jiff-0_2` | Enable support for v0.2 of the [`jiff`](https://docs.rs/jiff/0.2) crate in the public API.             | no      |
 //! | `uuid-1`     | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API.           | no      |
 //! | `time-0_3`   | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API.           | no      |
+//! | `serde`      | Enable integration with the [`serde`](https://docs.rs/serde/) serialization/deserialization framework.  | no      |
 //! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for [`DateTime`] and [`Uuid`]. | no      |
 //! | `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest).  This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | no |
-//! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
+//! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | yes |
 //! | `large_dates` | Increase the supported year range for some `bson::DateTime` utilities from +/-9,999 (inclusive) to +/-999,999 (inclusive). Note that enabling this feature can impact performance and introduce parsing ambiguities. | no |
 //! | `serde_json-1` | Enable support for v1.x of the [`serde_json`](https://docs.rs/serde_json/1.x) crate in the public API. | no |
 //!
@@ -170,12 +171,13 @@
 //! let error = doc.get_i64("i32"); // Err(...)
 //! ```
 //!
-//! ## Modeling BSON with strongly typed data structures
+//! ## Integration with `serde`
 //!
 //! While it is possible to work with documents and BSON values directly, it will often introduce a
 //! lot of boilerplate for verifying the necessary keys are present and their values are the correct
-//! types. [`serde`](https://serde.rs/) provides a powerful way of mapping BSON data into Rust data structures largely
-//! automatically, removing the need for all that boilerplate.
+//! types. Enabling the `serde` feature provides integration with the [`serde`](https://serde.rs/)
+//! crate that maps BSON data into Rust data structs largely automatically, removing the need for
+//! all that boilerplate.
 //!
 //! e.g.:
 //! ```rust
@@ -224,6 +226,64 @@
 //! failing field.  This feature does incur a small CPU and memory overhead during (de)serialization
 //! and should be enabled with care in performance-sensitive environments.
 //!
+//! ### Embedding BSON Value Types
+//!
+//! The `serde` feature also enables implementations of [`Serialize`](serde::Serialize) and
+//! [`Deserialize`](serde::Deserialize) for the Rust types provided by this crate that represent
+//! BSON values, allowing them to be embedded in domain-specific structs as appropriate:
+//! ```rust
+//! use serde::{Deserialize, Serialize};
+//! use bson::{bson, Bson, oid::ObjectId};
+//!
+//! #[derive(Serialize, Deserialize)]
+//! struct Person {
+//!     id: ObjectId,
+//!     name: String,
+//!     age: i32,
+//!     phones: Vec<String>,
+//! }
+//!
+//! let bson_data: Bson = bson!({
+//!     "id": ObjectId::new(),
+//!     "name": "John Doe",
+//!     "age": 43,
+//!     "phones": [
+//!         "+44 1234567",
+//!         "+44 2345678"
+//!     ]
+//! });
+//!
+//! let person: Person = bson::deserialize_from_bson(bson_data).unwrap();
+//! ```
+//!
+//! ### Encoding vs. Serialization
+//!
+//! With the `serde` feature enabled, a BSON document can be converted to its wire-format byte
+//! representation in multiple ways:
+//! ```rust
+//! # fn wrapper() -> bson::error::Result<()> {
+//! use bson::{doc, serialize_to_vec};
+//! let my_document = doc! { "hello": "bson" };
+//! let encoded = my_document.to_vec()?;
+//! let serialized = serialize_to_vec(&my_document)?;
+//! # Ok(())
+//! # }
+//! # wrapper().unwrap();
+//! ```
+//!
+//! We recommend that, where possible, documents be converted to byte form using the encoding
+//! methods ([`Document::to_vec`]/[`Document::to_writer`]); this is more efficient as it avoids
+//! the intermediate `serde` data model representation.  This also applies to decoding; prefer
+//! [`Document::from_reader`] over [`deserialize_from_reader`] / [`deserialize_from_slice`].
+//!
+//! ### Serializer Compatibility
+//!
+//! The implementations of [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize)
+//! for BSON value types are tested with the `serde` \[de\]serializers provided by this crate and by
+//! the `serde_json` crate.  Compatibility with formats provided by other crates is not guaranteed
+//! and the data produced by serializing BSON values to other formats may change when this crate is
+//! updated.
+//!
 //! ## Working with Extended JSON
 //!
 //! MongoDB Extended JSON (extJSON) is a format of JSON that allows for the encoding

From 7fd393e3fb8755a92e8fa42363dc2a8796ba171f Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Fri, 8 Aug 2025 16:20:34 +0100
Subject: [PATCH 152/156] RUST-1998 Remove now-redundant
 `to_document_utf8_lossy` method (#592)

---
 src/raw/document.rs                          | 12 ------------
 src/tests/modules/serializer_deserializer.rs |  7 ++++---
 src/tests/spec/corpus.rs                     | 18 +++++++++---------
 3 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/src/raw/document.rs b/src/raw/document.rs
index c07e8984..e62526ec 100644
--- a/src/raw/document.rs
+++ b/src/raw/document.rs
@@ -498,18 +498,6 @@ impl RawDocument {
         let s = try_to_str(bytes)?;
         s.try_into()
     }
-
-    /// Copy this into a [`Document`], returning an error if invalid BSON is encountered.  Any
-    /// invalid UTF-8 sequences will be replaced with the Unicode replacement character.
-    pub fn to_document_utf8_lossy(&self) -> RawResult<Document> {
-        let mut out = Document::new();
-        for elem in self.iter_elements() {
-            let elem = elem?;
-            let value = deep_utf8_lossy(elem.value_utf8_lossy()?)?;
-            out.insert(elem.key().as_str(), value);
-        }
-        Ok(out)
-    }
 }
 
 #[cfg(feature = "serde")]
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
index 16b4ba37..f579a59b 100644
--- a/src/tests/modules/serializer_deserializer.rs
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -21,6 +21,7 @@ use crate::{
     RawDocumentBuf,
     Regex,
     Timestamp,
+    Utf8Lossy,
 };
 use serde_json::json;
 
@@ -74,11 +75,11 @@ fn test_encode_decode_utf8_string_invalid() {
     doc.to_writer(&mut buf).unwrap();
 
     let expected = doc! { "key": "��", "subdoc": { "subkey": "��" } };
-    let decoded = RawDocumentBuf::from_reader(&mut Cursor::new(buf))
+    let decoded: Utf8Lossy<Document> = RawDocumentBuf::from_reader(&mut Cursor::new(buf))
         .unwrap()
-        .to_document_utf8_lossy()
+        .try_into()
         .unwrap();
-    assert_eq!(decoded, expected);
+    assert_eq!(decoded.0, expected);
 }
 
 #[test]
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
index c8bae9c4..fb53c2a7 100644
--- a/src/tests/spec/corpus.rs
+++ b/src/tests/spec/corpus.rs
@@ -562,15 +562,15 @@ fn run_test(test: TestFile) {
             .expect_err(description.as_str());
 
         if decode_error.description.contains("invalid UTF-8") {
-            RawDocumentBuf::from_reader(bson.as_slice())
-                .expect(&description)
-                .to_document_utf8_lossy()
-                .unwrap_or_else(|err| {
-                    panic!(
-                        "{}: utf8_lossy should not fail (failed with {:?})",
-                        description, err
-                    )
-                });
+            Utf8Lossy::<Document>::try_from(
+                RawDocumentBuf::from_reader(bson.as_slice()).expect(&description),
+            )
+            .unwrap_or_else(|err| {
+                panic!(
+                    "{}: utf8_lossy should not fail (failed with {:?})",
+                    description, err
+                )
+            });
             crate::deserialize_from_slice::<Utf8Lossy<Document>>(bson.as_slice())
                 .expect(&description);
         }

From 47d05d38a69803ba3f6437077114563ce7925a60 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 11 Aug 2025 10:06:19 +0100
Subject: [PATCH 153/156] Bump the rust-dependencies group with 3 updates
 (#593)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Cargo.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8b70c350..713d630d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -161,9 +161,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.31"
+version = "1.2.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
+checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e"
 dependencies = [
  "shlex",
 ]
@@ -692,9 +692,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
 dependencies = [
  "unicode-ident",
 ]
@@ -868,9 +868,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.21"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
 
 [[package]]
 name = "rusty-fork"

From 062c499dfc6f7960d332972b1b1bab1912833f30 Mon Sep 17 00:00:00 2001
From: Abraham Egnor <abraham.egnor@mongodb.com>
Date: Tue, 12 Aug 2025 10:45:51 +0100
Subject: [PATCH 154/156] RUST-2148 Migration guide for bson crate 3.0 (#591)

---
 migration-3.0.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 migration-3.0.md

diff --git a/migration-3.0.md b/migration-3.0.md
new file mode 100644
index 00000000..e39062c7
--- /dev/null
+++ b/migration-3.0.md
@@ -0,0 +1,81 @@
+# Migrating from 2.x to 3.0
+3.0 updates several APIs in backwards-incompatible ways; in most cases these changes should require only minor updates in application code.
+
+## Unified error hierarchy
+In 2.x, many crate submodules had their own `Error` types, with inconsistent conversions between those types.  In 3.0, the crate defines a single `bson::error::Error` type, with fields for values common across errors like message or associated key, and a `kind` enum that provides granular root cause information.
+
+## `&CStr`
+The [bson spec](https://bsonspec.org/spec.html) describes a "cstring" type as UTF-8, with the exception that it cannot contain byte `0` (which is otherwise a valid UTF8 byte value).  This type is used in BSON for the keys of documents and for the pattern and options of regular expressions.
+
+In 2.x, attempting to use `rawdoc!` or `RawDocumentBuf::append` with a key or regular expression containing a `0` byte would panic.
+
+3.0 introduces the `&CStr`/`CString` types to represent the "cstring" type as described in the spec; these types are analogous to `&str` and `String` but validate on construction that no `0` byte is contained.  The `cstr!` macro will construct a literal ``&`static CStr`` from a ``&`static str`` with compile-time validation, and `TryFrom` impls are provided for run-time validation.
+
+In 2.x:
+```rust
+let mut computed_key = "foo".to_owned();
+computed_key.push_str("bar");
+let mut doc_buf = rawdoc! {
+    "hello": "world",
+    computed_key: 42,
+    "regex": Regex {
+        pattern: "needle".to_owned(),
+        options: "".to_owned(),
+    },
+};
+doc_buf.append("a key", "a value");
+```
+
+In 3.0:
+```rust
+let mut computed_key = "foo".to_owned();
+computed_key.push_str("bar");
+// Non-static values need to be checked at runtime
+let computed_key = CString::try_from(computed_key)?;
+let doc_buf = rawdoc! {
+    // String literal keys in `rawdoc!` are implicitly checked at compile-time.
+    "hello": "world",
+    computed_key: 42,
+    "regex": Regex {
+        // `&CStr` implements many common traits like `ToOwned`
+        pattern: cstr!("needle").to_owned(),
+        options: cstr!("").to_owned(),
+    }
+};
+// `append` keys must now be a `&CStr` or `CString`.
+doc_buf.append(cstr!("a key"), "a value");
+```
+
+## Conversions
+In 2.x, conversions between raw types (`RawDocumentBuf`, `RawBson`, `RawArray`) and their associated reference types and equivalent core types (`Document`, `Bson`, `Array`) were via a mix of standard traits, ad-hoc functions, and in some cases not present at all.  In 3.0, all appropriate conversions are available, and all are via standard library traits.
+
+## Clarifying encoding vs serialization
+In 2.x, the API documentation, structure, and naming frequently conflated _encoding_ (directly converting Rust BSON values into BSON bytes) with _serialization_ (converting arbitrary Rust structs, including BSON values, to arbitrary formats, including BSON bytes, via the `serde` crate), and likewise for decoding vs deserialization.  This was a persistent footgun for crate users, who could easily end up using `serde` functionality when encoding or decoding would have been simpler and more efficient.
+
+In 3.0, use of `serde` is now an optional feature, disabled by default; additionally, the functions for serialization and deserialization now have `serialize_to_` or `deserialize_from_` prefixes to make the distinction obvious at point of use.
+
+## Documenting supported `serde` formats
+The `serde` data model allows a high degree of flexibility in how data types represent themselves, and how data formats will parse and reconstruct that representation.  This flexibility comes with the downside that not all data types will produce the same values when serialized and deserialized with a given format.  Because of that, for 3.0 we have clarified our compatibility policy:
+
+> The implementations of `Serialize` and `Deserialize` for BSON value types are tested with the `serde` \[de\]serializers provided by this crate and by the `serde_json` crate.  Compatibility with formats provided by other crates is not guaranteed and the data produced by serializing BSON values to other formats may change when this crate is updated.
+
+## Lossy UTF8 text decoding
+BSON text is required to be UTF8 encoded.  However, in various real-world circumstances, text strings may be truncated or contain invalid character sequences; in those circumstances, it's sometimes appropriate to use _lossy text decoding_, where invalid sequences are replaced with the Unicode replacement character.
+
+In 2.x, this was only available for deserialization, not decoding, and had multiple overlapping APIs:
+* the `Utf8LossyDeserialization` wrapper type that would cause the BSON binary deserializer to use lossy string decoding for the wrapped type,
+* `from_slice_utf8_lossy` / `from_reader_utf8_lossy`, functions to deserialize arbitrary types from BSON with lossy string decoding
+* `Document::from_reader_utf8_lossy`, deserializing a `Document` from a byte stream with lossy string decoding
+
+In 3.0, this API has updated to be simpler and to cover both decoding and deserialization:
+* the `Utf8Lossy` wraper type provides the same functionality as `Utf8LossyDeserialization` from 2.x
+* a `RawDocument` can be decoded into a `Utf8Lossy<Document>` via `TryFrom`
+* the `RawElement::value_utf8_lossy` allows low-level element-by-element lossy text decoding
+
+## Serde helpers
+The BSON crate provides a number of helper functions to allow \[de\]serializing common types like `ObjectId` or `DateTime` in other useful formats.  For 3.0, these have been updated to work with the `serde_as` annotation provided by the `serde_with` crate; this allows substantially more flexibility and composition of the annotated field types.
+
+## Smaller changes
+Finally, we made a few small changes for API consistency:
+* `append` and `append_ref` have been merged; `append` now accepts both owned and borrowed values,
+* `RawElement::len` has been renamed to `RawElement::size` to better reflect its purpose.

From e76c0e72164730e66cc619dd4f215490be5b8d07 Mon Sep 17 00:00:00 2001
From: Isabel Atkinson <isabel.atkinson@mongodb.com>
Date: Tue, 12 Aug 2025 14:27:20 -0400
Subject: [PATCH 155/156] minor: bump clippy to 1.89 (#594)

---
 .evergreen/check-clippy.sh |  2 +-
 src/bson.rs                |  2 +-
 src/document.rs            | 10 +++++-----
 src/raw/array.rs           |  2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh
index c2925c75..ca811c7e 100755
--- a/.evergreen/check-clippy.sh
+++ b/.evergreen/check-clippy.sh
@@ -5,7 +5,7 @@ set -o errexit
 . ~/.cargo/env
 
 # Pin clippy to the latest version. This should be updated when new versions of Rust are released.
-CLIPPY_VERSION=1.83.0
+CLIPPY_VERSION=1.89.0
 
 rustup install $CLIPPY_VERSION
 
diff --git a/src/bson.rs b/src/bson.rs
index b131e5cb..da4aa97c 100644
--- a/src/bson.rs
+++ b/src/bson.rs
@@ -789,7 +789,7 @@ impl Bson {
     /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error
     /// reporting.
     #[cfg(feature = "serde")]
-    pub(crate) fn as_unexpected(&self) -> serde::de::Unexpected {
+    pub(crate) fn as_unexpected(&self) -> serde::de::Unexpected<'_> {
         use serde::de::Unexpected;
         match self {
             Bson::Array(_) => Unexpected::Seq,
diff --git a/src/document.rs b/src/document.rs
index 95d8b1ac..422aa98c 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -218,12 +218,12 @@ impl Document {
     }
 
     /// Returns an iterator over the contents of the document.
-    pub fn iter(&self) -> Iter {
+    pub fn iter(&self) -> Iter<'_> {
         self.into_iter()
     }
 
     /// Returns an iterator over mutable references to the contents of the document.
-    pub fn iter_mut(&mut self) -> IterMut {
+    pub fn iter_mut(&mut self) -> IterMut<'_> {
         IterMut {
             inner: self.inner.iter_mut(),
         }
@@ -629,14 +629,14 @@ impl Document {
     }
 
     /// Returns an iterator over the keys in the document.
-    pub fn keys(&self) -> Keys {
+    pub fn keys(&self) -> Keys<'_> {
         Keys {
             inner: self.inner.keys(),
         }
     }
 
     /// Returns an iterator over the values in the document.
-    pub fn values(&self) -> Values {
+    pub fn values(&self) -> Values<'_> {
         Values {
             inner: self.inner.values(),
         }
@@ -666,7 +666,7 @@ impl Document {
     }
 
     /// Returns an [`Entry`] for the given key.
-    pub fn entry(&mut self, k: impl Into<String>) -> Entry {
+    pub fn entry(&mut self, k: impl Into<String>) -> Entry<'_> {
         match self.inner.entry(k.into()) {
             indexmap::map::Entry::Occupied(o) => Entry::Occupied(OccupiedEntry { inner: o }),
             indexmap::map::Entry::Vacant(v) => Entry::Vacant(VacantEntry { inner: v }),
diff --git a/src/raw/array.rs b/src/raw/array.rs
index 6be175d3..28210a59 100644
--- a/src/raw/array.rs
+++ b/src/raw/array.rs
@@ -213,7 +213,7 @@ impl RawArray {
     /// view onto the array but do not parse out or construct
     /// values until the `.value()` or `.try_into()` methods are
     /// called.
-    pub fn iter_elements(&self) -> RawIter {
+    pub fn iter_elements(&self) -> RawIter<'_> {
         RawIter::new(&self.doc)
     }
 }

From 93b391c7cc7eaee815fadc01bdce12f5ddb4aef5 Mon Sep 17 00:00:00 2001
From: Leon Wimbes <12753781+LeWimbes@users.noreply.github.com>
Date: Wed, 13 Aug 2025 16:37:49 +0200
Subject: [PATCH 156/156] RUST-2258 Use borrowed buffer in raw serializer
 (#590)

Co-authored-by: Isabel Atkinson <isabel.atkinson@mongodb.com>
---
 src/lib.rs                         |  1 +
 src/ser.rs                         | 16 ++++++-
 src/ser/raw.rs                     | 74 ++++++++++++++++--------------
 src/ser/raw/document_serializer.rs | 36 +++++++--------
 src/ser/raw/value_serializer.rs    | 50 ++++++++++----------
 5 files changed, 97 insertions(+), 80 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index ed29e7ff..43cfba1e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -474,6 +474,7 @@ pub use self::{
     },
     ser::{
         serialize_to_bson,
+        serialize_to_buffer,
         serialize_to_document,
         serialize_to_raw_document_buf,
         serialize_to_vec,
diff --git a/src/ser.rs b/src/ser.rs
index ca829448..c391e7f7 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -89,7 +89,19 @@ pub fn serialize_to_vec<T>(value: &T) -> Result<Vec<u8>>
 where
     T: Serialize,
 {
-    let mut serializer = raw::Serializer::new();
+    let mut bytes = Vec::new();
+    serialize_to_buffer(value, &mut bytes)?;
+    Ok(bytes)
+}
+
+/// Serialize the given `T` as a BSON byte vector into the provided byte buffer.
+/// This allows reusing the same buffer for multiple serializations.
+#[inline]
+pub fn serialize_to_buffer<T>(value: &T, buffer: &mut Vec<u8>) -> Result<()>
+where
+    T: Serialize,
+{
+    let mut serializer = raw::Serializer::new(buffer);
     #[cfg(feature = "serde_path_to_error")]
     {
         serde_path_to_error::serialize(value, &mut serializer).map_err(Error::with_path)?;
@@ -98,7 +110,7 @@ where
     {
         value.serialize(&mut serializer)?;
     }
-    Ok(serializer.into_vec())
+    Ok(())
 }
 
 /// Serialize the given `T` as a [`RawDocumentBuf`].
diff --git a/src/ser/raw.rs b/src/ser/raw.rs
index 73aec059..d5c3b832 100644
--- a/src/ser/raw.rs
+++ b/src/ser/raw.rs
@@ -22,8 +22,11 @@ use crate::{
 use document_serializer::DocumentSerializer;
 
 /// Serializer used to convert a type `T` into raw BSON bytes.
-pub(crate) struct Serializer {
-    bytes: Vec<u8>,
+pub(crate) struct Serializer<'a> {
+    bytes: &'a mut Vec<u8>,
+
+    /// The index into `bytes` where the current serialization started.
+    start_index: usize,
 
     /// The index into `bytes` where the current element type will need to be stored.
     /// This needs to be set retroactively because in BSON, the element type comes before the key,
@@ -58,21 +61,18 @@ impl SerializerHint {
     }
 }
 
-impl Serializer {
-    pub(crate) fn new() -> Self {
+impl<'a> Serializer<'a> {
+    pub(crate) fn new(bytes: &'a mut Vec<u8>) -> Self {
+        let start_index = bytes.len();
         Self {
-            bytes: Vec::new(),
-            type_index: 0,
+            bytes,
+            start_index,
+            type_index: start_index,
             hint: SerializerHint::None,
             human_readable: false,
         }
     }
 
-    /// Convert this serializer into the vec of the serialized bytes.
-    pub(crate) fn into_vec(self) -> Vec<u8> {
-        self.bytes
-    }
-
     /// Reserve a spot for the element type to be set retroactively via `update_element_type`.
     #[inline]
     fn reserve_element_type(&mut self) {
@@ -83,7 +83,7 @@ impl Serializer {
     /// Retroactively set the element type of the most recently serialized element.
     #[inline]
     fn update_element_type(&mut self, t: ElementType) -> Result<()> {
-        if self.type_index == 0 {
+        if self.type_index == self.start_index {
             if matches!(t, ElementType::EmbeddedDocument) {
                 // don't need to set the element type for the top level document
                 return Ok(());
@@ -108,22 +108,22 @@ impl Serializer {
 
     fn serialize_raw(&mut self, v: RawBsonRef) -> Result<()> {
         self.update_element_type(v.element_type())?;
-        v.append_to(&mut self.bytes);
+        v.append_to(self.bytes);
         Ok(())
     }
 }
 
-impl<'a> serde::Serializer for &'a mut Serializer {
+impl<'a, 'b> serde::Serializer for &'a mut Serializer<'b> {
     type Ok = ();
     type Error = Error;
 
-    type SerializeSeq = DocumentSerializer<'a>;
-    type SerializeTuple = DocumentSerializer<'a>;
-    type SerializeTupleStruct = DocumentSerializer<'a>;
-    type SerializeTupleVariant = VariantSerializer<'a>;
-    type SerializeMap = DocumentSerializer<'a>;
-    type SerializeStruct = StructSerializer<'a>;
-    type SerializeStructVariant = VariantSerializer<'a>;
+    type SerializeSeq = DocumentSerializer<'a, 'b>;
+    type SerializeTuple = DocumentSerializer<'a, 'b>;
+    type SerializeTupleStruct = DocumentSerializer<'a, 'b>;
+    type SerializeTupleVariant = VariantSerializer<'a, 'b>;
+    type SerializeMap = DocumentSerializer<'a, 'b>;
+    type SerializeStruct = StructSerializer<'a, 'b>;
+    type SerializeStructVariant = VariantSerializer<'a, 'b>;
 
     fn is_human_readable(&self) -> bool {
         self.human_readable
@@ -385,15 +385,15 @@ impl<'a> serde::Serializer for &'a mut Serializer {
     }
 }
 
-pub(crate) enum StructSerializer<'a> {
+pub(crate) enum StructSerializer<'a, 'b> {
     /// Serialize a BSON value currently represented in serde as a struct (e.g. ObjectId)
-    Value(ValueSerializer<'a>),
+    Value(ValueSerializer<'a, 'b>),
 
     /// Serialize the struct as a document.
-    Document(DocumentSerializer<'a>),
+    Document(DocumentSerializer<'a, 'b>),
 }
 
-impl SerializeStruct for StructSerializer<'_> {
+impl SerializeStruct for StructSerializer<'_, '_> {
     type Ok = ();
     type Error = Error;
 
@@ -424,8 +424,8 @@ enum VariantInnerType {
 
 /// Serializer used for enum variants, including both tuple (e.g. Foo::Bar(1, 2, 3)) and
 /// struct (e.g. Foo::Bar { a: 1 }).
-pub(crate) struct VariantSerializer<'a> {
-    root_serializer: &'a mut Serializer,
+pub(crate) struct VariantSerializer<'a, 'b> {
+    root_serializer: &'a mut Serializer<'b>,
 
     /// Variants are serialized as documents of the form `{ <variant name>: <document or array> }`,
     /// and `doc_start` indicates the index at which the outer document begins.
@@ -438,22 +438,26 @@ pub(crate) struct VariantSerializer<'a> {
     num_elements_serialized: usize,
 }
 
-impl<'a> VariantSerializer<'a> {
-    fn start(rs: &'a mut Serializer, variant: &'static CStr, inner_type: VariantInnerType) -> Self {
+impl<'a, 'b> VariantSerializer<'a, 'b> {
+    fn start(
+        rs: &'a mut Serializer<'b>,
+        variant: &'static CStr,
+        inner_type: VariantInnerType,
+    ) -> Self {
         let doc_start = rs.bytes.len();
         // write placeholder length for document, will be updated at end
         static ZERO: RawBsonRef = RawBsonRef::Int32(0);
-        ZERO.append_to(&mut rs.bytes);
+        ZERO.append_to(rs.bytes);
 
         let inner = match inner_type {
             VariantInnerType::Struct => ElementType::EmbeddedDocument,
             VariantInnerType::Tuple => ElementType::Array,
         };
         rs.bytes.push(inner as u8);
-        variant.append_to(&mut rs.bytes);
+        variant.append_to(rs.bytes);
         let inner_start = rs.bytes.len();
         // write placeholder length for inner, will be updated at end
-        ZERO.append_to(&mut rs.bytes);
+        ZERO.append_to(rs.bytes);
 
         Self {
             root_serializer: rs,
@@ -469,7 +473,7 @@ impl<'a> VariantSerializer<'a> {
         T: Serialize + ?Sized,
     {
         self.root_serializer.reserve_element_type();
-        CStr::from_str(k)?.append_to(&mut self.root_serializer.bytes);
+        CStr::from_str(k)?.append_to(self.root_serializer.bytes);
         v.serialize(&mut *self.root_serializer)?;
 
         self.num_elements_serialized += 1;
@@ -492,7 +496,7 @@ impl<'a> VariantSerializer<'a> {
     }
 }
 
-impl serde::ser::SerializeTupleVariant for VariantSerializer<'_> {
+impl serde::ser::SerializeTupleVariant for VariantSerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
@@ -511,7 +515,7 @@ impl serde::ser::SerializeTupleVariant for VariantSerializer<'_> {
     }
 }
 
-impl serde::ser::SerializeStructVariant for VariantSerializer<'_> {
+impl serde::ser::SerializeStructVariant for VariantSerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
diff --git a/src/ser/raw/document_serializer.rs b/src/ser/raw/document_serializer.rs
index a2317eb7..ef54d558 100644
--- a/src/ser/raw/document_serializer.rs
+++ b/src/ser/raw/document_serializer.rs
@@ -7,21 +7,21 @@ use crate::{
 
 use super::Serializer;
 
-pub(crate) struct DocumentSerializationResult<'a> {
-    pub(crate) root_serializer: &'a mut Serializer,
+pub(crate) struct DocumentSerializationResult<'a, 'b> {
+    pub(crate) root_serializer: &'a mut Serializer<'b>,
 }
 
 /// Serializer used to serialize document or array bodies.
-pub(crate) struct DocumentSerializer<'a> {
-    root_serializer: &'a mut Serializer,
+pub(crate) struct DocumentSerializer<'a, 'b> {
+    root_serializer: &'a mut Serializer<'b>,
     num_keys_serialized: usize,
     start: usize,
 }
 
-impl<'a> DocumentSerializer<'a> {
-    pub(crate) fn start(rs: &'a mut Serializer) -> Self {
+impl<'a, 'b> DocumentSerializer<'a, 'b> {
+    pub(crate) fn start(rs: &'a mut Serializer<'b>) -> Self {
         let start = rs.bytes.len();
-        RawBsonRef::Int32(0).append_to(&mut rs.bytes);
+        RawBsonRef::Int32(0).append_to(rs.bytes);
         Self {
             root_serializer: rs,
             num_keys_serialized: 0,
@@ -30,7 +30,7 @@ impl<'a> DocumentSerializer<'a> {
     }
 
     /// Serialize a document key using the provided closure.
-    fn serialize_doc_key_custom<F: FnOnce(&mut Serializer) -> Result<()>>(
+    fn serialize_doc_key_custom<F: FnOnce(&mut Serializer<'b>) -> Result<()>>(
         &mut self,
         f: F,
     ) -> Result<()> {
@@ -55,7 +55,7 @@ impl<'a> DocumentSerializer<'a> {
         Ok(())
     }
 
-    pub(crate) fn end_doc(self) -> crate::ser::Result<DocumentSerializationResult<'a>> {
+    pub(crate) fn end_doc(self) -> crate::ser::Result<DocumentSerializationResult<'a, 'b>> {
         self.root_serializer.bytes.push(0);
         let length = (self.root_serializer.bytes.len() - self.start) as i32;
         self.root_serializer.replace_i32(self.start, length);
@@ -65,7 +65,7 @@ impl<'a> DocumentSerializer<'a> {
     }
 }
 
-impl serde::ser::SerializeSeq for DocumentSerializer<'_> {
+impl serde::ser::SerializeSeq for DocumentSerializer<'_, '_> {
     type Ok = ();
     type Error = Error;
 
@@ -90,7 +90,7 @@ impl serde::ser::SerializeSeq for DocumentSerializer<'_> {
     }
 }
 
-impl serde::ser::SerializeMap for DocumentSerializer<'_> {
+impl serde::ser::SerializeMap for DocumentSerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
@@ -116,7 +116,7 @@ impl serde::ser::SerializeMap for DocumentSerializer<'_> {
     }
 }
 
-impl serde::ser::SerializeStruct for DocumentSerializer<'_> {
+impl serde::ser::SerializeStruct for DocumentSerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
@@ -136,7 +136,7 @@ impl serde::ser::SerializeStruct for DocumentSerializer<'_> {
     }
 }
 
-impl serde::ser::SerializeTuple for DocumentSerializer<'_> {
+impl serde::ser::SerializeTuple for DocumentSerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
@@ -156,7 +156,7 @@ impl serde::ser::SerializeTuple for DocumentSerializer<'_> {
     }
 }
 
-impl serde::ser::SerializeTupleStruct for DocumentSerializer<'_> {
+impl serde::ser::SerializeTupleStruct for DocumentSerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
@@ -178,11 +178,11 @@ impl serde::ser::SerializeTupleStruct for DocumentSerializer<'_> {
 
 /// Serializer used specifically for serializing document keys.
 /// Only keys that serialize to strings will be accepted.
-struct KeySerializer<'a> {
-    root_serializer: &'a mut Serializer,
+struct KeySerializer<'a, 'b> {
+    root_serializer: &'a mut Serializer<'b>,
 }
 
-impl serde::Serializer for KeySerializer<'_> {
+impl serde::Serializer for KeySerializer<'_, '_> {
     type Ok = ();
 
     type Error = Error;
@@ -257,7 +257,7 @@ impl serde::Serializer for KeySerializer<'_> {
 
     #[inline]
     fn serialize_str(self, v: &str) -> Result<Self::Ok> {
-        crate::raw::CStr::from_str(v)?.append_to(&mut self.root_serializer.bytes);
+        crate::raw::CStr::from_str(v)?.append_to(self.root_serializer.bytes);
         Ok(())
     }
 
diff --git a/src/ser/raw/value_serializer.rs b/src/ser/raw/value_serializer.rs
index 5df7f4f4..5e0d79a2 100644
--- a/src/ser/raw/value_serializer.rs
+++ b/src/ser/raw/value_serializer.rs
@@ -21,8 +21,8 @@ use super::{document_serializer::DocumentSerializer, Serializer};
 
 /// A serializer used specifically for serializing the serde-data-model form of a BSON type (e.g.
 /// [`Binary`]) to raw bytes.
-pub(crate) struct ValueSerializer<'a> {
-    root_serializer: &'a mut Serializer,
+pub(crate) struct ValueSerializer<'a, 'b> {
+    root_serializer: &'a mut Serializer<'b>,
     state: SerializationStep,
 }
 
@@ -124,8 +124,8 @@ impl From<ValueType> for ElementType {
     }
 }
 
-impl<'a> ValueSerializer<'a> {
-    pub(super) fn new(rs: &'a mut Serializer, value_type: ValueType) -> Self {
+impl<'a, 'b> ValueSerializer<'a, 'b> {
+    pub(super) fn new(rs: &'a mut Serializer<'b>, value_type: ValueType) -> Self {
         let state = match value_type {
             ValueType::DateTime => SerializationStep::DateTime,
             ValueType::Binary => SerializationStep::Binary,
@@ -155,7 +155,7 @@ impl<'a> ValueSerializer<'a> {
     }
 }
 
-impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
+impl<'a, 'b> serde::Serializer for &'a mut ValueSerializer<'_, 'b> {
     type Ok = ();
     type Error = Error;
 
@@ -163,7 +163,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     type SerializeTuple = Impossible<(), Error>;
     type SerializeTupleStruct = Impossible<(), Error>;
     type SerializeTupleVariant = Impossible<(), Error>;
-    type SerializeMap = CodeWithScopeSerializer<'b>;
+    type SerializeMap = CodeWithScopeSerializer<'a, 'b>;
     type SerializeStruct = Self;
     type SerializeStructVariant = Impossible<(), Error>;
 
@@ -199,7 +199,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                 let increment = u32::try_from(v).map_err(Error::custom)?;
 
                 RawBsonRef::Timestamp(crate::Timestamp { time, increment })
-                    .append_to(&mut self.root_serializer.bytes);
+                    .append_to(self.root_serializer.bytes);
 
                 Ok(())
             }
@@ -215,7 +215,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                     subtype: v.into(),
                     bytes,
                 };
-                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::Binary(binary).append_to(self.root_serializer.bytes);
                 self.state = SerializationStep::Done;
                 Ok(())
             }
@@ -258,11 +258,11 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::DateTimeNumberLong => {
                 let millis = v.parse().map_err(Error::custom)?;
                 RawBsonRef::DateTime(crate::DateTime::from_millis(millis))
-                    .append_to(&mut self.root_serializer.bytes);
+                    .append_to(self.root_serializer.bytes);
             }
             SerializationStep::Oid => {
                 let oid = ObjectId::parse_str(v).map_err(Error::custom)?;
-                RawBsonRef::ObjectId(oid).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::ObjectId(oid).append_to(self.root_serializer.bytes);
             }
             SerializationStep::BinaryBytes => {
                 self.state = SerializationStep::BinarySubType {
@@ -274,10 +274,10 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                 let subtype: BinarySubtype = subtype_byte[0].into();
                 let bytes = &base64::decode(base64.as_str()).map_err(Error::custom)?;
                 let binary = RawBinaryRef { subtype, bytes };
-                RawBsonRef::Binary(binary).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::Binary(binary).append_to(self.root_serializer.bytes);
             }
             SerializationStep::Symbol => {
-                RawBsonRef::Symbol(v).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::Symbol(v).append_to(self.root_serializer.bytes);
             }
             SerializationStep::DbPointerRef => {
                 self.state = SerializationStep::DbPointerId { ns: v.to_owned() };
@@ -285,7 +285,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
             SerializationStep::DbPointerId { ns } => {
                 let id = ObjectId::parse_str(v).map_err(Error::custom)?;
                 RawBsonRef::DbPointer(crate::RawDbPointerRef { namespace: ns, id })
-                    .append_to(&mut self.root_serializer.bytes);
+                    .append_to(self.root_serializer.bytes);
             }
             SerializationStep::RegExPattern => {
                 self.state = SerializationStep::RegExOptions {
@@ -301,10 +301,10 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                     pattern: pattern.as_ref(),
                     options: options.as_str().try_into()?,
                 })
-                .append_to(&mut self.root_serializer.bytes);
+                .append_to(self.root_serializer.bytes);
             }
             SerializationStep::Code => {
-                RawBsonRef::JavaScriptCode(v).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::JavaScriptCode(v).append_to(self.root_serializer.bytes);
             }
             SerializationStep::CodeWithScopeCode => {
                 self.state = SerializationStep::CodeWithScopeScope {
@@ -327,7 +327,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
         match self.state {
             SerializationStep::Decimal128Value => {
                 let dec = crate::Decimal128::from_bytes(v.try_into().map_err(Error::custom)?);
-                RawBsonRef::Decimal128(dec).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::Decimal128(dec).append_to(self.root_serializer.bytes);
                 Ok(())
             }
             SerializationStep::BinaryBytes => {
@@ -339,7 +339,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
                     code,
                     scope: RawDocument::from_bytes(v).map_err(Error::custom)?,
                 };
-                RawBsonRef::JavaScriptCodeWithScope(raw).append_to(&mut self.root_serializer.bytes);
+                RawBsonRef::JavaScriptCodeWithScope(raw).append_to(self.root_serializer.bytes);
                 self.state = SerializationStep::Done;
                 Ok(())
             }
@@ -475,7 +475,7 @@ impl<'b> serde::Serializer for &'b mut ValueSerializer<'_> {
     }
 }
 
-impl SerializeStruct for &mut ValueSerializer<'_> {
+impl SerializeStruct for &mut ValueSerializer<'_, '_> {
     type Ok = ();
     type Error = Error;
 
@@ -605,24 +605,24 @@ impl SerializeStruct for &mut ValueSerializer<'_> {
     }
 }
 
-pub(crate) struct CodeWithScopeSerializer<'a> {
+pub(crate) struct CodeWithScopeSerializer<'a, 'b> {
     start: usize,
-    doc: DocumentSerializer<'a>,
+    doc: DocumentSerializer<'a, 'b>,
 }
 
-impl<'a> CodeWithScopeSerializer<'a> {
+impl<'a, 'b> CodeWithScopeSerializer<'a, 'b> {
     #[inline]
-    fn start(code: &str, rs: &'a mut Serializer) -> Self {
+    fn start(code: &str, rs: &'a mut Serializer<'b>) -> Self {
         let start = rs.bytes.len();
-        RawBsonRef::Int32(0).append_to(&mut rs.bytes); // placeholder length
-        write_string(&mut rs.bytes, code);
+        RawBsonRef::Int32(0).append_to(rs.bytes); // placeholder length
+        write_string(rs.bytes, code);
 
         let doc = DocumentSerializer::start(rs);
         Self { start, doc }
     }
 }
 
-impl SerializeMap for CodeWithScopeSerializer<'_> {
+impl SerializeMap for CodeWithScopeSerializer<'_, '_> {
     type Ok = ();
     type Error = Error;
 
