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

Reply via email to