mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00
rust: qom: add initial subset of methods on Object
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>
This commit is contained in:
parent
f50cd85c84
commit
ba3b81f3b6
3 changed files with 66 additions and 3 deletions
|
@ -12,6 +12,7 @@ pub use crate::qom::Object;
|
||||||
pub use crate::qom::ObjectCast;
|
pub use crate::qom::ObjectCast;
|
||||||
pub use crate::qom::ObjectCastMut;
|
pub use crate::qom::ObjectCastMut;
|
||||||
pub use crate::qom::ObjectDeref;
|
pub use crate::qom::ObjectDeref;
|
||||||
|
pub use crate::qom::ObjectMethods;
|
||||||
pub use crate::qom::ObjectType;
|
pub use crate::qom::ObjectType;
|
||||||
|
|
||||||
pub use crate::qom_isa;
|
pub use crate::qom_isa;
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
//! Bindings to access QOM functionality from Rust.
|
//! Bindings to access QOM functionality from Rust.
|
||||||
//!
|
//!
|
||||||
//! The QEMU Object Model (QOM) provides inheritance and dynamic typing for QEMU
|
//! 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
|
//! devices. This module makes QOM's features available in Rust through three
|
||||||
//! mechanisms:
|
//! main mechanisms:
|
||||||
//!
|
//!
|
||||||
//! * Automatic creation and registration of `TypeInfo` for classes that are
|
//! * Automatic creation and registration of `TypeInfo` for classes that are
|
||||||
//! written in Rust, as well as mapping between Rust traits and QOM vtables.
|
//! 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
|
//! trait and methods such as [`upcast`](ObjectCast::upcast) and
|
||||||
//! [`downcast`](ObjectCast::downcast).
|
//! [`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
|
//! # Structure of a class
|
||||||
//!
|
//!
|
||||||
//! A leaf class only needs a struct holding instance state. The struct must
|
//! 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;
|
//! `ClassInitImpl<DeviceClass>`. This fills the vtable in the class struct;
|
||||||
//! the source for this is the `*Impl` trait; the associated consts and
|
//! the source for this is the `*Impl` trait; the associated consts and
|
||||||
//! functions if needed are wrapped to map C types into Rust types.
|
//! 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::{
|
use std::{
|
||||||
ffi::CStr,
|
ffi::CStr,
|
||||||
|
@ -46,7 +61,7 @@ use std::{
|
||||||
|
|
||||||
pub use bindings::{Object, ObjectClass};
|
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
|
/// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct
|
||||||
/// or indirect parent of `Self`).
|
/// or indirect parent of `Self`).
|
||||||
|
@ -532,3 +547,38 @@ unsafe impl ObjectType for Object {
|
||||||
const TYPE_NAME: &'static CStr =
|
const TYPE_NAME: &'static CStr =
|
||||||
unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_OBJECT) };
|
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> {}
|
||||||
|
|
|
@ -88,6 +88,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
|
// a note on all "cast" tests: usually, especially for downcasts the desired
|
||||||
// class would be placed on the right, for example:
|
// class would be placed on the right, for example:
|
||||||
//
|
//
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue