Skip to content

RUST-2471 Fix Eq implementation for Bson; extend Eq/Hash to raw types - #686

Open
abr-egn wants to merge 1 commit into
mongodb:mainfrom
abr-egn:RUST-2471/bson-eq
Open

RUST-2471 Fix Eq implementation for Bson; extend Eq/Hash to raw types#686
abr-egn wants to merge 1 commit into
mongodb:mainfrom
abr-egn:RUST-2471/bson-eq

Conversation

@abr-egn

@abr-egn abr-egn commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

RUST-2471

This changes the Bson impl for PartialEq to compare by byte value rather than the derived comparison, which carried the float non-reflexive behavior and made Eq a lie. To keep things consistent, I updated the raw types to use the same comparison; this also meant making the raw types Eq/Hash was straightforward.

Notably, the raw buffer types (RawDocument[Buf], RawArray[Buf]) were already just comparing by byte value, so this change makes everything consistent rather than having an undocumented mismatch.

Fixes #683, #684.

Comment thread src/raw/bson.rs

impl std::hash::Hash for RawBson {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is unrelated to the rest of the changes, but since we're changing the hash output (or adding it in the case of the raw types), this makes it behave a little better. Including the discriminant in the hash reduces collisions; previously, all the unit variants would hash equal, as would pairs like Bson::String("x") and Bson::Symbol("x").

Comment thread src/raw/bson_ref.rs
impl<'a> PartialEq for RawBsonRef<'a> {
fn eq(&self, other: &Self) -> bool {
match self {
Self::Double(s) => matches!(other, Self::Double(o) if s.to_bits() == o.to_bits()),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This slightly awkward construction means there doesn't need to be a fallthrough case like there would be for matching directly against (self, other), so we keep the compile-time exhaustiveness check.

Comment thread src/bson.rs
std::mem::discriminant(self).hash(state);
match self {
Bson::Double(double) => {
if *double == 0.0_f64 {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This special casing goes away because both equality and hash are just using the byte values.

@abr-egn
abr-egn marked this pull request as ready for review August 14, 2026 11:34
@abr-egn
abr-egn requested a review from a team as a code owner August 14, 2026 11:34
@abr-egn
abr-egn requested a review from isabelatkinson August 14, 2026 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RUST-2471 Bson doesn't uphold Eq's reflexivity guarantee

1 participant