aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api
diff options
context:
space:
mode:
Diffstat (limited to 'rust/qemu-api')
-rw-r--r--rust/qemu-api/Cargo.toml18
-rw-r--r--rust/qemu-api/build.rs11
-rw-r--r--rust/qemu-api/meson.build5
-rw-r--r--rust/qemu-api/src/assertions.rs25
-rw-r--r--rust/qemu-api/src/c_str.rs61
-rw-r--r--rust/qemu-api/src/cell.rs6
-rw-r--r--rust/qemu-api/src/chardev.rs5
-rw-r--r--rust/qemu-api/src/irq.rs6
-rw-r--r--rust/qemu-api/src/lib.rs7
-rw-r--r--rust/qemu-api/src/memory.rs3
-rw-r--r--rust/qemu-api/src/offset_of.rs168
-rw-r--r--rust/qemu-api/src/qdev.rs9
-rw-r--r--rust/qemu-api/src/qom.rs22
-rw-r--r--rust/qemu-api/src/timer.rs6
-rw-r--r--rust/qemu-api/src/vmstate.rs97
-rw-r--r--rust/qemu-api/src/zeroable.rs106
-rw-r--r--rust/qemu-api/tests/tests.rs11
-rw-r--r--rust/qemu-api/tests/vmstate_tests.rs64
18 files changed, 170 insertions, 460 deletions
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
index 57747bc..c96cf50 100644
--- a/rust/qemu-api/Cargo.toml
+++ b/rust/qemu-api/Cargo.toml
@@ -1,26 +1,22 @@
[package]
name = "qemu_api"
version = "0.1.0"
-edition = "2021"
authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
-license = "GPL-2.0-or-later"
-readme = "README.md"
-homepage = "https://www.qemu.org"
description = "Rust bindings for QEMU"
-repository = "https://gitlab.com/qemu-project/qemu/"
+readme = "README.md"
resolver = "2"
publish = false
-keywords = []
-categories = []
-rust-version = "1.63.0"
+
+edition.workspace = true
+homepage.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
[dependencies]
qemu_api_macros = { path = "../qemu-api-macros" }
libc = "0.2.162"
-[build-dependencies]
-version_check = "~0.9"
-
[features]
default = ["debug_cell"]
allocator = []
diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs
index 471e6c6..1e72064 100644
--- a/rust/qemu-api/build.rs
+++ b/rust/qemu-api/build.rs
@@ -8,15 +8,13 @@ use std::os::unix::fs::symlink as symlink_file;
use std::os::windows::fs::symlink_file;
use std::{env, fs::remove_file, io::Result, path::Path};
-use version_check as rustc;
-
fn main() -> Result<()> {
// Placing bindings.inc.rs in the source directory is supported
// but not documented or encouraged.
let path = env::var("MESON_BUILD_ROOT")
.unwrap_or_else(|_| format!("{}/src", env!("CARGO_MANIFEST_DIR")));
- let file = format!("{}/bindings.inc.rs", path);
+ let file = format!("{path}/bindings.inc.rs");
let file = Path::new(&file);
if !Path::new(&file).exists() {
panic!(concat!(
@@ -31,18 +29,13 @@ fn main() -> Result<()> {
}
let out_dir = env::var("OUT_DIR").unwrap();
- let dest_path = format!("{}/bindings.inc.rs", out_dir);
+ let dest_path = format!("{out_dir}/bindings.inc.rs");
let dest_path = Path::new(&dest_path);
if dest_path.symlink_metadata().is_ok() {
remove_file(dest_path)?;
}
symlink_file(file, dest_path)?;
- // Check for available rustc features
- if rustc::is_min_version("1.77.0").unwrap_or(false) {
- println!("cargo:rustc-cfg=has_offset_of");
- }
-
println!("cargo:rerun-if-changed=build.rs");
Ok(())
}
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 858685d..1696df7 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -5,9 +5,6 @@ _qemu_api_cfg = run_command(rustc_args,
libc_dep = dependency('libc-0.2-rs')
# _qemu_api_cfg += ['--cfg', 'feature="allocator"']
-if rustc.version().version_compare('>=1.77.0')
- _qemu_api_cfg += ['--cfg', 'has_offset_of']
-endif
if get_option('debug_mutex')
_qemu_api_cfg += ['--cfg', 'feature="debug_cell"']
endif
@@ -23,12 +20,10 @@ _qemu_api_rs = static_library(
'src/callbacks.rs',
'src/cell.rs',
'src/chardev.rs',
- 'src/c_str.rs',
'src/errno.rs',
'src/irq.rs',
'src/memory.rs',
'src/module.rs',
- 'src/offset_of.rs',
'src/prelude.rs',
'src/qdev.rs',
'src/qom.rs',
diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions.rs
index eb12e94..a2d38c8 100644
--- a/rust/qemu-api/src/assertions.rs
+++ b/rust/qemu-api/src/assertions.rs
@@ -78,33 +78,26 @@ macro_rules! assert_same_type {
/// ```
#[macro_export]
macro_rules! assert_field_type {
- ($t:ty, $i:tt, $ti:ty) => {
+ (@internal $param_name:ident, $ti:ty, $t:ty, $($field:tt)*) => {
const _: () = {
#[allow(unused)]
- fn assert_field_type(v: $t) {
- fn types_must_be_equal<T, U>(_: T)
+ fn assert_field_type($param_name: &$t) {
+ fn types_must_be_equal<T, U>(_: &T)
where
T: $crate::assertions::EqType<Itself = U>,
{
}
- types_must_be_equal::<_, $ti>(v.$i);
+ types_must_be_equal::<_, $ti>(&$($field)*);
}
};
};
+ ($t:ty, $i:tt, $ti:ty) => {
+ $crate::assert_field_type!(@internal v, $ti, $t, v.$i);
+ };
+
($t:ty, $i:tt, $ti:ty, num = $num:ident) => {
- const _: () = {
- #[allow(unused)]
- fn assert_field_type(v: $t) {
- fn types_must_be_equal<T, U>(_: T)
- where
- T: $crate::assertions::EqType<Itself = U>,
- {
- }
- let index: usize = v.$num.try_into().unwrap();
- types_must_be_equal::<_, &$ti>(&v.$i[index]);
- }
- };
+ $crate::assert_field_type!(@internal v, $ti, $t, v.$i[0]);
};
}
diff --git a/rust/qemu-api/src/c_str.rs b/rust/qemu-api/src/c_str.rs
deleted file mode 100644
index 3fa61b5..0000000
--- a/rust/qemu-api/src/c_str.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2024 Red Hat, Inc.
-// Author(s): Paolo Bonzini <pbonzini@redhat.com>
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#![doc(hidden)]
-//! This module provides a macro to define a constant of type
-//! [`CStr`](std::ffi::CStr), for compatibility with versions of
-//! Rust that lack `c""` literals.
-//!
-//! Documentation is hidden because it only exposes macros, which
-//! are exported directly from `qemu_api`.
-
-#[macro_export]
-/// Given a string constant _without_ embedded or trailing NULs, return
-/// a `CStr`.
-///
-/// Needed for compatibility with Rust <1.77.
-macro_rules! c_str {
- ($str:expr) => {{
- const STRING: &str = concat!($str, "\0");
- const BYTES: &[u8] = STRING.as_bytes();
-
- // "for" is not allowed in const context... oh well,
- // everybody loves some lisp. This could be turned into
- // a procedural macro if this is a problem; alternatively
- // Rust 1.72 makes CStr::from_bytes_with_nul a const function.
- const fn f(b: &[u8], i: usize) {
- if i == b.len() - 1 {
- } else if b[i] == 0 {
- panic!("c_str argument contains NUL")
- } else {
- f(b, i + 1)
- }
- }
- f(BYTES, 0);
-
- // SAFETY: absence of NULs apart from the final byte was checked above
- unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(BYTES) }
- }};
-}
-
-#[cfg(test)]
-mod tests {
- use std::ffi::CStr;
-
- use crate::c_str;
-
- #[test]
- fn test_cstr_macro() {
- let good = c_str!("🦀");
- let good_bytes = b"\xf0\x9f\xa6\x80\0";
- assert_eq!(good.to_bytes_with_nul(), good_bytes);
- }
-
- #[test]
- fn test_cstr_macro_const() {
- const GOOD: &CStr = c_str!("🦀");
- const GOOD_BYTES: &[u8] = b"\xf0\x9f\xa6\x80\0";
- assert_eq!(GOOD.to_bytes_with_nul(), GOOD_BYTES);
- }
-}
diff --git a/rust/qemu-api/src/cell.rs b/rust/qemu-api/src/cell.rs
index ab0785a..05ce09f 100644
--- a/rust/qemu-api/src/cell.rs
+++ b/rust/qemu-api/src/cell.rs
@@ -77,13 +77,13 @@
//!
//! ```
//! # use qemu_api::prelude::*;
-//! # use qemu_api::{c_str, cell::BqlRefCell, irq::InterruptSource, irq::IRQState};
+//! # use qemu_api::{cell::BqlRefCell, irq::InterruptSource, irq::IRQState};
//! # use qemu_api::{sysbus::SysBusDevice, qom::Owned, qom::ParentField};
//! # const N_GPIOS: usize = 8;
//! # struct PL061Registers { /* ... */ }
//! # unsafe impl ObjectType for PL061State {
//! # type Class = <SysBusDevice as ObjectType>::Class;
-//! # const TYPE_NAME: &'static std::ffi::CStr = c_str!("pl061");
+//! # const TYPE_NAME: &'static std::ffi::CStr = c"pl061";
//! # }
//! struct PL061State {
//! parent_obj: ParentField<SysBusDevice>,
@@ -1016,7 +1016,7 @@ impl<T> Opaque<T> {
/// Returns a raw pointer to the opaque data.
pub const fn as_ptr(&self) -> *const T {
- self.as_mut_ptr() as *const _
+ self.as_mut_ptr().cast_const()
}
/// Returns a raw pointer to the opaque data that can be passed to a
diff --git a/rust/qemu-api/src/chardev.rs b/rust/qemu-api/src/chardev.rs
index 11e6c45..6e0590d 100644
--- a/rust/qemu-api/src/chardev.rs
+++ b/rust/qemu-api/src/chardev.rs
@@ -10,11 +10,10 @@
//! called.
use std::{
- ffi::CStr,
+ ffi::{c_int, c_void, CStr},
fmt::{self, Debug},
io::{self, ErrorKind, Write},
marker::PhantomPinned,
- os::raw::{c_int, c_void},
ptr::addr_of_mut,
slice,
};
@@ -161,7 +160,7 @@ impl CharBackend {
receive_cb,
event_cb,
None,
- (owner as *const T as *mut T).cast::<c_void>(),
+ (owner as *const T).cast_mut().cast::<c_void>(),
core::ptr::null_mut(),
true,
);
diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs
index 1222d4f..1526e6f 100644
--- a/rust/qemu-api/src/irq.rs
+++ b/rust/qemu-api/src/irq.rs
@@ -4,7 +4,11 @@
//! Bindings for interrupt sources
-use std::{ffi::CStr, marker::PhantomData, os::raw::c_int, ptr};
+use std::{
+ ffi::{c_int, CStr},
+ marker::PhantomData,
+ ptr,
+};
use crate::{
bindings::{self, qemu_set_irq},
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 05f38b5..234a94e 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -15,7 +15,6 @@ pub mod prelude;
pub mod assertions;
pub mod bitops;
-pub mod c_str;
pub mod callbacks;
pub mod cell;
pub mod chardev;
@@ -23,7 +22,6 @@ pub mod errno;
pub mod irq;
pub mod memory;
pub mod module;
-pub mod offset_of;
pub mod qdev;
pub mod qom;
pub mod sysbus;
@@ -33,7 +31,7 @@ pub mod zeroable;
use std::{
alloc::{GlobalAlloc, Layout},
- os::raw::c_void,
+ ffi::c_void,
};
#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
@@ -165,6 +163,3 @@ unsafe impl GlobalAlloc for QemuAllocator {
}
}
}
-
-#[cfg(has_offset_of)]
-pub use core::mem::offset_of;
diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs
index fdb1ea1..9ef2694 100644
--- a/rust/qemu-api/src/memory.rs
+++ b/rust/qemu-api/src/memory.rs
@@ -5,9 +5,8 @@
//! Bindings for `MemoryRegion`, `MemoryRegionOps` and `MemTxAttrs`
use std::{
- ffi::{CStr, CString},
+ ffi::{c_uint, c_void, CStr, CString},
marker::PhantomData,
- os::raw::{c_uint, c_void},
};
pub use bindings::{hwaddr, MemTxAttrs};
diff --git a/rust/qemu-api/src/offset_of.rs b/rust/qemu-api/src/offset_of.rs
deleted file mode 100644
index 373229b..0000000
--- a/rust/qemu-api/src/offset_of.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-#![doc(hidden)]
-//! This module provides macros that emulate the functionality of
-//! `core::mem::offset_of` on older versions of Rust.
-//!
-//! Documentation is hidden because it only exposes macros, which
-//! are exported directly from `qemu_api`.
-
-/// This macro provides the same functionality as `core::mem::offset_of`,
-/// except that only one level of field access is supported. The declaration
-/// of the struct must be wrapped with `with_offsets! { }`.
-///
-/// It is needed because `offset_of!` was only stabilized in Rust 1.77.
-#[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 {
- // This method to generate field offset constants comes from:
- //
- // 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
- (
- $(#[$struct_meta:meta])*
- $struct_vis:vis
- struct $StructName:ident {
- $(
- $(#[$field_meta:meta])*
- $field_vis:vis
- $field_name:ident : $field_ty:ty
- ),*
- $(,)?
- }
- ) => (
- #[cfg(not(has_offset_of))]
- const _: () = {
- struct StructOffsetsHelper<T>(std::marker::PhantomData<T>);
- const END_OF_PREV_FIELD: usize = 0;
-
- // populate StructOffsetsHelper<T> with associated consts,
- // one for each field
- $crate::with_offsets! {
- @struct $StructName
- @names [ $($field_name)* ]
- @tys [ $($field_ty ,)*]
- }
-
- // now turn StructOffsetsHelper<T>'s consts into a single struct,
- // applying field visibility. This provides better error messages
- // than if offset_of! used StructOffsetsHelper::<T> directly.
- pub
- struct StructOffsets {
- $(
- $field_vis
- $field_name: usize,
- )*
- }
- impl $StructName {
- pub
- const OFFSET_TO__: StructOffsets = StructOffsets {
- $(
- $field_name: StructOffsetsHelper::<$StructName>::$field_name,
- )*
- };
- }
- };
- );
-
- (
- @struct $StructName:ident
- @names []
- @tys []
- ) => ();
-
- (
- @struct $StructName:ident
- @names [$field_name:ident $($other_names:tt)*]
- @tys [$field_ty:ty , $($other_tys:tt)*]
- ) => (
- #[allow(non_local_definitions)]
- #[allow(clippy::modulo_one)]
- impl StructOffsetsHelper<$StructName> {
- #[allow(nonstandard_style)]
- const $field_name: usize = {
- const ALIGN: usize = std::mem::align_of::<$field_ty>();
- const TRAIL: usize = END_OF_PREV_FIELD % ALIGN;
- END_OF_PREV_FIELD + (if TRAIL == 0 { 0usize } else { ALIGN - TRAIL })
- };
- }
- const _: () = {
- const END_OF_PREV_FIELD: usize =
- StructOffsetsHelper::<$StructName>::$field_name +
- std::mem::size_of::<$field_ty>()
- ;
- $crate::with_offsets! {
- @struct $StructName
- @names [$($other_names)*]
- @tys [$($other_tys)*]
- }
- };
- );
-}
-
-#[cfg(test)]
-mod tests {
- use crate::offset_of;
-
- #[repr(C)]
- struct Foo {
- a: u16,
- b: u32,
- c: u64,
- d: u16,
- }
-
- #[repr(C)]
- struct Bar {
- pub a: u16,
- pub b: u64,
- c: Foo,
- d: u64,
- }
-
- crate::with_offsets! {
- #[repr(C)]
- struct Bar {
- pub a: u16,
- pub b: u64,
- c: Foo,
- d: u64,
- }
- }
-
- #[repr(C)]
- pub struct Baz {
- b: u32,
- a: u8,
- }
- crate::with_offsets! {
- #[repr(C)]
- pub struct Baz {
- b: u32,
- a: u8,
- }
- }
-
- #[test]
- fn test_offset_of() {
- const OFFSET_TO_C: usize = offset_of!(Bar, c);
-
- assert_eq!(offset_of!(Bar, a), 0);
- assert_eq!(offset_of!(Bar, b), 8);
- assert_eq!(OFFSET_TO_C, 16);
- assert_eq!(offset_of!(Bar, d), 40);
-
- assert_eq!(offset_of!(Baz, b), 0);
- assert_eq!(offset_of!(Baz, a), 4);
- }
-}
diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs
index 18b4a9b..1279d7a 100644
--- a/rust/qemu-api/src/qdev.rs
+++ b/rust/qemu-api/src/qdev.rs
@@ -5,8 +5,7 @@
//! Bindings to create devices and access device functionality from Rust.
use std::{
- ffi::{CStr, CString},
- os::raw::{c_int, c_void},
+ ffi::{c_int, c_void, CStr, CString},
ptr::NonNull,
};
@@ -191,7 +190,7 @@ macro_rules! define_property {
// use associated function syntax for type checking
name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
- offset: $crate::offset_of!($state, $field) as isize,
+ offset: ::std::mem::offset_of!($state, $field) as isize,
bitnr: $bitnr,
set_default: true,
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
@@ -203,7 +202,7 @@ macro_rules! define_property {
// use associated function syntax for type checking
name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
- offset: $crate::offset_of!($state, $field) as isize,
+ offset: ::std::mem::offset_of!($state, $field) as isize,
set_default: true,
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
..$crate::zeroable::Zeroable::ZERO
@@ -214,7 +213,7 @@ macro_rules! define_property {
// use associated function syntax for type checking
name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
- offset: $crate::offset_of!($state, $field) as isize,
+ offset: ::std::mem::offset_of!($state, $field) as isize,
set_default: false,
..$crate::zeroable::Zeroable::ZERO
}
diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs
index 34d7bc0..41e5a5e 100644
--- a/rust/qemu-api/src/qom.rs
+++ b/rust/qemu-api/src/qom.rs
@@ -93,11 +93,10 @@
//! without incurring into violations of orphan rules for traits.
use std::{
- ffi::CStr,
+ ffi::{c_void, CStr},
fmt,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
- os::raw::c_void,
ptr::NonNull,
};
@@ -227,7 +226,7 @@ unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut bindings::
unsafe extern "C" fn rust_class_init<T: ObjectType + ObjectImpl>(
klass: *mut ObjectClass,
- _data: *mut c_void,
+ _data: *const c_void,
) {
let mut klass = NonNull::new(klass)
.unwrap()
@@ -389,7 +388,7 @@ where
{
#[allow(clippy::as_ptr_cast_mut)]
{
- self.as_ptr::<U>() as *mut _
+ self.as_ptr::<U>().cast_mut()
}
}
}
@@ -492,7 +491,7 @@ pub trait ObjectImpl: ObjectType + IsA<Object> {
/// the effects of copying the contents of the parent's class struct
/// to the descendants.
const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *const c_void),
> = None;
const TYPE_INFO: TypeInfo = TypeInfo {
@@ -513,8 +512,8 @@ pub trait ObjectImpl: ObjectType + IsA<Object> {
class_size: core::mem::size_of::<Self::Class>(),
class_init: Some(rust_class_init::<Self>),
class_base_init: Self::CLASS_BASE_INIT,
- class_data: core::ptr::null_mut(),
- interfaces: core::ptr::null_mut(),
+ class_data: core::ptr::null(),
+ interfaces: core::ptr::null(),
};
// methods on ObjectClass
@@ -535,9 +534,10 @@ pub trait ObjectImpl: ObjectType + IsA<Object> {
/// While `klass`'s parent class is initialized on entry, the other fields
/// are all zero; it is therefore assumed that all fields in `T` can be
/// zeroed, otherwise it would not be possible to provide the class as a
- /// `&mut T`. TODO: add a bound of [`Zeroable`](crate::zeroable::Zeroable)
- /// to T; this is more easily done once Zeroable does not require a manual
- /// implementation (Rust 1.75.0).
+ /// `&mut T`. TODO: it may be possible to add an unsafe trait that checks
+ /// that all fields *after the parent class* (but not the parent class
+ /// itself) are Zeroable. This unsafe trait can be added via a derive
+ /// macro.
const CLASS_INIT: fn(&mut Self::Class);
}
@@ -638,7 +638,7 @@ impl<T: ObjectType> Owned<T> {
// SAFETY NOTE: while NonNull requires a mutable pointer, only
// Deref is implemented so the pointer passed to from_raw
// remains const
- Owned(NonNull::new(ptr as *mut T).unwrap())
+ Owned(NonNull::new(ptr.cast_mut()).unwrap())
}
/// Obtain a raw C pointer from a reference. `src` is consumed
diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs
index f0b04ef..868bd88 100644
--- a/rust/qemu-api/src/timer.rs
+++ b/rust/qemu-api/src/timer.rs
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use std::{
- os::raw::{c_int, c_void},
+ ffi::{c_int, c_void},
pin::Pin,
};
@@ -81,7 +81,7 @@ impl Timer {
scale as c_int,
attributes as c_int,
Some(timer_cb),
- (opaque as *const T).cast::<c_void>() as *mut c_void,
+ (opaque as *const T).cast::<c_void>().cast_mut(),
)
}
}
@@ -121,3 +121,5 @@ impl ClockType {
pub const CLOCK_VIRTUAL: ClockType = ClockType {
id: QEMUClockType::QEMU_CLOCK_VIRTUAL,
};
+
+pub const NANOSECONDS_PER_SECOND: u64 = 1000000000;
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 1b2b12e..9c8b239 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -25,7 +25,7 @@
//! functionality that is missing from `vmstate_of!`.
use core::{marker::PhantomData, mem, ptr::NonNull};
-use std::os::raw::{c_int, c_void};
+use std::ffi::{c_int, c_void};
pub use crate::bindings::{VMStateDescription, VMStateField};
use crate::{
@@ -200,13 +200,14 @@ pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags
/// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
#[macro_export]
macro_rules! vmstate_of {
- ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
+ ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
- offset: $crate::offset_of!($struct_name, $field_name),
- $(num_offset: $crate::offset_of!($struct_name, $num),)?
+ offset: ::std::mem::offset_of!($struct_name, $field_name),
+ $(num_offset: ::std::mem::offset_of!($struct_name, $num),)?
+ $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
// The calls to `call_func_with_field!` are the magic that
// computes most of the VMStateField from the type of the field.
info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
@@ -426,7 +427,7 @@ unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
macro_rules! vmstate_unused {
($size:expr) => {{
$crate::bindings::VMStateField {
- name: $crate::c_str!("unused").as_ptr(),
+ name: c"unused".as_ptr(),
size: $size,
info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
flags: $crate::bindings::VMStateFlags::VMS_BUFFER,
@@ -435,6 +436,38 @@ macro_rules! vmstate_unused {
}};
}
+pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
+ opaque: *mut c_void,
+ version_id: c_int,
+) -> bool {
+ // SAFETY: the opaque was passed as a reference to `T`.
+ let owner: &T = unsafe { &*(opaque.cast::<T>()) };
+ let version: u8 = version_id.try_into().unwrap();
+ F::call((owner, version))
+}
+
+pub type VMSFieldExistCb = unsafe extern "C" fn(
+ opaque: *mut std::os::raw::c_void,
+ version_id: std::os::raw::c_int,
+) -> bool;
+
+#[macro_export]
+macro_rules! vmstate_exist_fn {
+ ($struct_name:ty, $test_fn:expr) => {{
+ const fn test_cb_builder__<T, F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>>(
+ _phantom: ::core::marker::PhantomData<F>,
+ ) -> $crate::vmstate::VMSFieldExistCb {
+ let _: () = F::ASSERT_IS_SOME;
+ $crate::vmstate::rust_vms_test_field_exists::<T, F>
+ }
+
+ const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
+ ::core::marker::PhantomData
+ }
+ Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
+ }};
+}
+
// FIXME: including the `vmsd` field in a `const` is not possible without
// the const_refs_static feature (stabilized in Rust 1.83.0). Without it,
// it is not possible to use VMS_STRUCT in a transparent manner using
@@ -445,19 +478,20 @@ macro_rules! vmstate_unused {
#[doc(alias = "VMSTATE_STRUCT")]
#[macro_export]
macro_rules! vmstate_struct {
- ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => {
+ ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
- $(num_offset: $crate::offset_of!($struct_name, $num),)?
+ $(num_offset: ::std::mem::offset_of!($struct_name, $num),)?
offset: {
$crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?);
- $crate::offset_of!($struct_name, $field_name)
+ ::std::mem::offset_of!($struct_name, $field_name)
},
size: ::core::mem::size_of::<$type>(),
flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
vmsd: $vmsd,
+ $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
..$crate::zeroable::Zeroable::ZERO
} $(.with_varray_flag_unchecked(
$crate::call_func_with_field!(
@@ -473,7 +507,7 @@ macro_rules! vmstate_struct {
#[doc(alias = "VMSTATE_CLOCK")]
#[macro_export]
macro_rules! vmstate_clock {
- ($struct_name:ty, $field_name:ident) => {{
+ ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?) => {{
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
@@ -482,9 +516,9 @@ macro_rules! vmstate_clock {
$crate::assert_field_type!(
$struct_name,
$field_name,
- $crate::qom::Owned<$crate::qdev::Clock>
+ $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)?
);
- $crate::offset_of!($struct_name, $field_name)
+ ::std::mem::offset_of!($struct_name, $field_name)
},
size: ::core::mem::size_of::<*const $crate::qdev::Clock>(),
flags: $crate::bindings::VMStateFlags(
@@ -493,7 +527,14 @@ macro_rules! vmstate_clock {
),
vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
..$crate::zeroable::Zeroable::ZERO
- }
+ } $(.with_varray_flag_unchecked(
+ $crate::call_func_with_field!(
+ $crate::vmstate::vmstate_varray_flag,
+ $struct_name,
+ $num
+ )
+ )
+ $(.with_varray_multiply($factor))?)?
}};
}
@@ -514,43 +555,13 @@ macro_rules! vmstate_fields {
}}
}
-pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
- opaque: *mut c_void,
- version_id: c_int,
-) -> bool {
- let owner: &T = unsafe { &*(opaque.cast::<T>()) };
- let version: u8 = version_id.try_into().unwrap();
- // SAFETY: the opaque was passed as a reference to `T`.
- F::call((owner, version))
-}
-
-pub type VMSFieldExistCb = unsafe extern "C" fn(
- opaque: *mut std::os::raw::c_void,
- version_id: std::os::raw::c_int,
-) -> bool;
-
#[doc(alias = "VMSTATE_VALIDATE")]
#[macro_export]
macro_rules! vmstate_validate {
($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
$crate::bindings::VMStateField {
name: ::std::ffi::CStr::as_ptr($test_name),
- field_exists: {
- const fn test_cb_builder__<
- T,
- F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>,
- >(
- _phantom: ::core::marker::PhantomData<F>,
- ) -> $crate::vmstate::VMSFieldExistCb {
- let _: () = F::ASSERT_IS_SOME;
- $crate::vmstate::rust_vms_test_field_exists::<T, F>
- }
-
- const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
- ::core::marker::PhantomData
- }
- Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
- },
+ field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
flags: $crate::bindings::VMStateFlags(
$crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
| $crate::bindings::VMStateFlags::VMS_ARRAY.0,
diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs
index a3415a2..d8239d0 100644
--- a/rust/qemu-api/src/zeroable.rs
+++ b/rust/qemu-api/src/zeroable.rs
@@ -4,89 +4,17 @@
/// Encapsulates the requirement that
/// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause undefined
-/// behavior. This trait in principle could be implemented as just:
-///
-/// ```
-/// pub unsafe trait Zeroable: Default {
-/// const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() };
-/// }
-/// ```
-///
-/// The need for a manual implementation is only because `zeroed()` cannot
-/// be used as a `const fn` prior to Rust 1.75.0. Once we can assume a new
-/// enough version of the compiler, we could provide a `#[derive(Zeroable)]`
-/// macro to check at compile-time that all struct fields are Zeroable, and
-/// use the above blanket implementation of the `ZERO` constant.
+/// behavior.
///
/// # Safety
///
-/// Because the implementation of `ZERO` is manual, it does not make
-/// any assumption on the safety of `zeroed()`. However, other users of the
-/// trait could use it that way. Do not add this trait to a type unless
-/// all-zeroes is a valid value for the type. In particular, remember that
-/// raw pointers can be zero, but references and `NonNull<T>` cannot
+/// Do not add this trait to a type unless all-zeroes is a valid value for the
+/// type. In particular, raw pointers can be zero, but references and
+/// `NonNull<T>` cannot.
pub unsafe trait Zeroable: Default {
- const ZERO: Self;
-}
-
-/// A macro that acts similarly to [`core::mem::zeroed()`], only is const
-///
-/// ## Safety
-///
-/// Similar to `core::mem::zeroed()`, except this zeroes padding bits. Zeroed
-/// padding usually isn't relevant to safety, but might be if a C union is used.
-///
-/// Just like for `core::mem::zeroed()`, an all zero byte pattern might not
-/// be a valid value for a type, as is the case for references `&T` and `&mut
-/// T`. Reference types trigger a (denied by default) lint and cause immediate
-/// undefined behavior if the lint is ignored
-///
-/// ```rust compile_fail
-/// use const_zero::const_zero;
-/// // error: any use of this value will cause an error
-/// // note: `#[deny(const_err)]` on by default
-/// const STR: &str = unsafe{const_zero!(&'static str)};
-/// ```
-///
-/// `const_zero` does not work on unsized types:
-///
-/// ```rust compile_fail
-/// use const_zero::const_zero;
-/// // error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-/// const BYTES: [u8] = unsafe{const_zero!([u8])};
-/// ```
-/// ## Differences with `core::mem::zeroed`
-///
-/// `const_zero` zeroes padding bits, while `core::mem::zeroed` doesn't
-#[macro_export]
-macro_rules! const_zero {
- // This macro to produce a type-generic zero constant is taken from the
- // const_zero crate (v0.1.1):
- //
- // https://docs.rs/const-zero/latest/src/const_zero/lib.rs.html
- //
- // and used under MIT license
- ($type_:ty) => {{
- const TYPE_SIZE: ::core::primitive::usize = ::core::mem::size_of::<$type_>();
- union TypeAsBytes {
- bytes: [::core::primitive::u8; TYPE_SIZE],
- inner: ::core::mem::ManuallyDrop<$type_>,
- }
- const ZERO_BYTES: TypeAsBytes = TypeAsBytes {
- bytes: [0; TYPE_SIZE],
- };
- ::core::mem::ManuallyDrop::<$type_>::into_inner(ZERO_BYTES.inner)
- }};
-}
-
-/// A wrapper to implement the `Zeroable` trait through the `const_zero` macro.
-#[macro_export]
-macro_rules! impl_zeroable {
- ($type:ty) => {
- unsafe impl $crate::zeroable::Zeroable for $type {
- const ZERO: Self = unsafe { $crate::const_zero!($type) };
- }
- };
+ /// Return a value of Self whose memory representation consists of all
+ /// zeroes, with the possible exclusion of padding bytes.
+ const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() };
}
// bindgen does not derive Default here
@@ -97,13 +25,13 @@ impl Default for crate::bindings::VMStateFlags {
}
}
-impl_zeroable!(crate::bindings::Property__bindgen_ty_1);
-impl_zeroable!(crate::bindings::Property);
-impl_zeroable!(crate::bindings::VMStateFlags);
-impl_zeroable!(crate::bindings::VMStateField);
-impl_zeroable!(crate::bindings::VMStateDescription);
-impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1);
-impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2);
-impl_zeroable!(crate::bindings::MemoryRegionOps);
-impl_zeroable!(crate::bindings::MemTxAttrs);
-impl_zeroable!(crate::bindings::CharBackend);
+unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {}
+unsafe impl Zeroable for crate::bindings::Property {}
+unsafe impl Zeroable for crate::bindings::VMStateFlags {}
+unsafe impl Zeroable for crate::bindings::VMStateField {}
+unsafe impl Zeroable for crate::bindings::VMStateDescription {}
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {}
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {}
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps {}
+unsafe impl Zeroable for crate::bindings::MemTxAttrs {}
+unsafe impl Zeroable for crate::bindings::CharBackend {}
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 99a7aab..a658a49 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -6,7 +6,6 @@ use std::{ffi::CStr, ptr::addr_of};
use qemu_api::{
bindings::{module_call_init, module_init_type, qdev_prop_bool},
- c_str,
cell::{self, BqlCell},
declare_properties, define_property,
prelude::*,
@@ -21,12 +20,11 @@ mod vmstate_tests;
// Test that macros can compile.
pub static VMSTATE: VMStateDescription = VMStateDescription {
- name: c_str!("name").as_ptr(),
+ name: c"name".as_ptr(),
unmigratable: true,
..Zeroable::ZERO
};
-#[derive(qemu_api_macros::offsets)]
#[repr(C)]
#[derive(qemu_api_macros::Object)]
pub struct DummyState {
@@ -49,7 +47,7 @@ impl DummyClass {
declare_properties! {
DUMMY_PROPERTIES,
define_property!(
- c_str!("migrate-clk"),
+ c"migrate-clk",
DummyState,
migrate_clock,
unsafe { &qdev_prop_bool },
@@ -59,7 +57,7 @@ declare_properties! {
unsafe impl ObjectType for DummyState {
type Class = DummyClass;
- const TYPE_NAME: &'static CStr = c_str!("dummy");
+ const TYPE_NAME: &'static CStr = c"dummy";
}
impl ObjectImpl for DummyState {
@@ -79,7 +77,6 @@ impl DeviceImpl for DummyState {
}
}
-#[derive(qemu_api_macros::offsets)]
#[repr(C)]
#[derive(qemu_api_macros::Object)]
pub struct DummyChildState {
@@ -94,7 +91,7 @@ pub struct DummyChildClass {
unsafe impl ObjectType for DummyChildState {
type Class = DummyChildClass;
- const TYPE_NAME: &'static CStr = c_str!("dummy_child");
+ const TYPE_NAME: &'static CStr = c"dummy_child";
}
impl ObjectImpl for DummyChildState {
diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs
index 8b93492..ad0fc5c 100644
--- a/rust/qemu-api/tests/vmstate_tests.rs
+++ b/rust/qemu-api/tests/vmstate_tests.rs
@@ -2,14 +2,18 @@
// Author(s): Zhao Liu <zhai1.liu@intel.com>
// SPDX-License-Identifier: GPL-2.0-or-later
-use std::{ffi::CStr, mem::size_of, os::raw::c_void, ptr::NonNull, slice};
+use std::{
+ ffi::{c_void, CStr},
+ mem::size_of,
+ ptr::NonNull,
+ slice,
+};
use qemu_api::{
bindings::{
vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8,
vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
},
- c_str,
cell::{BqlCell, Opaque},
impl_vmstate_forward,
vmstate::{VMStateDescription, VMStateField},
@@ -28,7 +32,7 @@ const FOO_ARRAY_MAX: usize = 3;
// - VMSTATE_VARRAY_UINT16_UNSAFE
// - VMSTATE_VARRAY_MULTIPLY
#[repr(C)]
-#[derive(qemu_api_macros::offsets)]
+#[derive(Default)]
struct FooA {
arr: [u8; FOO_ARRAY_MAX],
num: u16,
@@ -38,7 +42,7 @@ struct FooA {
}
static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
- name: c_str!("foo_a").as_ptr(),
+ name: c"foo_a".as_ptr(),
version_id: 1,
minimum_version_id: 1,
fields: vmstate_fields! {
@@ -147,8 +151,9 @@ fn test_vmstate_varray_multiply() {
// - VMSTATE_STRUCT_VARRAY_UINT8
// - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
// - VMSTATE_ARRAY
+// - VMSTATE_STRUCT_VARRAY_UINT8 with BqlCell wrapper & test_fn
#[repr(C)]
-#[derive(qemu_api_macros::offsets)]
+#[derive(Default)]
struct FooB {
arr_a: [FooA; FOO_ARRAY_MAX],
num_a: u8,
@@ -158,10 +163,16 @@ struct FooB {
val: bool,
// FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
arr_i64: [i64; FOO_ARRAY_MAX],
+ arr_a_wrap: [FooA; FOO_ARRAY_MAX],
+ num_a_wrap: BqlCell<u32>,
+}
+
+fn validate_foob(_state: &FooB, _version_id: u8) -> bool {
+ true
}
static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
- name: c_str!("foo_b").as_ptr(),
+ name: c"foo_b".as_ptr(),
version_id: 2,
minimum_version_id: 1,
fields: vmstate_fields! {
@@ -170,13 +181,14 @@ static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
vmstate_of!(FooB, arr_i64),
+ vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FOOA, FooA, validate_foob),
},
..Zeroable::ZERO
};
#[test]
fn test_vmstate_bool_v() {
- let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
// 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
assert_eq!(
@@ -196,7 +208,7 @@ fn test_vmstate_bool_v() {
#[test]
fn test_vmstate_uint64() {
- let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
// 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
assert_eq!(
@@ -216,7 +228,7 @@ fn test_vmstate_uint64() {
#[test]
fn test_vmstate_struct_varray_uint8() {
- let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
// 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
// VMSTATE_STRUCT_VARRAY_UINT8)
@@ -240,7 +252,7 @@ fn test_vmstate_struct_varray_uint8() {
#[test]
fn test_vmstate_struct_varray_uint32_multiply() {
- let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
// 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
// (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
@@ -266,7 +278,7 @@ fn test_vmstate_struct_varray_uint32_multiply() {
#[test]
fn test_vmstate_macro_array() {
- let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
// 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
// VMSTATE_ARRAY)
@@ -283,9 +295,26 @@ fn test_vmstate_macro_array() {
assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
assert!(foo_fields[4].vmsd.is_null());
assert!(foo_fields[4].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_struct_varray_uint8_wrapper() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
+ let mut foo_b: FooB = Default::default();
+ let foo_b_p = std::ptr::addr_of_mut!(foo_b).cast::<c_void>();
+
+ // 6th VMStateField ("arr_a_wrap") in VMSTATE_FOOB (corresponding to
+ // VMSTATE_STRUCT_VARRAY_UINT8). Other fields are checked in
+ // test_vmstate_struct_varray_uint8.
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[5].name) }.to_bytes_with_nul(),
+ b"arr_a_wrap\0"
+ );
+ assert_eq!(foo_fields[5].num_offset, 228);
+ assert!(unsafe { foo_fields[5].field_exists.unwrap()(foo_b_p, 0) });
// The last VMStateField in VMSTATE_FOOB.
- assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
+ assert_eq!(foo_fields[6].flags, VMStateFlags::VMS_END);
}
// =========================== Test VMSTATE_FOOC ===========================
@@ -299,7 +328,6 @@ struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array i
impl_vmstate_forward!(FooCWrapper);
#[repr(C)]
-#[derive(qemu_api_macros::offsets)]
struct FooC {
ptr: *const i32,
ptr_a: NonNull<FooA>,
@@ -308,7 +336,7 @@ struct FooC {
}
static VMSTATE_FOOC: VMStateDescription = VMStateDescription {
- name: c_str!("foo_c").as_ptr(),
+ name: c"foo_c".as_ptr(),
version_id: 3,
minimum_version_id: 1,
fields: vmstate_fields! {
@@ -423,13 +451,13 @@ fn validate_food_2(_state: &FooD, _version_id: u8) -> bool {
}
static VMSTATE_FOOD: VMStateDescription = VMStateDescription {
- name: c_str!("foo_d").as_ptr(),
+ name: c"foo_d".as_ptr(),
version_id: 3,
minimum_version_id: 1,
fields: vmstate_fields! {
- vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0),
- vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1),
- vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2),
+ vmstate_validate!(FooD, c"foo_d_0", FooD::validate_food_0),
+ vmstate_validate!(FooD, c"foo_d_1", FooD::validate_food_1),
+ vmstate_validate!(FooD, c"foo_d_2", validate_food_2),
},
..Zeroable::ZERO
};