Skip to content

RUST-2215 Ergonomics for HumanReadable #540

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 2 commits into from
May 28, 2025
Merged
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
60 changes: 58 additions & 2 deletions src/serde_helpers.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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
Expand Down