On Wed, May 21, 2025 at 11:29 AM Daniel P. Berrangé <berra...@redhat.com> wrote: > > On Wed, May 21, 2025 at 10:18:40AM +0200, Paolo Bonzini wrote: > > One common thing that device emulation does is manipulate bitmasks, for > > example > > to check whether two bitmaps have common bits. One example in the pl011 > > crate > > is the checks for pending interrupts, where an interrupt cause corresponds > > to > > at least one interrupt source from a fixed set. > > > > Unfortunately, this is one case where Rust *can* provide some kind of > > abstraction but it does so with a rather Perl-ish There Is More Way To > > Do It. It is not something where a crate like "bilge" helps, because > > it only covers the packing of bits in a structure; operations like "are > > all bits of Y set in X" almost never make sense for bit-packed structs; > > you need something else, there are several crates that do it and of course > > we're going to roll our own. > > > > In particular I examined three: > > > > - bitmask (https://docs.rs/bitmask/0.5.0/bitmask/) does not support const > > at all. This is a showstopper because one of the ugly things in the > > current pl011 code is the ugliness of code that defines interrupt masks > > at compile time: > > > > pub const E: Self = Self(Self::OE.0 | Self::BE.0 | Self::PE.0 | > > Self::FE.0); > > > > or even worse: > > > > const IRQMASK: [u32; 6] = [ > > Interrupt::E.0 | Interrupt::MS.0 | Interrupt::RT.0 | Interrupt::TX.0 > > | Interrupt::RX.0, > > ... > > } > > > > You would have to use roughly the same code---"bitmask" only helps with > > defining the struct. > > > > - bitmask_enum (https://docs.rs/bitmask-enum/2.2.5/bitmask_enum/) does not > > have a good separation of "valid" and "invalid" bits, so for example "!x" > > will invert all 16 bits if you choose u16 as the representation -- even if > > you only defined 10 bits. This makes it easier to introduce subtle bugs > > in comparisons. > > > > - bitflags (https://docs.rs/bitflags/2.6.0/bitflags/) is generally the most > > used such crate and is the one that I took most inspiration from with > > respect to the syntax. It's a pretty sophisticated implementation, > > with a lot of bells and whistles such as an implementation of "Iter" > > that returns the bits one at a time. > > > > The main thing that all of them lack, however, is a way to simplify the > > ugly definitions like the above. "bitflags" includes const methods that > > perform AND/OR/XOR of masks (these are necessary because Rust operator > > overloading does not support const yet, and therefore overloaded operators > > cannot be used in the definition of a "static" variable), but they become > > even more verbose and unmanageable, like > > > > > > Interrupt::E.union(Interrupt::MS).union(Interrupt::RT).union(Interrupt::TX).union(Interrupt::RX) > > > > This was the main reason to create "bits", which allows something like > > > > bits!(Interrupt: E | MS | RT | TX | RX) > > > > and expands it 1) add "Interrupt::" in front of all identifiers 2) convert > > operators to the wordy const functions like "union". It supports boolean > > operators "&", "|", "^", "!" and parentheses, with a relatively simple > > recursive descent parser that's implemented in qemu_api_macros. > > > > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> > > --- > > rust/Cargo.lock | 7 + > > rust/Cargo.toml | 1 + > > rust/bits/Cargo.toml | 19 ++ > > rust/bits/meson.build | 12 + > > rust/bits/src/lib.rs | 441 +++++++++++++++++++++++++++++++ > > rust/meson.build | 1 + > > rust/qemu-api-macros/src/bits.rs | 227 ++++++++++++++++ > > rust/qemu-api-macros/src/lib.rs | 12 + > > 8 files changed, 720 insertions(+) > > create mode 100644 rust/bits/Cargo.toml > > create mode 100644 rust/bits/meson.build > > create mode 100644 rust/bits/src/lib.rs > > create mode 100644 rust/qemu-api-macros/src/bits.rs > > > diff --git a/rust/bits/src/lib.rs b/rust/bits/src/lib.rs > > new file mode 100644 > > index 00000000000..d80a6263f1e > > --- /dev/null > > +++ b/rust/bits/src/lib.rs > > @@ -0,0 +1,441 @@ > > This (and other new .rs files) needs SPDX-License-Identifier
We should probably lint for this in .rs files. -- Manos Pitsidianakis Emulation and Virtualization Engineer at Linaro Ltd