On Wed, May 21, 2025 at 12:23:02PM +0300, Manos Pitsidianakis wrote:
> 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.

Strengthened from a recommendation to a mandate in:

https://lists.nongnu.org/archive/html/qemu-devel/2025-05/msg04968.html


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


Reply via email to