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

Should the BitFlags trait subtrait BitAnd et al.? #293

Closed
PatchMixolydic opened this issue Dec 9, 2022 · 5 comments
Closed

Should the BitFlags trait subtrait BitAnd et al.? #293

PatchMixolydic opened this issue Dec 9, 2022 · 5 comments

Comments

@PatchMixolydic
Copy link

PatchMixolydic commented Dec 9, 2022

I'm currently using bitflags to implement collision bitmasks in a game engine. Of course, since different games use collision for different things, I decided to try making my collider type generic over the mask type using the BitFlags trait. However, this didn't quite work:

error[E0369]: no implementation for `M & M`
   --> triplicata/src/collision.rs:222:53
    |
222 | what_collided: self.accept_mask & other.generate_mask,
    |                ---------------- ^ ------------------- M
    |                |
    |                M
    |
help: consider further restricting this bound
    |
157 | impl<M: BitFlags + std::ops::BitAnd<Output = M>> Hitbox<M> {
    |                  ++++++++++++++++++++++++++++++

Since the types created by bitflags! always implement BitAnd (alongside several other traits), it might be convenient for BitFlags to subtrait BitAnd et al. Is this feasible?

(I realize I could probably just use BitAnd as a bound on its own in this case, but I'd like to push users towards using bitflags to define their bitmasks.)

cc #262

@KodrAus
Copy link
Member

KodrAus commented Jan 31, 2023

Hi @PatchMixolydic 👋

I think the only reason we don't currently use Bit* traits as supertraits was to keep the initial scope of BitFlags small since the trait itself is quite new. We may allow the trait to be implemented manually at some point, in which case we'd have to be careful about what additional traits we've inherited from the bitflags! macro. To be fair, the Bit* traits are probably not contentious as supertraits of BitFlags.

In the meantime, you can use the intersection method as an alternative to &.

@rusty-snake
Copy link
Contributor

To leave a more complex example:

fn contains_uncorresponding_bits<T, U>(flags: T) -> bool
where
    T: BitFlags<Bits = U> + BitAnd<Output = T>,
    U: Not<Output = U>,
{
    !(flags & (T::from_bits_retain(!T::all().bits()))).is_empty()
}

In the meantime, you can use the intersection method as an alternative to &.

The BitFlags trait does not have "Set" methods (intersection, union, difference, ...).

@rusty-snake
Copy link
Contributor

rusty-snake commented Apr 2, 2023

Ok, this should give you almost everything:

use core::fmt::{Binary, LowerHex, Octal, UpperHex};
use core::ops::{
    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
    Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};

use bitflags::BitFlags;

pub trait BitFlagsExt {
    fn complement_retain(self) -> Self;
    fn has_uncorresponding_bits(self) -> bool;
}
impl<T, U> BitFlagsExt for T
where
    T: BitFlags<Bits = U>
        + BitAnd<Output = T>
        + BitAndAssign
        + BitOr<Output = T>
        + BitOrAssign
        + BitXor<Output = T>
        + BitXorAssign
        + Not<Output = T>
        + Sub<Output = T>
        + SubAssign
        + Extend<T>
        + FromIterator<T>
        + IntoIterator
        + Binary
        + LowerHex
        + Octal
        + UpperHex,
    U: BitAnd<Output = U>
        + BitAndAssign
        + BitOr<Output = U>
        + BitOrAssign
        + BitXor<Output = U>
        + BitXorAssign
        + Not<Output = U>
        + Shl<Output = U>
        + ShlAssign
        + Shr<Output = U>
        + ShrAssign
        + Add<Output = U>
        + AddAssign
        + Div<Output = U>
        + DivAssign
        + Mul<Output = U>
        + MulAssign
        + Rem<Output = U>
        + RemAssign
        + Sub<Output = U>
        + SubAssign,
{
    fn complement_retain(self) -> Self {
        Self::from_bits_retain(!self.bits())
    }

    fn has_uncorresponding_bits(self) -> bool {
        !(self & Self::all().complement_retain()).is_empty()
    }
}

@KodrAus
Copy link
Member

KodrAus commented Apr 2, 2023

The BitFlags trait does not have "Set" methods (intersection, union, difference, ...).

Ah, those are methods I think we should add to the Bits trait.

@KodrAus
Copy link
Member

KodrAus commented May 17, 2023

In #348 I made the BitFlags trait far more useful and publicly implementable. I don't think we'll add all these supertrait bounds directly so that the trait is easy to implement, but have added the set operator methods to it that are automatically implemented for you.

Thanks for the input everyone!

@KodrAus KodrAus closed this as completed May 17, 2023
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

3 participants