aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/qemu-api/src')
-rw-r--r--rust/qemu-api/src/qom.rs96
1 files changed, 95 insertions, 1 deletions
diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs
index 14f98fe..ef966e5 100644
--- a/rust/qemu-api/src/qom.rs
+++ b/rust/qemu-api/src/qom.rs
@@ -95,7 +95,7 @@
use std::{
ffi::{c_void, CStr},
fmt,
- mem::ManuallyDrop,
+ mem::{ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
ptr::NonNull,
};
@@ -206,6 +206,100 @@ impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> {
}
}
+/// This struct knows that the superclasses of the object have already been
+/// initialized.
+pub struct ParentInit<'a, T>(&'a mut MaybeUninit<T>);
+
+impl<'a, T> ParentInit<'a, T> {
+ #[inline]
+ pub fn with(obj: &'a mut MaybeUninit<T>, f: impl FnOnce(ParentInit<'a, T>)) {
+ let parent_init = ParentInit(obj);
+ f(parent_init)
+ }
+}
+
+impl<T: ObjectType> ParentInit<'_, T> {
+ /// Return the receiver as a mutable raw pointer to Object.
+ ///
+ /// # Safety
+ ///
+ /// Fields beyond `Object` could be uninitialized and it's your
+ /// responsibility to avoid that they're used when the pointer is
+ /// dereferenced, either directly or through a cast.
+ pub fn as_object_mut_ptr(&self) -> *mut bindings::Object {
+ self.as_object_ptr().cast_mut()
+ }
+
+ /// Return the receiver as a mutable raw pointer to Object.
+ ///
+ /// # Safety
+ ///
+ /// Fields beyond `Object` could be uninitialized and it's your
+ /// responsibility to avoid that they're used when the pointer is
+ /// dereferenced, either directly or through a cast.
+ pub fn as_object_ptr(&self) -> *const bindings::Object {
+ self.0.as_ptr().cast()
+ }
+}
+
+impl<'a, T: ObjectImpl> ParentInit<'a, T> {
+ /// Convert from a derived type to one of its parent types, which
+ /// have already been initialized.
+ ///
+ /// # Safety
+ ///
+ /// Structurally this is always a safe operation; the [`IsA`] trait
+ /// provides static verification trait that `Self` dereferences to `U` or
+ /// a child of `U`, and only parent types of `T` are allowed.
+ ///
+ /// However, while the fields of the resulting reference are initialized,
+ /// calls might use uninitialized fields of the subclass. It is your
+ /// responsibility to avoid this.
+ pub unsafe fn upcast<U: ObjectType>(&self) -> &'a U
+ where
+ T::ParentType: IsA<U>,
+ {
+ // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait;
+ // the parent has been initialized before `instance_init `is called
+ unsafe { &*(self.0.as_ptr().cast::<U>()) }
+ }
+
+ /// Convert from a derived type to one of its parent types, which
+ /// have already been initialized.
+ ///
+ /// # Safety
+ ///
+ /// Structurally this is always a safe operation; the [`IsA`] trait
+ /// provides static verification trait that `Self` dereferences to `U` or
+ /// a child of `U`, and only parent types of `T` are allowed.
+ ///
+ /// However, while the fields of the resulting reference are initialized,
+ /// calls might use uninitialized fields of the subclass. It is your
+ /// responsibility to avoid this.
+ pub unsafe fn upcast_mut<U: ObjectType>(&mut self) -> &'a mut U
+ where
+ T::ParentType: IsA<U>,
+ {
+ // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait;
+ // the parent has been initialized before `instance_init `is called
+ unsafe { &mut *(self.0.as_mut_ptr().cast::<U>()) }
+ }
+}
+
+impl<T> Deref for ParentInit<'_, T> {
+ type Target = MaybeUninit<T>;
+
+ fn deref(&self) -> &Self::Target {
+ self.0
+ }
+}
+
+impl<T> DerefMut for ParentInit<'_, T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.0
+ }
+}
+
unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut bindings::Object) {
let mut state = NonNull::new(obj).unwrap().cast::<T>();
// SAFETY: obj is an instance of T, since rust_instance_init<T>