Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@CosmicHorrorDev
Copy link
Contributor

@CosmicHorrorDev CosmicHorrorDev commented Jul 26, 2025

Ref #512

bitflags was only being used for FontStyle, so it seems reasonable to me to just replace it with its expanded code (courtesy of cargo-expand plus lots of manual cleanup). No more outdated dependency for anyone to complain about now 😆🙊. This also gives us the liberty of customizing the docs to our specific use along with being able to freely #[deprecate] anything that we want to drop with the next major release (I'm looking at you unsafe fn from_bits_unchecked(bits: u8) -> Self 👀)

That being said the generated code was very gross because it handled a bunch of edge-cases that we can ignore, so I also took a few passes at cleaning things up with -- what should be -- equivalent implementations. Take the original expanded debug impl for example (yes it was the worst of the bunch)

impl core::fmt::Debug for FontStyle {
    fn fmt(
        &self,
        f: &mut core::fmt::Formatter,
    ) -> core::fmt::Result {
        #[allow(non_snake_case)]
        trait __BitFlags {
            #[inline]
            fn BOLD(&self) -> bool {
                false
            }
            #[inline]
            fn UNDERLINE(&self) -> bool {
                false
            }
            #[inline]
            fn ITALIC(&self) -> bool {
                false
            }
        }
        #[allow(non_snake_case)]
        impl __BitFlags for FontStyle {
            #[allow(deprecated)]
            #[inline]
            fn BOLD(&self) -> bool {
                if Self::BOLD.bits == 0 && self.bits != 0 {
                    false
                } else {
                    self.bits & Self::BOLD.bits == Self::BOLD.bits
                }
            }
            #[allow(deprecated)]
            #[inline]
            fn UNDERLINE(&self) -> bool {
                if Self::UNDERLINE.bits == 0 && self.bits != 0 {
                    false
                } else {
                    self.bits & Self::UNDERLINE.bits == Self::UNDERLINE.bits
                }
            }
            #[allow(deprecated)]
            #[inline]
            fn ITALIC(&self) -> bool {
                if Self::ITALIC.bits == 0 && self.bits != 0 {
                    false
                } else {
                    self.bits & Self::ITALIC.bits == Self::ITALIC.bits
                }
            }
        }
        let mut first = true;
        if <Self as __BitFlags>::BOLD(self) {
            if !first {
                f.write_str(" | ")?;
            }
            first = false;
            f.write_str("BOLD")?;
        }
        if <Self as __BitFlags>::UNDERLINE(self) {
            if !first {
                f.write_str(" | ")?;
            }
            first = false;
            f.write_str("UNDERLINE")?;
        }
        if <Self as __BitFlags>::ITALIC(self) {
            if !first {
                f.write_str(" | ")?;
            }
            first = false;
            f.write_str("ITALIC")?;
        }
        let extra_bits = self.bits & !Self::all().bits();
        if extra_bits != 0 {
            if !first {
                f.write_str(" | ")?;
            }
            first = false;
            f.write_str("0x")?;
            core::fmt::LowerHex::fmt(&extra_bits, f)?;
        }
        if first {
            f.write_str("(empty)")?;
        }
        Ok(())
    }
}

Cursed looking? Absolutely

Here's the cleaned up version

impl fmt::Debug for FontStyle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut empty = true;

        let pairs = [
            (Self::BOLD, "BOLD"),
            (Self::UNDERLINE, "UNDERLINE"),
            (Self::ITALIC, "ITALIC"),
        ];
        for (flag, flag_str) in pairs {
            if self.contains(flag) {
                if !std::mem::take(&mut empty) {
                    f.write_str(" | ")?;
                }
                f.write_str(flag_str)?;
            }
        }

        let extra_bits = self.bits & !Self::all().bits();
        if extra_bits != 0 {
            if !std::mem::take(&mut empty) {
                f.write_str(" | ")?;
            }
            f.write_str("0x")?;
            fmt::LowerHex::fmt(&extra_bits, f)?;
        }

        if empty {
            f.write_str("(empty)")?;
        }

        Ok(())
    }
}

Unreachable branches like if Self::BOLD.bits == 0 && self.bits != 0 { were pruned (none of our flags == 0). The internal __BitFlags trait was removed entirely (including the default methods that were all unused). Etc. etc.

Note: I took the liberty of removing all of the #[inline]s because it's generally an optimization code smell to have on everything (and it was on virtually everything)

Copy link
Collaborator

@Enselic Enselic left a comment

Choose a reason for hiding this comment

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

Definitely a step in the right direction, thanks!

For the next breaking release we might want look over what the API should look like long term, but since the API remains unchanged to consumers I'd say let's merge this.

I'll merge it latest Monday, I want to give other maintainers a reasonable chance of giving input first though.

@CosmicHorrorDev
Copy link
Contributor Author

For the next breaking release we might want look over what the API should look like long term, but since the API remains unchanged to consumers I'd say let's merge this.

Totally agree!

Copy link
Collaborator

@keith-hall keith-hall left a comment

Choose a reason for hiding this comment

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

Nice, I appreciate the detailed description/ explanation as well btw, thank you! 🚀

@Enselic
Copy link
Collaborator

Enselic commented Jul 26, 2025

If Keith is also on board let's merge :)

@Enselic Enselic merged commit fc05913 into trishume:master Jul 26, 2025
4 checks passed
@CosmicHorrorDev CosmicHorrorDev deleted the bitflags-at-home branch July 26, 2025 08:12
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.

3 participants