mbox series

[00/15] rust: prepare for splitting crates

Message ID 20250221170342.63591-1-pbonzini@redhat.com (mailing list archive)
Headers show
Series rust: prepare for splitting crates | expand

Message

Paolo Bonzini Feb. 21, 2025, 5:03 p.m. UTC
This series is logically split in two parts.  The first one is more
strictly tied to the objective of splitting qemu_api into multiple crates,
as it breaks the QOM bindings free of the constraints imposed by Rust
orphan rules.  The second one instead completes another task that was on
my todo list, namely ensuring that rustc sees the possible changes that
C functions can make when a shared reference &bindings::Foo is passed
via *mut bindings::Foo.

More in detail, patches 1-5 redo the QOM class init mechanism so that
it does not rely on the ClassInitImpl trait.  While ClassInitImpl is
very nice in theory, it practice it does not play well with classes
defined outside qemu_api (or more precisely, outside the crate that
defines ClassInitImpl itself).  This is because ClassInitImpl relies on
a blanket implementation such as

    impl<T> ClassInitImpl<ObjectClass> for T
    where
        T: ObjectImpl

and this is only possible inside the crate that defines ClassInitImpl.
With these patches the class_init methods move from ClassInitImpl<Class>
to the Class struct itself.  More precisely, before the series you
have

    <T as ClassInitImpl<ObjectClass>>::class_init

and afterwards

    ObjectClass::class_init::<T>

which is assigned to the CLASS_INIT associated const of ObjectImpl.
The problem is that even if CLASS_INIT is always defined the same
way, i.e.

    const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;

there isn't a way to tell the compiler that the above is valid *in the
definition of ObjectImpl*.  Therefore the above line has to be duplicated
in all subclasses; this however is a small issue and in the future it
could be handled by #[derive(Object)].

Patches 6-15 instead introduce a third generic type in qemu_api::cell,
Opaque<T>.  This type is similar to a same-named type in Linux; it is
basically a "disable all undefined behavior" switch for the Rust compiler
and it helps maintaining safety at the Rust/C boundary, complementing
the existing BqlCell and BqlRefCell types.

Apart from making things more formally correct, this makes it possible
to implement methods on a struct that is distinct from the one produced
by bindgen.  This has a couple of advantages:

- you do not have to disable the Copy trait on structs where you want
  to add a Drop trait.  This was already a problem for the Timer struct.

- whether Send and Sync are implemented is entirely a decision of the
  place that implements the wrapper.  Previously, a struct with no
  pointers for example would have been always both Send and Sync,
  whereas now that can be adjusted depending on the actual
  thread-safety of the Rust methods.

- more pertinent to the "multiple crates" plan, you do not have to put
  the methods in the same crate as the bindgen-generated bindings.inc.rs.

It also makes Debug output a bit less unwieldy, and in the future one
might want to add specialized implementations of Display and Debug that
are both useful and readable.

Paolo

Paolo Bonzini (15):
  rust: add IsA bounds to QOM implementation traits
  rust: add SysBusDeviceImpl
  rust: qom: add ObjectImpl::CLASS_INIT
  rust: pl011, qemu_api tests: do not use ClassInitImpl
  rust: qom: get rid of ClassInitImpl
  rust: cell: add wrapper for FFI types
  rust: qemu_api_macros: add Wrapper derive macro
  rust: timer: wrap QEMUTimer with Opaque<>
  rust: irq: wrap IRQState with Opaque<>
  rust: qom: wrap Object with Opaque<>
  rust: qdev: wrap Clock and DeviceState with Opaque<>
  rust: sysbus: wrap SysBusDevice with Opaque<>
  rust: memory: wrap MemoryRegion with Opaque<>
  rust: chardev: wrap Chardev with Opaque<>
  rust: bindings: remove more unnecessary Send/Sync impls

 docs/devel/rust.rst              |  36 +++--
 meson.build                      |   7 -
 rust/hw/char/pl011/src/device.rs |  44 +++---
 rust/hw/timer/hpet/src/hpet.rs   |   7 +-
 rust/qemu-api-macros/src/lib.rs  |  82 +++++++++++-
 rust/qemu-api/meson.build        |   7 +-
 rust/qemu-api/src/bindings.rs    |  26 +---
 rust/qemu-api/src/cell.rs        | 222 ++++++++++++++++++++++++++++++-
 rust/qemu-api/src/chardev.rs     |   8 +-
 rust/qemu-api/src/irq.rs         |  15 ++-
 rust/qemu-api/src/memory.rs      |  32 ++---
 rust/qemu-api/src/qdev.rs        | 115 ++++++++++------
 rust/qemu-api/src/qom.rs         | 203 ++++++++++++++--------------
 rust/qemu-api/src/sysbus.rs      |  45 ++++---
 rust/qemu-api/src/timer.rs       |  24 +++-
 rust/qemu-api/src/vmstate.rs     |   2 +-
 rust/qemu-api/tests/tests.rs     |  32 ++---
 17 files changed, 620 insertions(+), 287 deletions(-)