Skip to content
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
1 change: 0 additions & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
15 changes: 14 additions & 1 deletion src/de/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -65,6 +68,7 @@ impl<'de> Deserializer<'de> {
Self {
bytes: BsonBuf::new(buf, utf8_lossy),
current_type: ElementType::EmbeddedDocument,
human_readable: false,
}
}

Expand Down Expand Up @@ -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(),
))
}
Expand Down Expand Up @@ -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(),
))
}
Expand Down Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be an issue when a HumanReadable<T> is nested in a struct with non-wrapped types following it? e.g.

struct Test {
    human_readable: HumanReadable<Document>,
    non_human_readable: Document,
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I've fixed the logic and updated the test to flag that kind of failure.

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! {
Expand Down
12 changes: 11 additions & 1 deletion src/de/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>,
}

Expand All @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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),
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/ser/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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
Expand Down Expand Up @@ -60,6 +63,7 @@ impl Serializer {
bytes: Vec::new(),
type_index: 0,
hint: SerializerHint::None,
human_readable: false,
}
}

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 11 additions & 1 deletion src/ser/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>,
}

Expand All @@ -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
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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),
}
}
Expand Down Expand Up @@ -447,6 +456,7 @@ impl ser::Serializer for Serializer {
})
}

#[allow(deprecated)]
fn is_human_readable(&self) -> bool {
self.options.human_readable.unwrap_or(true)
}
Expand Down
45 changes: 43 additions & 2 deletions src/serde_helpers.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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))
}
}
1 change: 1 addition & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod binary_subtype;
mod datetime;
mod modules;
mod serde;
mod serde_helpers;
mod spec;

use modules::TestLock;
Expand Down
Loading