Skip to content

RUST-2228 Normalize conversions between raw types and base crate types #580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/iterate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
});
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/string_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/type_markers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
12 changes: 6 additions & 6 deletions fuzz/generate_corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()))?,
)?;

Expand All @@ -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()))?,
)?;

Expand Down Expand Up @@ -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()))?,
)?;

Expand Down Expand Up @@ -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()))?,
)?;

Expand All @@ -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()))?,
)?;

Expand All @@ -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()))?,
)?;

Expand Down
22 changes: 11 additions & 11 deletions serde-tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use bson::{
cstr,
doc,
oid::ObjectId,
serde_helpers::Utf8LossyDeserialization,
spec::BinarySubtype,
Binary,
Bson,
Expand All @@ -43,6 +42,7 @@ use bson::{
RawRegexRef,
Regex,
Timestamp,
Utf8Lossy,
Uuid,
};

Expand All @@ -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);

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 };
Expand All @@ -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());
}
3 changes: 2 additions & 1 deletion src/de/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 10 additions & 10 deletions src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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(())
}
Expand All @@ -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()
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -396,6 +396,7 @@ pub use self::{
RawJavaScriptCodeWithScopeRef,
RawRegexRef,
},
utf8_lossy::Utf8Lossy,
uuid::{Uuid, UuidRepresentation},
};

Expand Down Expand Up @@ -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)]
Expand Down
Loading