-
Notifications
You must be signed in to change notification settings - Fork 17
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
Is there a more ergonomic way of accepting either a Bitflags<MyEnum> or just MyEnum? #29
Comments
The standard way would be to take |
Thanks. My intention is to wrap an unsafe FFI binded structure, and I was already using Option like this: pub fn new(/*...,*/ flags: Option<BitFlags<NcOptionFlag>>) -> Self {
MyStruct {
flags.unwrap_or(BitFlags::empty()).bits() as u64
}
} Which works well, and accepts either None, or Some(BitFlags). The only only "problem" was the ergonomics of providing a single flag. Now, when trying to make it work with the Into Trait I'm encountering a wall, which is that I no longer seem to be able to cast I think going this way is making it too complicated. Among the little information I've found regarding this trick, there's gtk-rs removing the usage of the Into trait for reasons I tend to agree with. But maybe I'm missing something and I'm open to keep trying. Do you have any more ideas? |
Thanks. My intention is to wrap an unsafe FFI binded structure, and I was already using Option like this:
```rust
pub fn new(/*...,*/ flags: Option<BitFlags<NcOptionFlag>>) -> Self {
MyStruct {
flags.unwrap_or(BitFlags::empty()).bits() as u64
}
}
```
Which works well, and accepts either None, or Some(BitFlags). The only only "problem" was the ergonomics of providing a single flag.
What's the motivation behind using `Option` here? Type-wise, I don't think there should be a distinction between `None` and `Some(BitFlags::empty())`.
Somewhat recently, support for `NcOptionFlag::empty()` landed on master too. Would that help here?
Now, when trying to make it work with the Into Trait I'm encountering a wall, which is that I no longer seem to be able to cast `as u64` nor using `u64::from(X)`, since I'm not the creator of either BitFlags or u64 ... So I can't crete the necessary `impl Into`...
Are you still using `.bits()`? AFAICS, this should work. Also, if you add `#[repr(u64)]` onto your `enum`, you won't need the cast ;)
I think going this way is making it too complicated. Among the little information I've found regarding this trick, there's [gtk-rs removing the usage of the Into trait](https://gtk-rs.org/blog/2019/06/22/new-release.html) for reasons I tend to agree with.
I agree with the type inference aspect, though it doesn't apply in case of bit flags. I might've misremembered the part about `Option`s somewhat...
As far as being explicit goes, I don't think there's much value in expressing this conversion, as it's merely type-level and compiles down to nothing. I think the trade-off should go in the direction of ergonomics in this case - the `Into` trick is a key part of what allows keeping a single flag a separate type from a set of them, and it's used [a fair amount of times](https://docs.rs/enumflags2/0.6.4/enumflags2/struct.BitFlags.html#method.intersects) in the crate itself.
|
Merely because since the original C API accepted null as a parameter for several fields, at first I wanted to remain as similar as possible by being able to pass None, but I surely prefer the most ergonomic option.
EDIT: I'm sorry I just realized it does work with the master version, which is more recent than the one published in crates.io
Ha! I completely overlooked that fact. You're right. I just did that and it now works for a single flag :D
|
BTW I just found out that it's imposible to derive BitFlags for an enum with a value of 0: The following code only works if I remove the BitFlags derive: #[repr(u32)]
#[derive(BitFlags, Copy, Clone, Debug, PartialEq)]
pub enum NcAlign {
Empty = 0 as u32,
One = 1 as u32,
Two = 2 as u32,
} It gives the error:
If that worked it would be the best solution for specifying an empty flag, since it would avoid the need of having to include the RawBitFlags trait into scope. Is there an unavoidable reason why that isn't allowed? |
The semantics of a flag that doesn't have exactly one bit set are unclear. In particular, should
This makes me realize that (side note: Also, what is the reason for the Is importing the trait something worth avoiding? I feel like this should be made opt-in with something like Thoughts? |
I'm not really sure of the trade-offs... I just miss a comfortable way of dealing with 0 / empty as part of the provided abstraction. I didn't imagine it would be so hairy. For my use-case I'd be the most happy with any solution that works without forcing the user to import anything more than the enum itself.
That looked promising but unfortunately it doesn't seem to compile, even in nightly.:
If you are able to make it const I'd say go for it, since I don't think it can have any disadvantages... And maybe then the previous code will work. 😄
Agree. And if you already intend to do some breaking changes, it's better to do them all together, better than getting stuck with an uglier API than it could have been once it's more used.
Well I'm sharing simplifications of the real code, the original code is more like:
I could use
Depends on the trade-offs I suppose. The only thing I'm sure of is that if importing the trait wasn't needed, we would never think of making it so. I haven't seen anything like what you propose. How would it work? Isn't it related to this pending issue? EDIT: I also found this procedural macro. |
> Is importing the trait something worth avoiding? I feel like this should be made opt-in with something like `#[bitflags(inherent_empty_all)]` - I checked, and inherent items shadow any trait impls, so this wouldn't introduce any usability issues.
Depends on the trade-offs I suppose. The only thing I'm sure of is that if importing the trait wasn't needed, we would never think of making it so.
I haven't seen anything like what you propose. How would it work? Isn't it related to [this pending issue](rust-lang/rfcs#2375)?
I haven't seen that RFC before. I'm just suggesting an attribute that
would make the macro generate an `impl YourEnum` block that creates
`empty` and `all`. Perhaps similar to `#[serde(transparent)]` syntax-wise.
"Inherent implementation" is the name for a non-trait `impl`
block, but from your response I can see that it isn't widely known...
However, now that I think about it, the only reason to not do this by
default would be backwards compatibility, so it's probably better to
enable it by default, together with the other changes.
I'll try to wrap up the next release sometime this week.
|
Ok now I understand. Well, I don't think I can be indicative of what is widely known since I'm learning Rust while I try to program what I need... and there's a lot I don't know yet. At the very least I've learned several very important things more in this thread. I'll let you to it then, and I'll be very happy to use the new release when it's ready. Thank you very much for your time. |
@joseluis Is this https://github.com/mokeyish/enum-flags a better implementation for your question?😅 |
thank you! the library looks really good, small and on point. |
…e first request of the KMIP spec 1.0 use case 11.1 to verify that it is serialized correctly. Update types to use the new "Transparent" Serde naming pattern where necessary from the krill-kmip-ttlv crate to ensure types are correctly serialized as TTLV structures or primitives in ambiguous newtype cases. Adds some missing #[non_exhaustive] attributes to enums which may gain additional member values in higher KMIP spec versions. Use new enum-flags crate for a simpler cleaner syntax than the enumflags2 crate (see: meithecatte/enumflags2#29 for context). Adds a test that works against a Kryptus KMIP HSM using TTLV over TLS.
I have a structure that accepts Bitflags for a flags field. And it works beautifully well except in the case of wanting to use just one flag:
Do you happen know of a more ergonomic way for the user to provide just one flag? Thank you
The text was updated successfully, but these errors were encountered: