Message ID | 20241209123717.99077-19-pbonzini@redhat.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | rust: bundle of prerequisites for HPET implementation | expand |
On Mon, Dec 09, 2024 at 01:37:09PM +0100, Paolo Bonzini wrote: > Date: Mon, 9 Dec 2024 13:37:09 +0100 > From: Paolo Bonzini <pbonzini@redhat.com> > Subject: [PATCH 18/26] rust: qom: add possibility of overriding unparent > X-Mailer: git-send-email 2.47.1 > > Add a blanket definition of ClassInitImpl<ObjectClass> that thunks > ObjectImpl::UNPARENT and overrides it in ObjectClass if it is not > None. > > ClassInitImpl<DeviceClass> can now call its superclass's ClassInitImpl, > so that the C and Rust hierarchies match more closely. > > This is mostly done as an example of implementing the metaclass > hierarchy under ClassInitImpl. > > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > --- > rust/qemu-api/src/definitions.rs | 44 ++++++++++++++++++++++++++++--- > rust/qemu-api/src/device_class.rs | 6 +++-- > 2 files changed, 45 insertions(+), 5 deletions(-) Reviewed-by: Zhao Liu <zhao1.liu@intel.com> (with an additional comment below...) > diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs > index 2429b9f53f0..958ea34decc 100644 > --- a/rust/qemu-api/src/definitions.rs > +++ b/rust/qemu-api/src/definitions.rs > @@ -6,7 +6,7 @@ > > use std::{ffi::CStr, os::raw::c_void}; > > -use crate::bindings::{Object, ObjectClass, TypeInfo}; > +use crate::bindings::{self, Object, ObjectClass, TypeInfo}; > > unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { > // SAFETY: obj is an instance of T, since rust_instance_init<T> > @@ -115,6 +115,9 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> { > class_data: core::ptr::null_mut(), > interfaces: core::ptr::null_mut(), > }; > + > + // methods on ObjectClass > + const UNPARENT: Option<fn(&mut Self)> = None; > } Will we change `&mut Self` to an immutable reference in the future? IIUC, the parent on the C side also has a pointer to current object.
On 12/12/24 10:40, Zhao Liu wrote: > On Mon, Dec 09, 2024 at 01:37:09PM +0100, Paolo Bonzini wrote: >> Date: Mon, 9 Dec 2024 13:37:09 +0100 >> From: Paolo Bonzini <pbonzini@redhat.com> >> Subject: [PATCH 18/26] rust: qom: add possibility of overriding unparent >> X-Mailer: git-send-email 2.47.1 >> >> Add a blanket definition of ClassInitImpl<ObjectClass> that thunks >> ObjectImpl::UNPARENT and overrides it in ObjectClass if it is not >> None. >> >> ClassInitImpl<DeviceClass> can now call its superclass's ClassInitImpl, >> so that the C and Rust hierarchies match more closely. >> >> This is mostly done as an example of implementing the metaclass >> hierarchy under ClassInitImpl. >> >> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> >> --- >> rust/qemu-api/src/definitions.rs | 44 ++++++++++++++++++++++++++++--- >> rust/qemu-api/src/device_class.rs | 6 +++-- >> 2 files changed, 45 insertions(+), 5 deletions(-) > > Reviewed-by: Zhao Liu <zhao1.liu@intel.com> > > (with an additional comment below...) > >> diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs >> index 2429b9f53f0..958ea34decc 100644 >> --- a/rust/qemu-api/src/definitions.rs >> +++ b/rust/qemu-api/src/definitions.rs >> @@ -6,7 +6,7 @@ >> >> use std::{ffi::CStr, os::raw::c_void}; >> >> -use crate::bindings::{Object, ObjectClass, TypeInfo}; >> +use crate::bindings::{self, Object, ObjectClass, TypeInfo}; >> >> unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { >> // SAFETY: obj is an instance of T, since rust_instance_init<T> >> @@ -115,6 +115,9 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> { >> class_data: core::ptr::null_mut(), >> interfaces: core::ptr::null_mut(), >> }; >> + >> + // methods on ObjectClass >> + const UNPARENT: Option<fn(&mut Self)> = None; >> } > > Will we change `&mut Self` to an immutable reference in the future? Good point, let's do it now since anyway UNPARENT is unused. Paolo
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs index 2429b9f53f0..958ea34decc 100644 --- a/rust/qemu-api/src/definitions.rs +++ b/rust/qemu-api/src/definitions.rs @@ -6,7 +6,7 @@ use std::{ffi::CStr, os::raw::c_void}; -use crate::bindings::{Object, ObjectClass, TypeInfo}; +use crate::bindings::{self, Object, ObjectClass, TypeInfo}; unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { // SAFETY: obj is an instance of T, since rust_instance_init<T> @@ -115,6 +115,9 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> { class_data: core::ptr::null_mut(), interfaces: core::ptr::null_mut(), }; + + // methods on ObjectClass + const UNPARENT: Option<fn(&mut Self)> = None; } /// Internal trait used to automatically fill in a class struct. @@ -128,7 +131,8 @@ 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::bindings::DeviceClass)`>`. +/// `ClassInitImpl<`[`DeviceClass`](crate::bindings::DeviceClass)`>` and +/// `ClassInitImpl<`[`ObjectClass`](crate::bindings::ObjectClass)`>`. /// /// Fortunately, this is almost never necessary. Instead, the Rust /// implementation of methods will usually come from a trait like @@ -139,9 +143,13 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> { /// ```ignore /// impl<T> ClassInitImpl<DeviceClass> for T /// where -/// T: DeviceImpl, +/// T: ClassInitImpl<ObjectClass> + DeviceImpl, /// ``` /// +/// The bound on `ClassInitImpl<ObjectClass>` is needed so that, +/// 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_ @@ -203,3 +211,33 @@ extern "C" fn ctor_fn() { } }; } + +/// # Safety +/// +/// We expect the FFI user of this function to pass a valid pointer that +/// can be downcasted to type `T`. We also expect the device is +/// readable/writeable from one thread at any time. +unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut Object) { + unsafe { + assert!(!dev.is_null()); + let mut state = core::ptr::NonNull::new_unchecked(dev.cast::<T>()); + T::UNPARENT.unwrap()(state.as_mut()); + } +} + +impl<T> ClassInitImpl<ObjectClass> for T +where + T: ObjectImpl, +{ + fn class_init(oc: &mut ObjectClass) { + if <T as ObjectImpl>::UNPARENT.is_some() { + oc.unparent = Some(rust_unparent_fn::<T>); + } + } +} + +unsafe impl ObjectType for Object { + type Class = ObjectClass; + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_OBJECT) }; +} diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs index ee9ae7eeb74..285dfe582c7 100644 --- a/rust/qemu-api/src/device_class.rs +++ b/rust/qemu-api/src/device_class.rs @@ -5,7 +5,7 @@ use std::ffi::CStr; use crate::{ - bindings::{self, DeviceClass, DeviceState, Error, Property, VMStateDescription}, + bindings::{self, DeviceClass, DeviceState, Error, ObjectClass, Property, VMStateDescription}, definitions::ClassInitImpl, prelude::*, zeroable::Zeroable, @@ -69,7 +69,7 @@ fn vmsd() -> Option<&'static VMStateDescription> { impl<T> ClassInitImpl<DeviceClass> for T where - T: DeviceImpl, + T: ClassInitImpl<ObjectClass> + DeviceImpl, { fn class_init(dc: &mut DeviceClass) { if <T as DeviceImpl>::REALIZE.is_some() { @@ -86,6 +86,8 @@ fn class_init(dc: &mut DeviceClass) { unsafe { bindings::device_class_set_props(dc, <T as DeviceImpl>::properties().as_ptr()); } + + <T as ClassInitImpl<ObjectClass>>::class_init(&mut dc.parent_class); } }
Add a blanket definition of ClassInitImpl<ObjectClass> that thunks ObjectImpl::UNPARENT and overrides it in ObjectClass if it is not None. ClassInitImpl<DeviceClass> can now call its superclass's ClassInitImpl, so that the C and Rust hierarchies match more closely. This is mostly done as an example of implementing the metaclass hierarchy under ClassInitImpl. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> --- rust/qemu-api/src/definitions.rs | 44 ++++++++++++++++++++++++++++--- rust/qemu-api/src/device_class.rs | 6 +++-- 2 files changed, 45 insertions(+), 5 deletions(-)