All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhao Liu <zhao1.liu@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel <qemu-devel@nongnu.org>,
	qemu-rust@nongnu.org, Junjie Mao <junjie.mao@hotmail.com>
Subject: Re: [PATCH 24/26] rust: qom: move device_id to PL011 class side
Date: Wed, 18 Dec 2024 22:46:33 +0800	[thread overview]
Message-ID: <Z2LgScN1f/C3UdcD@intel.com> (raw)
In-Reply-To: <d01798d5-1c93-48f7-bb78-d4602a13baac@redhat.com>

On Wed, Dec 18, 2024 at 11:26:35AM +0100, Paolo Bonzini wrote:
> Date: Wed, 18 Dec 2024 11:26:35 +0100
> From: Paolo Bonzini <pbonzini@redhat.com>
> Subject: Re: [PATCH 24/26] rust: qom: move device_id to PL011 class side
> 
> On 12/18/24 08:14, Paolo Bonzini wrote:
> >     Moving on to another topic, about the gap (or question :-)) where a
> >     child class inherits the ClassInitImpl trait from the parent, please see
> >     my test case example below: Doing something similar to SysBusDevice and
> >     DeviceState using a generic T outside of the QOM library would violate
> >     the orphan rule.
> > 
> > Ugh, you're right. Maybe ClassInitImpl should just be merged into
> > ObjectImpl etc. as a default method implementation. I will check.
> 
> Ok, I think we can make it mostly a documentation issue:
> 
> diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs
> index 2b472915707..ee95eda0447 100644
> --- a/rust/qemu-api/src/qom.rs
> +++ b/rust/qemu-api/src/qom.rs
> @@ -451,13 +451,14 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
>  /// Each struct will implement this trait with `T` equal to each
>  /// superclass.  For example, a device should implement at least
>  /// `ClassInitImpl<`[`DeviceClass`](crate::qdev::DeviceClass)`>` and
> -/// `ClassInitImpl<`[`ObjectClass`]`>`.
> +/// `ClassInitImpl<`[`ObjectClass`]`>`.  Such implementations are
> +/// made in one of two ways.
>  ///
> -/// Fortunately, this is almost never necessary.  Instead, the Rust
> -/// implementation of methods will usually come from a trait like
> -/// [`ObjectImpl`] or [`DeviceImpl`](crate::qdev::DeviceImpl).
> -/// `ClassInitImpl` then can be provided by blanket implementations
> -/// that operate on all implementors of the `*Impl`* trait.  For example:
> +/// For most superclasses, `ClassInitImpl` is provided by the `qemu-api`
> +/// crate itself.  The Rust implementation of methods will come from a
> +/// trait like [`ObjectImpl`] or [`DeviceImpl`](crate::qdev::DeviceImpl),
> +/// and `ClassInitImpl` is provided by blanket implementations that
> +/// operate on all implementors of the `*Impl`* trait.  For example:
>  ///
>  /// ```ignore
>  /// impl<T> ClassInitImpl<DeviceClass> for T
> @@ -469,11 +470,37 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
>  /// after initializing the `DeviceClass` part of the class struct,
>  /// the parent [`ObjectClass`] is initialized as well.
>  ///
> -/// The only case in which a manual implementation of the trait is needed
> -/// is for interfaces (note that there is no Rust example yet for using
> -/// interfaces).  In this case, unlike the C case, the Rust class _has_
> -/// to define its own class struct `FooClass` to go together with
> -/// `ClassInitImpl<FooClass>`.
> +/// In some other cases, manual implementation of the trait is needed.
> +/// These are the following:
> +///
> +/// * for classes that implement interfaces, the Rust code _has_
> +///   to define its own class struct `FooClass` and implement
> +///   `ClassInitImpl<FooClass>`.  `ClassInitImpl<FooClass>`'s
> +///   `class_init` method will then forward to multiple other
> +///   `class_init`s, for the interfaces as well as the superclass.
> +///   (Note that there is no Rust example yet for using
> +///   interfaces).
> +///
> +/// * for classes implemented outside the ``qemu-api`` crate, it's
> +///   not possible to add blanket implementations like the above one,
> +///   due to orphan rules.  In that case, the easiest solution is to
> +///   implement `ClassInitImpl<YourSuperclass>` for each subclass,
> +///   and not have a `YourSuperclassImpl` trait at all:
> +///
> +///   ```ignore
> +///   impl ClassInitImpl<YourSuperclass> for YourSubclass {
> +///       fn class_init(klass: &mut YourSuperclass) {
> +///           klass.some_method = Some(Self::some_method);
> +///           <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class);
> +///       }
> +///   }
> +///   ```

