rust: qom: allow initializing interface vtables

Unlike regular classes, interface vtables can only be obtained via
object_class_dynamic_cast.  Provide a wrapper that allows accessing
the vtable and pass it to a ClassInitImpl implementation, for example
ClassInitImpl<ResettableClass>.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2025-01-17 11:23:14 +01:00
parent 201ef001dd
commit 688c674158
2 changed files with 44 additions and 2 deletions

View file

@ -66,8 +66,8 @@ pub use bindings::{Object, ObjectClass};
use crate::{
bindings::{
self, object_dynamic_cast, object_get_class, object_get_typename, object_new, object_ref,
object_unref, TypeInfo,
self, object_class_dynamic_cast, object_dynamic_cast, object_get_class,
object_get_typename, object_new, object_ref, object_unref, TypeInfo,
},
cell::bql_locked,
};
@ -263,6 +263,47 @@ pub unsafe trait ObjectType: Sized {
}
}
/// Trait exposed by all structs corresponding to QOM interfaces.
/// Unlike `ObjectType`, it is implemented on the class type (which provides
/// the vtable for the interfaces).
///
/// # Safety
///
/// `TYPE` must match the contents of the `TypeInfo` as found in the C code;
/// right now, interfaces can only be declared in C.
pub unsafe trait InterfaceType: Sized {
/// The name of the type, which can be passed to
/// `object_class_dynamic_cast()` to obtain the pointer to the vtable
/// for this interface.
const TYPE_NAME: &'static CStr;
/// Initialize the vtable for the interface; the generic argument `T` is the
/// type being initialized, while the generic argument `U` is the type that
/// lists the interface in its `TypeInfo`.
///
/// # Panics
///
/// Panic if the incoming argument if `T` does not implement the interface.
fn interface_init<
T: ObjectType + ClassInitImpl<Self> + ClassInitImpl<U::Class>,
U: ObjectType,
>(
klass: &mut U::Class,
) {
unsafe {
// SAFETY: upcasting to ObjectClass is always valid, and the
// return type is either NULL or the argument itself
let result: *mut Self = object_class_dynamic_cast(
(klass as *mut U::Class).cast(),
Self::TYPE_NAME.as_ptr(),
)
.cast();
<T as ClassInitImpl<Self>>::class_init(result.as_mut().unwrap())
}
}
}
/// This trait provides safe casting operations for QOM objects to raw pointers,
/// to be used for example for FFI. The trait can be applied to any kind of
/// reference or smart pointers, and enforces correctness through the [`IsA`]