Non-primitive representation #451

Open
opened 2025-07-23 10:34:41 -05:00 by Caellian · 3 comments
Caellian commented 2025-07-23 10:34:41 -05:00 (Migrated from github.com)

Though I can count number of times when this was needed on fingers of a single hand, it would be useful if bitflags could generate array backed bitflags.

Instead of storing up to 128 states directly in u128, one could store however many states they need in [u64; {N / 64}] type.

When explicitly defining bitflags this is uncommon, but it's possible when flags are dynamically generated from some data at compile time.

bitflags::bitflags! {
        struct UnknownSize {
                const A = 1 << 0;
                const B = 1 << 1;
                const C = 1 << 2;
               // ... 146 other flags ...
                const L = 1 << 150;
        }
}

Implementation of this would be different because it would require a loop over u64 array items.

Though I can count number of times when this was needed on fingers of a single hand, it would be useful if bitflags could generate array backed bitflags. Instead of storing up to 128 states directly in `u128`, one could store however many states they need in `[u64; {N / 64}]` type. When explicitly defining bitflags this is uncommon, but it's possible when flags are dynamically generated from some data at compile time. ```bitflags bitflags::bitflags! { struct UnknownSize { const A = 1 << 0; const B = 1 << 1; const C = 1 << 2; // ... 146 other flags ... const L = 1 << 150; } } ``` Implementation of this would be different because it would require a loop over `u64` array items.
KodrAus commented 2025-07-26 04:33:47 -05:00 (Migrated from github.com)

Hi @Caellian 👋

This is something you technically can do outside of the bitflags macro by defining your own newtype over [T; N] and implementing the Bits trait for it. bitflags itself doesn't define a big-int type like what you're describing that you can use, but it is possible to build what you're looking for. We've got an example based on [bool; N] here.

The blocker from using a custom bits type in the bitflags macro itself is the need for const-time bitwise operators, which are only stable on primitive integer types.

Hi @Caellian :wave: This is something you technically can do outside of the `bitflags` macro by defining your own newtype over `[T; N]` and implementing the `Bits` trait for it. `bitflags` itself doesn't define a big-int type like what you're describing that you can use, but it is possible to build what you're looking for. We've got an example based on `[bool; N]` [here](https://github.com/bitflags/bitflags/blob/main/examples/custom_bits_type.rs). The blocker from using a custom bits type in the `bitflags` macro itself is the need for `const`-time bitwise operators, which are only stable on primitive integer types.
Caellian commented 2025-08-28 15:44:17 -05:00 (Migrated from github.com)

Until const traits lands, I don't see why not just generate code that performs bitwise ops on array values directly. Crate would probably require a whole separate codegen logic for arrays, but it's nicer than having to implement Bits manually for large flags. Maybe I'm missing something.

BTW, this isn't a high priority issue for me, it's just a feature suggestion - I don't even think I'd use it that often ever. I mean, if you need >128 booleans on a type, bit twiddling is probably least of your worries. But it would be a nice feature completeness thing.

One tweak to my initial suggestion would be to actually make it explicit somehow that the flags are an array (e.g. FlagsName: [u64; N]) because people will default to not specifying them and expect values being parsed from TokenStream to find optimal backing type.

Until const traits lands, I don't see why not just generate code that performs bitwise ops on array values directly. Crate would probably require a whole separate codegen logic for arrays, but it's nicer than having to implement `Bits` manually for large flags. Maybe I'm missing something. BTW, this isn't a high priority issue for me, it's just a feature suggestion - I don't even think I'd use it ~~that often~~ ever. I mean, if you need >128 booleans on a type, bit twiddling is probably least of your worries. But it would be a nice feature completeness thing. One tweak to my initial suggestion would be to actually make it explicit somehow that the flags are an array (e.g. `FlagsName: [u64; N]`) because people will default to not specifying them and expect values being parsed from `TokenStream` to find optimal backing type.
KodrAus commented 2025-08-31 15:55:58 -05:00 (Migrated from github.com)

Crate would probably require a whole separate codegen logic for arrays

This is essentially the problem. The macros here are already complex, and since macro_rules macros don't have good tools for abstraction you end up needing to duplicate a lot of logic. Each knob we add to twiddle in code generation here not only blows out the complexity of the macros, it also blows out the potential for feature mismatch. macro_rules macros are good at expanding code, they're not good at making decisions about what code to expand.

> Crate would probably require a whole separate codegen logic for arrays This is essentially the problem. The macros here are already complex, and since `macro_rules` macros don't have good tools for abstraction you end up needing to duplicate a lot of logic. Each knob we add to twiddle in code generation here not only blows out the complexity of the macros, it also blows out the potential for feature mismatch. `macro_rules` macros are good at expanding code, they're not good at making decisions about what code to expand.
Sign in to join this conversation.
No labels
bug
good first issue
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-bitflags/bitflags#451
No description provided.