BTW, maybe we could also squash my previous example in test? :-)

> +///
> +///   While this method incurs a small amount of code duplication,
> +///   it is generally limited to the recursive call on the last line.
> +///   This is because classes defined in Rust do not need the same
> +///   glue code that is needed when the classes are defined in C code.

Now I understand this advantage.

> +///   You may consider using a macro if you have many subclasses.

Yes, a custom macro is enough!

>  pub trait ClassInitImpl<T> {
>      /// Initialize `klass` to point to the virtual method implementations
>      /// for `Self`.  On entry, the virtual method pointers are set to

All the above changes look good to me!

> Optionally, something like this can be squashed in this patch, but I
> do not think it's worth the savings of... 3 lines of code:
> 
> diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
> index 41220c99a83..cbd3abb96ec 100644
> --- a/rust/hw/char/pl011/src/device.rs
> +++ b/rust/hw/char/pl011/src/device.rs
> @@ -46,11 +46,6 @@ fn index(&self, idx: hwaddr) -> &Self::Output {
>      }
>  }
> -impl DeviceId {
> -    const ARM: Self = Self(&[0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]);
> -    const LUMINARY: Self = Self(&[0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1]);
> -}
> -
>  #[repr(C)]
>  #[derive(Debug, qemu_api_macros::Object, qemu_api_macros::offsets)]
>  /// PL011 Device Model in QEMU
> @@ -112,7 +107,8 @@ unsafe impl ObjectType for PL011State {
>  impl ClassInitImpl<PL011Class> for PL011State {
>      fn class_init(klass: &mut PL011Class) {
> -        klass.device_id = DeviceId::ARM;
> +        klass.device_id = DeviceId(&[0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]);
> +
>          <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class);
>      }
>  }
> @@ -628,7 +624,8 @@ pub struct PL011Luminary {
>  impl ClassInitImpl<PL011Class> for PL011Luminary {
>      fn class_init(klass: &mut PL011Class) {
> -        klass.device_id = DeviceId::LUMINARY;
> +        klass.device_id = DeviceId(&[0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1]);
> +
>          <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class);
>      }
>  }

Still fine for me. :-)

