[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 13/14] rust: introduce alternative to offset_of!
From: |
Paolo Bonzini |
Subject: |
[PATCH 13/14] rust: introduce alternative to offset_of! |
Date: |
Mon, 1 Jul 2024 16:58:45 +0200 |
Allow working with Rust versions prior to 1.77. The code was
taken from Rust's Discourse platform and is used with permission of
the author.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qemu/Cargo.toml | 3 +
qemu/build.rs | 5 ++
qemu/src/hw/core/device_impl.rs | 4 +-
qemu/src/lib.rs | 4 ++
qemu/src/qom/object_impl.rs | 13 +++--
qemu/src/util/mod.rs | 1 +
qemu/src/util/offset_of.rs | 99 +++++++++++++++++++++++++++++++++
qemu/tests/main.rs | 11 +++-
9 files changed, 137 insertions(+), 10 deletions(-)
create mode 100644 qemu/build.rs
create mode 100644 qemu/src/util/offset_of.rs
diff --git a/qemu/Cargo.toml b/qemu/Cargo.toml
index a07a449..93808a5 100644
--- a/qemu/Cargo.toml
+++ b/qemu/Cargo.toml
@@ -12,3 +12,6 @@ cstr = { version = "=0.2.10" }
[dev-dependencies]
matches = ">=0"
+
+[build-dependencies]
+version_check = { version = "~0.9" }
diff --git a/qemu/build.rs b/qemu/build.rs
new file mode 100644
index 0000000..34f7b49
--- /dev/null
+++ b/qemu/build.rs
@@ -0,0 +1,5 @@
+fn main() {
+ if let Some(true) = version_check::is_min_version("1.77.0") {
+ println!("cargo:rustc-cfg=has_offset_of");
+ }
+}
diff --git a/qemu/src/hw/core/device_impl.rs b/qemu/src/hw/core/device_impl.rs
index 80b0e5e..b1d2f04 100644
--- a/qemu/src/hw/core/device_impl.rs
+++ b/qemu/src/hw/core/device_impl.rs
@@ -111,7 +111,7 @@ macro_rules! qdev_prop {
$kind,
$name,
(<$crate::conf_type!($type) as ConstDefault>::DEFAULT).$field,
- <$type as $crate::DeviceTypeImpl>::CONF_OFFSET +
std::mem::offset_of!($crate::conf_type!($type), $field)
+ <$type as $crate::DeviceTypeImpl>::CONF_OFFSET +
$crate::offset_of!($crate::conf_type!($type), $field)
)
};
}
@@ -126,7 +126,7 @@ macro_rules! qdev_define_type {
@extends $super $(,$supers)*, $crate::Object);
unsafe impl $crate::DeviceTypeImpl for $struct {
- const CONF_OFFSET: usize = std::mem::offset_of!($struct, conf);
+ const CONF_OFFSET: usize = $crate::offset_of!($struct, conf);
fn properties() -> *const $crate::Property {
static mut PROPERTIES: &'static [$crate::Property] =
&[$($props),+];
diff --git a/qemu/src/lib.rs b/qemu/src/lib.rs
index 3f0491c..2d43a25 100644
--- a/qemu/src/lib.rs
+++ b/qemu/src/lib.rs
@@ -31,3 +31,7 @@ pub use util::foreign::IntoNative;
pub use util::foreign::OwnedPointer;
pub use util::zeroed::Zeroed;
pub type Result<T> = std::result::Result<T, Error>;
+
+// with_offsets is exported directly from util::offset_of
+#[cfg(has_offset_of)]
+pub use std::mem::offset_of;
diff --git a/qemu/src/qom/object_impl.rs b/qemu/src/qom/object_impl.rs
index 61546b6..b1768b9 100644
--- a/qemu/src/qom/object_impl.rs
+++ b/qemu/src/qom/object_impl.rs
@@ -95,11 +95,14 @@ unsafe fn rust_type_register<T: TypeImpl + ObjectImpl>() {
#[macro_export]
macro_rules! qom_define_type {
($name:expr, $struct:ident, $conf_ty:ty, $state_ty:ty; @extends $super:ty
$(,$supers:ty)*) => {
- struct $struct {
- // self.base dropped by call to superclass instance_finalize
- base: std::mem::ManuallyDrop<$super>,
- conf: $conf_ty,
- state: $state_ty,
+ $crate::with_offsets! {
+ #[repr(C)]
+ struct $struct {
+ // self.base dropped by call to superclass instance_finalize
+ base: std::mem::ManuallyDrop<$super>,
+ conf: $conf_ty,
+ state: $state_ty,
+ }
}
// Define IsA markers for the struct itself and all the superclasses
diff --git a/qemu/src/util/mod.rs b/qemu/src/util/mod.rs
index 9c081b6..e4df7c9 100644
--- a/qemu/src/util/mod.rs
+++ b/qemu/src/util/mod.rs
@@ -1,3 +1,4 @@
pub mod error;
pub mod foreign;
+pub mod offset_of;
pub mod zeroed;
diff --git a/qemu/src/util/offset_of.rs b/qemu/src/util/offset_of.rs
new file mode 100644
index 0000000..4ce5188
--- /dev/null
+++ b/qemu/src/util/offset_of.rs
@@ -0,0 +1,99 @@
+#[cfg(not(has_offset_of))]
+#[macro_export]
+macro_rules! offset_of {
+ ($Container:ty, $field:ident) => {
+ <$Container>::offset_to.$field
+ };
+}
+
+/// A wrapper for struct declarations, that allows using `offset_of!` in
+/// versions of Rust prior to 1.77
+#[macro_export]
+macro_rules! with_offsets {
+ // source:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10a22a9b8393abd7b541d8fc844bc0df
+ // used under MIT license with permission of Yandros aka Daniel
Henry-Mantilla
+ (
+ #[repr(C)]
+ $(#[$struct_meta:meta])*
+ $struct_vis:vis
+ struct $StructName:ident {
+ $(
+ $(#[$field_meta:meta])*
+ $field_vis:vis
+ $field_name:ident : $field_ty:ty
+ ),*
+ $(,)?
+ }
+ ) => (
+ #[repr(C)]
+ $(#[$struct_meta])*
+ $struct_vis
+ struct $StructName {
+ $(
+ $(#[$field_meta])*
+ $field_vis
+ $field_name : $field_ty ,
+ )*
+ }
+
+ #[cfg(not(has_offset_of))]
+ #[allow(nonstandard_style)]
+ const _: () = {
+ pub
+ struct StructOffsets {
+ $(
+ $field_vis
+ $field_name: usize,
+ )*
+ }
+ struct Helper;
+ impl $StructName {
+ pub
+ const offset_to: StructOffsets = StructOffsets {
+ $(
+ $field_name: Helper::$field_name,
+ )*
+ };
+ }
+ const END_OF_PREV_FIELD: usize = 0;
+ $crate::with_offsets! {
+ @names [ $($field_name)* ]
+ @tys [ $($field_ty ,)*]
+ }
+ };
+ );
+
+ (
+ @names []
+ @tys []
+ ) => ();
+
+ (
+ @names [$field_name:ident $($other_names:tt)*]
+ @tys [$field_ty:ty , $($other_tys:tt)*]
+ ) => (
+ impl Helper {
+ const $field_name: usize = {
+ let align =
+ std::mem::align_of::<$field_ty>()
+ ;
+ let trail =
+ END_OF_PREV_FIELD % align
+ ;
+ 0 + END_OF_PREV_FIELD
+ + (align - trail)
+ * [1, 0][(trail == 0) as usize]
+ };
+ }
+ const _: () = {
+ const END_OF_PREV_FIELD: usize =
+ Helper::$field_name +
+ std::mem::size_of::<$field_ty>()
+ ;
+ $crate::with_offsets! {
+ @names [$($other_names)*]
+ @tys [$($other_tys)*]
+ }
+ };
+ );
+}
diff --git a/qemu/tests/main.rs b/qemu/tests/main.rs
index 601e92b..854c626 100644
--- a/qemu/tests/main.rs
+++ b/qemu/tests/main.rs
@@ -14,11 +14,16 @@ use qemu::DeviceState;
use qemu::Result;
+use qemu::with_offsets;
+
use std::cell::RefCell;
-#[derive(Default, ConstDefault)]
-struct TestConf {
- foo: bool,
+with_offsets! {
+ #[repr(C)]
+ #[derive(Default, ConstDefault)]
+ struct TestConf {
+ foo: bool,
+ }
}
#[derive(Default)]
--
2.45.2
- Re: [PATCH 03/14] rust: define traits and pointer wrappers to convert from/to C representations, (continued)
- [PATCH 07/14] rust: define wrappers for methods of the QOM Object class, Paolo Bonzini, 2024/07/01
- [PATCH 08/14] rust: define wrappers for methods of the QOM Device class, Paolo Bonzini, 2024/07/01
- [PATCH 06/14] rust: define wrappers for basic QOM concepts, Paolo Bonzini, 2024/07/01
- [PATCH 09/14] rust: add idiomatic bindings to define Object subclasses, Paolo Bonzini, 2024/07/01
- [PATCH 10/14] rust: add idiomatic bindings to define Device subclasses, Paolo Bonzini, 2024/07/01
- [PATCH 12/14] rust: replace c"" literals with cstr crate, Paolo Bonzini, 2024/07/01
- [PATCH 14/14] rust: use version of toml_edit that does not require new Rust, Paolo Bonzini, 2024/07/01
- [PATCH 13/14] rust: introduce alternative to offset_of!,
Paolo Bonzini <=
- [PATCH 11/14] rust: replace std::ffi::c_char with libc::c_char, Paolo Bonzini, 2024/07/01
- Re: [PATCH 00/14] rust: example of bindings code for Rust in QEMU, Pierrick Bouvier, 2024/07/04