Skip to content
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

Broken Equality using NewType Wrappers around Ulid and Derive Equality macros #40

Closed
moises-marquez opened this issue Oct 23, 2021 · 1 comment

Comments

@moises-marquez
Copy link

Not so long ago I found a weird case of broken equality in my wrapper types around Ulid which I can't find an explanation for after looking at the codebase for ulid-rs. I have created an example where I replicate it, hoping it could help to find out what could be wrong:

use std::fmt;
use ulid::Ulid;

fn main() {
    struct MyNewType {
        id: MyOtherNewTypeId,
    }

    #[derive(Debug, Eq, PartialEq, Copy, Clone)]
    struct MyNewTypeId(Ulid);

    impl MyNewTypeId {
        pub fn parse(string: String) -> Result<Self, ()> {
            Ulid::from_string(&string)
                .map(|ulid| Self(ulid))
                .map_err(|_| ())
        }
    }

    impl AsRef<Ulid> for MyNewTypeId {
        fn as_ref(&self) -> &Ulid {
            &self.0
        }
    }

    struct MyOtherNewType {
        pub id: MyOtherNewTypeId,
    }

    #[derive(Debug, Eq, PartialEq, Copy, Clone)]
    struct MyOtherNewTypeId(Ulid);

    impl MyOtherNewTypeId {
        pub fn new() -> Self {
            Self(Ulid::new())
        }

        pub fn parse(string: String) -> Result<Self, ()> {
            Ulid::from_string(&string)
                .map(|ulid| Self(ulid))
                .map_err(|_| ())
        }
    }

    impl AsRef<Ulid> for MyOtherNewTypeId {
        fn as_ref(&self) -> &Ulid {
            &self.0
        }
    }

    #[derive(Debug, Eq, PartialEq)]
    enum MyIdTypesEnum {
        MyNewTypeIdEnumVariant(MyNewTypeId),
        MyOtherNewTypeIdEnumVariant(MyOtherNewTypeId),
    }

    impl From<MyNewTypeId> for MyIdTypesEnum {
        fn from(my_new_type_id: MyNewTypeId) -> Self {
            Self::MyNewTypeIdEnumVariant(my_new_type_id)
        }
    }

    impl From<MyOtherNewTypeId> for MyIdTypesEnum {
        fn from(my_other_new_type_id: MyOtherNewTypeId) -> Self {
            Self::MyOtherNewTypeIdEnumVariant(my_other_new_type_id)
        }
    }

    impl AsRef<Ulid> for MyIdTypesEnum {
        fn as_ref(&self) -> &Ulid {
            match self {
                Self::MyNewTypeIdEnumVariant(my_new_type_id) => my_new_type_id.as_ref(),
                Self::MyOtherNewTypeIdEnumVariant(my_other_new_type_id) => my_other_new_type_id.as_ref(),
            }
        }
    }

    impl fmt::Display for MyIdTypesEnum {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.as_ref())
        }
    }

    enum MyTypesEnum {
        MyNewTypeEnumVariant(MyNewType),
        MyOtherNewTypeEnumVariant(MyOtherNewType),
    }

    impl MyTypesEnum {
        pub fn get_id(&self) -> MyIdTypesEnum {
            match self {
                Self::MyNewTypeEnumVariant(my_new_type) => my_new_type.id.into(),
                Self::MyOtherNewTypeEnumVariant(my_other_new_type) => my_other_new_type.id.into(),
            }
        }
    }

    struct SomeOtherStruct {
        pub new_types_id: MyIdTypesEnum,
    }

    let some_other_struct = SomeOtherStruct {
        new_types_id: MyIdTypesEnum::MyNewTypeIdEnumVariant(
            MyNewTypeId::parse("01FJ4HS4AQCEBWTGM951G1NHE6".to_string()).unwrap(),
        ),
    };
    let my_types_enum = MyTypesEnum::MyOtherNewTypeEnumVariant(MyOtherNewType {
        id: MyOtherNewTypeId::parse("01FJ4HS4AQCEBWTGM951G1NHE6".to_string()).unwrap(),
    });
    println!(
        "Hello, broken equality! Equality is: {:?}",
        &some_other_struct.new_types_id == &my_types_enum.get_id()
        // &some_other_struct.new_types_id.to_string() == &my_types_enum.get_id().to_string()
    );
}

Will also follow up with the community and see what they think about this.

Thanks in advance!

@moises-marquez
Copy link
Author

Closing it. The issue was that I was comparing two different MyIdTypesEnum enum variants, and this breaks the equality check.

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

No branches or pull requests

1 participant