Regards,
Zhao




  reply	other threads:[~2024-12-18 14:32 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-09 12:36 [PATCH 00/26] rust: bundle of prerequisites for HPET implementation Paolo Bonzini
2024-12-09 12:36 ` [PATCH 01/26] bql: check that the BQL is not dropped within marked sections Paolo Bonzini
2024-12-09 12:36 ` [PATCH 02/26] rust: cell: add BQL-enforcing Cell variant Paolo Bonzini
2024-12-09 12:36 ` [PATCH 03/26] rust: cell: add BQL-enforcing RefCell variant Paolo Bonzini
2024-12-09 12:36 ` [PATCH 04/26] rust: define prelude Paolo Bonzini
2024-12-10  7:19   ` Zhao Liu
2024-12-09 12:36 ` [PATCH 05/26] rust: add bindings for interrupt sources Paolo Bonzini
2024-12-10  7:25   ` Zhao Liu
2024-12-09 12:36 ` [PATCH 06/26] rust: add a bit operation module Paolo Bonzini
2024-12-10  8:13   ` Zhao Liu
2024-12-10  9:30     ` Paolo Bonzini
2024-12-09 12:36 ` [PATCH 07/26] rust: qom: add default definitions for ObjectImpl Paolo Bonzini
2024-12-10  8:21   ` Zhao Liu
2024-12-09 12:36 ` [PATCH 08/26] rust: qom: rename Class trait to ClassInitImpl Paolo Bonzini
2024-12-10  8:24   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 09/26] rust: qom: convert type_info! macro to an associated const Paolo Bonzini
2024-12-10  8:30   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 10/26] rust: qom: move ClassInitImpl to the instance side Paolo Bonzini
2024-12-10 16:03   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 11/26] rust: qdev: move device_class_init! body to generic function, ClassInitImpl implementation to macro Paolo Bonzini
2024-12-10 16:06   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 12/26] rust: qdev: move bridge for realize and reset functions out of pl011 Paolo Bonzini
2024-12-10 16:07   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 13/26] rust: qom: automatically use Drop trait to implement instance_finalize Paolo Bonzini
2024-12-10 16:16   ` Zhao Liu
2024-12-11 12:42     ` Paolo Bonzini
2024-12-11 15:37       ` Zhao Liu
2024-12-09 12:37 ` [PATCH 14/26] rust: qom: move bridge for TypeInfo functions out of pl011 Paolo Bonzini
2024-12-10 15:50   ` Zhao Liu
2024-12-10 17:38     ` Paolo Bonzini
2024-12-11  7:59       ` Zhao Liu
2024-12-11  9:11         ` Paolo Bonzini
2024-12-11 16:56           ` Zhao Liu
2024-12-12  9:24             ` Paolo Bonzini
2024-12-13  8:53               ` Zhao Liu
2024-12-10 16:02   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 15/26] rust: qom: split ObjectType from ObjectImpl trait Paolo Bonzini
2024-12-11  8:41   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 16/26] rust: qom: change the parent type to an associated type Paolo Bonzini
2024-12-11  8:47   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 17/26] rust: qom: put class_init together from multiple ClassInitImpl<> Paolo Bonzini
2024-12-12  9:15   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 18/26] rust: qom: add possibility of overriding unparent Paolo Bonzini
2024-12-12  9:40   ` Zhao Liu
2024-12-12 11:15     ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 19/26] rust: rename qemu-api modules to follow C code a bit more Paolo Bonzini
2024-12-12  9:52   ` Zhao Liu
2024-12-12 11:28     ` Paolo Bonzini
2024-12-13  9:19       ` Zhao Liu
2024-12-13 11:24         ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 20/26] rust: re-export C types from qemu-api submodules Paolo Bonzini
2024-12-12  9:55   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 21/26] rust: tests: allow writing more than one test Paolo Bonzini
2024-12-12 10:04   ` Zhao Liu
2024-12-16 15:07     ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 22/26] rust: qom: add casting functionality Paolo Bonzini
2024-12-16 12:53   ` Zhao Liu
2024-12-16 15:17     ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 23/26] rust: qom: add initial subset of methods on Object Paolo Bonzini
2024-12-16 15:18   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 24/26] rust: qom: move device_id to PL011 class side Paolo Bonzini
2024-12-17  3:58   ` Zhao Liu
2024-12-17 16:50     ` Paolo Bonzini
2024-12-18  6:57       ` Zhao Liu
2024-12-18  7:14         ` Paolo Bonzini
2024-12-18 10:26           ` Paolo Bonzini
2024-12-18 14:46             ` Zhao Liu [this message]
2024-12-18 16:01               ` Paolo Bonzini
2024-12-18 14:30           ` Zhao Liu
2024-12-18 14:47   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 25/26] rust: qemu-api: add a module to wrap functions and zero-sized closures Paolo Bonzini
2024-12-17 15:03   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 26/26] rust: callbacks: allow passing optional callbacks as () Paolo Bonzini
2024-12-17 16:13   ` Zhao Liu
2024-12-17 16:40     ` Paolo Bonzini
2024-12-18  7:09       ` Zhao Liu
2024-12-18  7:32         ` Paolo Bonzini
2024-12-18 15:09           ` Zhao Liu
2024-12-09 16:24 ` [PATCH 00/26] rust: bundle of prerequisites for HPET implementation Philippe Mathieu-Daudé
2024-12-09 17:23   ` Paolo Bonzini
2024-12-10  2:38     ` Zhao Liu

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=Z2LgScN1f/C3UdcD@intel.com \
    --to=zhao1.liu@intel.com \
    --cc=junjie.mao@hotmail.com \
    --cc=pbonzini@redhat.com \
    --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.