diff options
| author | Zhao Liu <zhao1.liu@intel.com> | 2025-09-08 12:49:39 +0200 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2025-09-17 19:00:56 +0200 |
| commit | 7da9ee9207c55a783567eb46c71fa89cb5b43461 (patch) | |
| tree | c8c731f109dc2c0a82b4dbd2435bff9ec047ac2e /rust/qemu-api/tests | |
| parent | a71df7e143b57427c1f8a917654e7b0ed1ceb919 (diff) | |
| download | focaccia-qemu-7da9ee9207c55a783567eb46c71fa89cb5b43461.tar.gz focaccia-qemu-7da9ee9207c55a783567eb46c71fa89cb5b43461.zip | |
rust: vmstate: convert to use builder pattern
Similar to MemoryRegionOps, the builder pattern has two advantages: 1) it makes it possible to build a VMStateDescription that knows which types it will be invoked on; 2) it provides a way to wrap the callbacks and let devices avoid "unsafe". Unfortunately, building a static VMStateDescription requires the builder methods to be "const", and because the VMStateFields are *also* static, this requires const_refs_static. So this requires Rust 1.83.0. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Link: https://lore.kernel.org/r/20250908105005.2119297-8-pbonzini@redhat.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'rust/qemu-api/tests')
| -rw-r--r-- | rust/qemu-api/tests/tests.rs | 16 | ||||
| -rw-r--r-- | rust/qemu-api/tests/vmstate_tests.rs | 124 |
2 files changed, 75 insertions, 65 deletions
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index aff3eecd65..4d4e4653f3 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -11,18 +11,16 @@ use qemu_api::{ qdev::{DeviceImpl, DeviceState, ResettablePhasesImpl}, qom::{ObjectImpl, ParentField}, sysbus::SysBusDevice, - vmstate::VMStateDescription, - zeroable::Zeroable, + vmstate::{VMStateDescription, VMStateDescriptionBuilder}, }; mod vmstate_tests; // Test that macros can compile. -pub static VMSTATE: VMStateDescription = VMStateDescription { - name: c"name".as_ptr(), - unmigratable: true, - ..Zeroable::ZERO -}; +pub const VMSTATE: VMStateDescription<DummyState> = VMStateDescriptionBuilder::<DummyState>::new() + .name(c"name") + .unmigratable() + .build(); #[repr(C)] #[derive(qemu_api_macros::Object, qemu_api_macros::Device)] @@ -58,8 +56,8 @@ impl ObjectImpl for DummyState { impl ResettablePhasesImpl for DummyState {} impl DeviceImpl for DummyState { - fn vmsd() -> Option<&'static VMStateDescription> { - Some(&VMSTATE) + fn vmsd() -> Option<VMStateDescription<Self>> { + Some(VMSTATE) } } diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs index bded836eb6..8ffc2779d4 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -16,9 +16,8 @@ use qemu_api::{ }, cell::{BqlCell, Opaque}, impl_vmstate_forward, - vmstate::{VMStateDescription, VMStateField}, + vmstate::{VMStateDescription, VMStateDescriptionBuilder, VMStateField}, vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate, - zeroable::Zeroable, }; const FOO_ARRAY_MAX: usize = 3; @@ -41,22 +40,22 @@ struct FooA { elem: i8, } -static VMSTATE_FOOA: VMStateDescription = VMStateDescription { - name: c"foo_a".as_ptr(), - version_id: 1, - minimum_version_id: 1, - fields: vmstate_fields! { +static VMSTATE_FOOA: VMStateDescription<FooA> = VMStateDescriptionBuilder::<FooA>::new() + .name(c"foo_a") + .version_id(1) + .minimum_version_id(1) + .fields(vmstate_fields! { vmstate_of!(FooA, elem), vmstate_unused!(size_of::<i64>()), vmstate_of!(FooA, arr[0 .. num]).with_version_id(0), vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]), - }, - ..Zeroable::ZERO -}; + }) + .build(); #[test] fn test_vmstate_uint16() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16) assert_eq!( @@ -76,7 +75,8 @@ fn test_vmstate_uint16() { #[test] fn test_vmstate_unused() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED) assert_eq!( @@ -96,7 +96,8 @@ fn test_vmstate_unused() { #[test] fn test_vmstate_varray_uint16_unsafe() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to // VMSTATE_VARRAY_UINT16_UNSAFE) @@ -117,7 +118,8 @@ fn test_vmstate_varray_uint16_unsafe() { #[test] fn test_vmstate_varray_multiply() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to // VMSTATE_VARRAY_MULTIPLY) @@ -171,24 +173,25 @@ fn validate_foob(_state: &FooB, _version_id: u8) -> bool { true } -static VMSTATE_FOOB: VMStateDescription = VMStateDescription { - name: c"foo_b".as_ptr(), - version_id: 2, - minimum_version_id: 1, - fields: vmstate_fields! { - vmstate_of!(FooB, val).with_version_id(2), - vmstate_of!(FooB, wrap), - 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 -}; +static VMSTATE_FOOB: VMStateDescription<FooB> = + VMStateDescriptionBuilder::<FooB>::new() + .name(c"foo_b") + .version_id(2) + .minimum_version_id(1) + .fields(vmstate_fields! { + vmstate_of!(FooB, val).with_version_id(2), + vmstate_of!(FooB, wrap), + 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), + }) + .build(); #[test] fn test_vmstate_bool_v() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V) assert_eq!( @@ -208,7 +211,8 @@ fn test_vmstate_bool_v() { #[test] fn test_vmstate_uint64() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64) assert_eq!( @@ -228,7 +232,8 @@ fn test_vmstate_uint64() { #[test] fn test_vmstate_struct_varray_uint8() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to // VMSTATE_STRUCT_VARRAY_UINT8) @@ -246,13 +251,14 @@ fn test_vmstate_struct_varray_uint8() { foo_fields[2].flags.0, VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0 ); - assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA); + assert_eq!(foo_fields[2].vmsd, VMSTATE_FOOA.as_ref()); assert!(foo_fields[2].field_exists.is_none()); } #[test] fn test_vmstate_struct_varray_uint32_multiply() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32) @@ -272,13 +278,14 @@ fn test_vmstate_struct_varray_uint32_multiply() { | VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 ); - assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA); + assert_eq!(foo_fields[3].vmsd, VMSTATE_FOOA.as_ref()); assert!(foo_fields[3].field_exists.is_none()); } #[test] fn test_vmstate_macro_array() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to // VMSTATE_ARRAY) @@ -299,7 +306,8 @@ fn test_vmstate_macro_array() { #[test] fn test_vmstate_struct_varray_uint8_wrapper() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; let mut foo_b: FooB = Default::default(); let foo_b_p = std::ptr::addr_of_mut!(foo_b).cast::<c_void>(); @@ -335,26 +343,28 @@ struct FooC { arr_ptr_wrap: FooCWrapper, } -static VMSTATE_FOOC: VMStateDescription = VMStateDescription { - name: c"foo_c".as_ptr(), - version_id: 3, - minimum_version_id: 1, - fields: vmstate_fields! { +unsafe impl Sync for FooC {} + +static VMSTATE_FOOC: VMStateDescription<FooC> = VMStateDescriptionBuilder::<FooC>::new() + .name(c"foo_c") + .version_id(3) + .minimum_version_id(1) + .fields(vmstate_fields! { vmstate_of!(FooC, ptr).with_version_id(2), // FIXME: Currently vmstate_struct doesn't support the pointer to structure. // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>) vmstate_unused!(size_of::<NonNull<FooA>>()), vmstate_of!(FooC, arr_ptr), vmstate_of!(FooC, arr_ptr_wrap), - }, - ..Zeroable::ZERO -}; + }) + .build(); const PTR_SIZE: usize = size_of::<*mut ()>(); #[test] fn test_vmstate_pointer() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER) assert_eq!( @@ -377,7 +387,8 @@ fn test_vmstate_pointer() { #[test] fn test_vmstate_macro_array_of_pointer() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to // VMSTATE_ARRAY_OF_POINTER) @@ -401,7 +412,8 @@ fn test_vmstate_macro_array_of_pointer() { #[test] fn test_vmstate_macro_array_of_pointer_wrapped() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to // VMSTATE_ARRAY_OF_POINTER) @@ -450,21 +462,21 @@ fn validate_food_2(_state: &FooD, _version_id: u8) -> bool { true } -static VMSTATE_FOOD: VMStateDescription = VMStateDescription { - name: c"foo_d".as_ptr(), - version_id: 3, - minimum_version_id: 1, - fields: vmstate_fields! { +static VMSTATE_FOOD: VMStateDescription<FooD> = VMStateDescriptionBuilder::<FooD>::new() + .name(c"foo_d") + .version_id(3) + .minimum_version_id(1) + .fields(vmstate_fields! { 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 -}; + }) + .build(); #[test] fn test_vmstate_validate() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) }; + let foo_fields: &[VMStateField] = + unsafe { slice::from_raw_parts(VMSTATE_FOOD.as_ref().fields, 4) }; let mut foo_d = FooD; let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>(); |