[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 31/41] rust: qom: add initial subset of methods on Object
From: |
Paolo Bonzini |
Subject: |
[PULL 31/41] rust: qom: add initial subset of methods on Object |
Date: |
Thu, 19 Dec 2024 09:32:18 +0100 |
Add an example of implementing instance methods and converting the
result back to a Rust type. In this case the returned types are a
string (actually a Cow<str>; but that's transparent as long as it derefs
to &str) and a QOM class.
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api/src/prelude.rs | 1 +
rust/qemu-api/src/qom.rs | 56 ++++++++++++++++++++++++++++++++++--
rust/qemu-api/tests/tests.rs | 12 ++++++++
3 files changed, 66 insertions(+), 3 deletions(-)
diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs
index a0a71fcd6bc..6f32deeb2ed 100644
--- a/rust/qemu-api/src/prelude.rs
+++ b/rust/qemu-api/src/prelude.rs
@@ -12,6 +12,7 @@
pub use crate::qom::ObjectCast;
pub use crate::qom::ObjectCastMut;
pub use crate::qom::ObjectDeref;
+pub use crate::qom::ObjectMethods;
pub use crate::qom::ObjectType;
pub use crate::qom_isa;
diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs
index 74ea5721f77..7d5fbef1e17 100644
--- a/rust/qemu-api/src/qom.rs
+++ b/rust/qemu-api/src/qom.rs
@@ -5,8 +5,8 @@
//! Bindings to access QOM functionality from Rust.
//!
//! The QEMU Object Model (QOM) provides inheritance and dynamic typing for
QEMU
-//! devices. This module makes QOM's features available in Rust through two
main
-//! mechanisms:
+//! devices. This module makes QOM's features available in Rust through three
+//! main mechanisms:
//!
//! * Automatic creation and registration of `TypeInfo` for classes that are
//! written in Rust, as well as mapping between Rust traits and QOM vtables.
@@ -15,6 +15,11 @@
//! trait and methods such as [`upcast`](ObjectCast::upcast) and
//! [`downcast`](ObjectCast::downcast).
//!
+//! * Automatic delegation of parent class methods to child classes. When a
+//! trait uses [`IsA`] as a bound, its contents become available to all child
+//! classes through blanket implementations. This works both for class
methods
+//! and for instance methods accessed through references or smart pointers.
+//!
//! # Structure of a class
//!
//! A leaf class only needs a struct holding instance state. The struct must
@@ -37,6 +42,16 @@
//! `ClassInitImpl<DeviceClass>`. This fills the vtable in the class struct;
//! the source for this is the `*Impl` trait; the associated consts and
//! functions if needed are wrapped to map C types into Rust types.
+//!
+//! * a trait for instance methods, for example `DeviceMethods`. This trait is
+//! automatically implemented for any reference or smart pointer to a device
+//! instance. It calls into the vtable provides access across all subclasses
+//! to methods defined for the class.
+//!
+//! * optionally, a trait for class methods, for example `DeviceClassMethods`.
+//! This provides access to class-wide functionality that doesn't depend on
+//! instance data. Like instance methods, these are automatically inherited
by
+//! child classes.
use std::{
ffi::CStr,
@@ -46,7 +61,7 @@
pub use bindings::{Object, ObjectClass};
-use crate::bindings::{self, object_dynamic_cast, TypeInfo};
+use crate::bindings::{self, object_dynamic_cast, object_get_class,
object_get_typename, TypeInfo};
/// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a
direct
/// or indirect parent of `Self`).
@@ -532,3 +547,38 @@ unsafe impl ObjectType for Object {
const TYPE_NAME: &'static CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_OBJECT) };
}
+
+/// Trait for methods exposed by the Object class. The methods can be
+/// called on all objects that have the trait `IsA<Object>`.
+///
+/// The trait should only be used through the blanket implementation,
+/// which guarantees safety via `IsA`
+pub trait ObjectMethods: ObjectDeref
+where
+ Self::Target: IsA<Object>,
+{
+ /// Return the name of the type of `self`
+ fn typename(&self) -> std::borrow::Cow<'_, str> {
+ let obj = self.upcast::<Object>();
+ // SAFETY: safety of this is the requirement for implementing IsA
+ // The result of the C API has static lifetime
+ unsafe {
+ let p = object_get_typename(obj.as_mut_ptr());
+ CStr::from_ptr(p).to_string_lossy()
+ }
+ }
+
+ fn get_class(&self) -> &'static <Self::Target as ObjectType>::Class {
+ let obj = self.upcast::<Object>();
+
+ // SAFETY: all objects can call object_get_class; the actual class
+ // type is guaranteed by the implementation of `ObjectType` and
+ // `ObjectImpl`.
+ let klass: &'static <Self::Target as ObjectType>::Class =
+ unsafe { &*object_get_class(obj.as_mut_ptr()).cast() };
+
+ klass
+ }
+}
+
+impl<R: ObjectDeref> ObjectMethods for R where R::Target: IsA<Object> {}
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 5d9f13b15d4..41ea4026b83 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -94,6 +94,18 @@ fn test_object_new() {
}
}
+#[test]
+/// Try invoking a method on an object.
+fn test_typename() {
+ init_qom();
+ let p: *mut DummyState = unsafe {
object_new(DummyState::TYPE_NAME.as_ptr()).cast() };
+ let p_ref: &DummyState = unsafe { &*p };
+ assert_eq!(p_ref.typename(), "dummy");
+ unsafe {
+ object_unref(p_ref.as_object_mut_ptr().cast::<c_void>());
+ }
+}
+
// a note on all "cast" tests: usually, especially for downcasts the desired
// class would be placed on the right, for example:
//
--
2.47.1
- [PULL 24/41] Constify all opaque Property pointers, (continued)
- [PULL 24/41] Constify all opaque Property pointers, Paolo Bonzini, 2024/12/19
- [PULL 20/41] include/hw/qdev-properties: Remove DEFINE_PROP_END_OF_LIST, Paolo Bonzini, 2024/12/19
- [PULL 26/41] rust: qom: add possibility of overriding unparent, Paolo Bonzini, 2024/12/19
- [PULL 25/41] rust: qom: put class_init together from multiple ClassInitImpl<>, Paolo Bonzini, 2024/12/19
- [PULL 27/41] rust: rename qemu-api modules to follow C code a bit more, Paolo Bonzini, 2024/12/19
- [PULL 28/41] rust: re-export C types from qemu-api submodules, Paolo Bonzini, 2024/12/19
- [PULL 29/41] rust: tests: allow writing more than one test, Paolo Bonzini, 2024/12/19
- [PULL 30/41] rust: qom: add casting functionality, Paolo Bonzini, 2024/12/19
- [PULL 32/41] rust: qemu-api: add a module to wrap functions and zero-sized closures, Paolo Bonzini, 2024/12/19
- [PULL 33/41] kvm: consistently return 0/-errno from kvm_convert_memory, Paolo Bonzini, 2024/12/19
- [PULL 31/41] rust: qom: add initial subset of methods on Object,
Paolo Bonzini <=
- [PULL 34/41] target/i386: Reset TSCs of parked vCPUs too on VM reset, Paolo Bonzini, 2024/12/19
- [PULL 35/41] rust: pl011: fix declaration of LineControl bits, Paolo Bonzini, 2024/12/19
- [PULL 36/41] rust: pl011: match break logic of C version, Paolo Bonzini, 2024/12/19
- [PULL 37/41] rust: pl011: always use reset() method on registers, Paolo Bonzini, 2024/12/19
- [PULL 38/41] rust: pl011: fix break errors and definition of Data struct, Paolo Bonzini, 2024/12/19
- [PULL 40/41] rust: pl011: fix migration stream, Paolo Bonzini, 2024/12/19
- [PULL 39/41] rust: pl011: extend registers to 32 bits, Paolo Bonzini, 2024/12/19
- [PULL 41/41] rust: pl011: simplify handling of the FIFO enabled bit in LCR, Paolo Bonzini, 2024/12/19
- Re: [PULL 00/41] Rust, qdev, target/i386 changes for 2024-12-19, Richard Henderson, 2024/12/19