All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel@nongnu.org, peter.maydell@linaro.org,
	qemu-rust@nongnu.org, manos.pitsidianakis@linaro.org
Subject: Re: [RFC PATCH 1/6] rust: add "bits", a custom bitflags implementation
Date: Wed, 21 May 2025 09:29:06 +0100	[thread overview]
Message-ID: <aC2O0iNVZZMQUpjQ@redhat.com> (raw)
In-Reply-To: <20250521081845.496442-2-pbonzini@redhat.com>

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 <pbonzini@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

> +/// # Definition entry point
> +///
> +/// Define a struct with a single field of type $type.  Include public constants
> +/// for each element listed in braces.
> +///
> +/// The unnamed element at the end, if present, can be used to enlarge the set
> +/// of valid bits.  Bits that are valid but not listed are treated normally for
> +/// the purpose of arithmetic operations, and are printed with their hexadecimal
> +/// value.
> +///
> +/// The struct implements the following traits: [`BitAnd`](std::ops::BitAnd),
> +/// [`BitOr`](std::ops::BitOr), [`BitXor`](std::ops::BitXor),
> +/// [`Not`](std::ops::Not), [`Sub`](std::ops::Sub); [`Debug`](std::fmt::Debug),
> +/// [`Display`](std::fmt::Display), [`Binary`](std::fmt::Binary),
> +/// [`Octal`](std::fmt::Octal), [`LowerHex`](std::fmt::LowerHex),
> +/// [`UpperHex`](std::fmt::UpperHex); [`From`]`<type>`/[`Into`]`<type>` where
> +/// type is the type specified in the definition.

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	other threads:[~2025-05-21  8:29 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-21  8:18 [RFC PATCH 0/6] rust: make usage of bitmasks and bitfields nicer Paolo Bonzini
2025-05-21  8:18 ` [RFC PATCH 1/6] rust: add "bits", a custom bitflags implementation Paolo Bonzini
2025-05-21  8:29   ` Daniel P. Berrangé [this message]
2025-05-21  9:23     ` Manos Pitsidianakis
2025-05-21 15:05       ` Daniel P. Berrangé
2025-05-21  8:18 ` [RFC PATCH 2/6] rust: pl011: use the bits macro Paolo Bonzini
2025-05-21  8:18 ` [RFC PATCH 3/6] rust: qemu-api-macros: add from_bits and into_bits to #[derive(TryInto)] Paolo Bonzini
2025-05-21  8:18 ` [RFC PATCH 4/6] rust: subprojects: add bitfield-struct Paolo Bonzini
2025-05-21  8:18 ` [RFC PATCH 5/6] rust: pl011: switch from bilge to bitfield-struct Paolo Bonzini
2025-05-21  9:21   ` Manos Pitsidianakis
2025-05-21  9:40     ` Manos Pitsidianakis
2025-05-21 13:51     ` Paolo Bonzini
2025-05-21  9:50   ` Alex Bennée
2025-05-21 11:12     ` Manos Pitsidianakis
2025-05-21 13:54       ` Paolo Bonzini
2025-05-21  8:18 ` [RFC PATCH 6/6] rust: remove bilge crate Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aC2O0iNVZZMQUpjQ@redhat.com \
    --to=berrange@redhat.com \
    --cc=manos.pitsidianakis@linaro.org \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-rust@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.