-
Notifications
You must be signed in to change notification settings - Fork 144
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
BitFlags trait #220
BitFlags trait #220
Conversation
Adds a BitFlags trait that is implemented by every bitflags. The trait includes documentation so it the current hack to document methods through an example could be removed Closes bitflags#154
Any updates on this? I've been looking for something like this for a project, and the changes look reasonable. |
src/bitflags_trait.rs
Outdated
use core as _core; | ||
|
||
pub trait BitFlags<T>: | ||
_core::ops::BitOr<Output = Self> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be better for the BitFlags
trait not to include these additional supertraits and let consumers add them as additional bounds if they need them.
On the one hand it seems reasonable that if you've got flags you'll want to perform bitwise operations on them, but on the other it's a bit of a grab-bag snapshot of our current functionality that we won't be able to extend (since we can't add new supertraits without breakage).
It might be best to stick with just the current set of methods on the trait which cover:
- Construction from bits
- Conversion back into bits
- Set operations on pairs of flags
That should be enough to support a wide range of fundamental use-cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about Clone + Copy? I need those to implement the iterator which is based on a value and removes the flags as it advances through it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the BitFlags
type itself to be Copy
? Or just the underlying bits? If I understand right, we could just perform shifts and masks on the bits themselves and use BitFlags::from_bits_unchecked
to return just that flag.
src/bitflags_trait.rs
Outdated
fn from_bits(bits: T) -> _core::option::Option<Self>; | ||
/// Convert from underlying bit representation, dropping any bits | ||
/// that do not correspond to flags. | ||
unsafe fn from_bits_truncate(bits: T) -> Self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method doesn't need to be unsafe
.
Thanks for your patience on this one everybody! I've had a look through this now and left some thoughts on what direction we might want to take it in 🙇 |
src/bitflags_trait.rs
Outdated
@@ -0,0 +1,68 @@ | |||
use core as _core; | |||
|
|||
pub trait BitFlags<T>: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably make this an associated type, since an implementation of BitFlags
only corresponds to a single underlying integer type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the lines in this comment are wrong? do you mean perhaps empty and all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry, I mean making the trait look like:
pub trait BitFlags {
type Bits;
..
}
instead of:
pub trait BitFlags<T> {
..
}
I've implemented all the changes and left out Copy and Clone by now since they are not really needed for this PR, once this is merged I'll look into what's the minimum needed for the iterators PR. Two of the tests are failing but doesn't seem related to this, the 1.32 test seems to be related to unsupported features in const function because that function is not wrapped with |
@arturoc, we ran into a case where this would be useful for the atsamd-hal crate. I'm looking forward to seeing it get merged. Thanks for working on it. |
Hey @bradleyharden! 👋 Would you be happy to share some more details of your usecase? Would the trait in its current shape without any supertraits be sufficient for you? |
Looks like we just need a rebase on the current Thanks again for persisting with this @arturoc |
@@ -0,0 +1,46 @@ | |||
use core as _core; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use core as _core; |
This is only necessary for use in macros, so that types get resolved correctly. For the definition of the trait, you can just write Option
etc.
We may also want to add the functions added in #244 as trait methods (which would also eliminate the need for the supertraits for ops). I was worried a bit about the names conflicting with the respective |
Ah yes, inherent methods are resolved over methods from traits or deref, so we'd be safe adding them to the trait. We may also want to use some private supertrait to discourage callers from implementing this trait directly (we can't technically prevent it since expansion happens in their crates). That way we could mark the trait methods as #[doc(hidden)]
pub mod _private {
pub trait ProducedByMacro {}
}
pub trait BitFlags: ProducedByMacro { .. } |
Why would this private supertrait have to be generated by a macro? It could just be defined as a normal trait (as is the case for the |
fn bits(&self) -> Self::Bits; | ||
/// Convert from underlying bit representation, unless that | ||
/// representation contains bits that do not correspond to a flag. | ||
fn from_bits(bits: Self::Bits) -> _core::option::Option<Self> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn from_bits(bits: Self::Bits) -> _core::option::Option<Self> | |
fn from_bits(bits: Self::Bits) -> Option<Self> |
|
||
pub trait BitFlags { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub trait BitFlags { | |
/// A trait that is automatically implemented for all bitflags. | |
pub trait BitFlags { |
Ah the pattern would be almost the same as the usual The sealed trait (whether it's called |
jjust found a moment to rebase on current main, every test seems to be passing now without problem |
Thanks for working on this @arturoc! I'll go ahead and merge this in and send a follow-up that includes a few of the other things we were looking at. |
That's great! Btw, probably the generated example that serves as documentation is not necesary anymore since the trait documents everything already |
impl $crate::BitFlags for $BitFlags { | ||
type Bits = $T; | ||
|
||
fn empty() -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want to put inline on most methods here, to enable cross-crate inlining if called via a trait.
Adds a BitFlags trait that is implemented by every bitflags.
The trait includes documentation so it the current hack to document methods through an example could be removed
Closes #154