xref: /qemu/rust/qemu-api/tests/vmstate_tests.rs (revision 8df1b0012aba2501bb1654cb4fbdf1b52ce22222)
119985021SZhao Liu // Copyright (C) 2025 Intel Corporation.
219985021SZhao Liu // Author(s): Zhao Liu <zhai1.liu@intel.com>
319985021SZhao Liu // SPDX-License-Identifier: GPL-2.0-or-later
419985021SZhao Liu 
5*8df1b001SZhao Liu use std::{ffi::CStr, mem::size_of, ptr::NonNull, slice};
619985021SZhao Liu 
719985021SZhao Liu use qemu_api::{
857c327f3SZhao Liu     bindings::{
9*8df1b001SZhao Liu         vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8,
10*8df1b001SZhao Liu         vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
1157c327f3SZhao Liu     },
1219985021SZhao Liu     c_str,
13*8df1b001SZhao Liu     cell::{BqlCell, Opaque},
14*8df1b001SZhao Liu     impl_vmstate_forward,
1519985021SZhao Liu     vmstate::{VMStateDescription, VMStateField},
1657c327f3SZhao Liu     vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused,
1719985021SZhao Liu     zeroable::Zeroable,
1819985021SZhao Liu };
1919985021SZhao Liu 
2019985021SZhao Liu const FOO_ARRAY_MAX: usize = 3;
2119985021SZhao Liu 
2219985021SZhao Liu // =========================== Test VMSTATE_FOOA ===========================
2319985021SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
2419985021SZhao Liu // macro variants:
2519985021SZhao Liu //   * VMSTATE_FOOA:
2619985021SZhao Liu //     - VMSTATE_U16
2719985021SZhao Liu //     - VMSTATE_UNUSED
2819985021SZhao Liu //     - VMSTATE_VARRAY_UINT16_UNSAFE
2919985021SZhao Liu //     - VMSTATE_VARRAY_MULTIPLY
3019985021SZhao Liu #[repr(C)]
3119985021SZhao Liu #[derive(qemu_api_macros::offsets)]
3219985021SZhao Liu struct FooA {
3319985021SZhao Liu     arr: [u8; FOO_ARRAY_MAX],
3419985021SZhao Liu     num: u16,
3519985021SZhao Liu     arr_mul: [i8; FOO_ARRAY_MAX],
3619985021SZhao Liu     num_mul: u32,
3719985021SZhao Liu     elem: i8,
3819985021SZhao Liu }
3919985021SZhao Liu 
4019985021SZhao Liu static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
4119985021SZhao Liu     name: c_str!("foo_a").as_ptr(),
4219985021SZhao Liu     version_id: 1,
4319985021SZhao Liu     minimum_version_id: 1,
4419985021SZhao Liu     fields: vmstate_fields! {
4519985021SZhao Liu         vmstate_of!(FooA, elem),
4619985021SZhao Liu         vmstate_unused!(size_of::<i64>()),
4719985021SZhao Liu         vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
4819985021SZhao Liu         vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
4919985021SZhao Liu     },
5019985021SZhao Liu     ..Zeroable::ZERO
5119985021SZhao Liu };
5219985021SZhao Liu 
5319985021SZhao Liu #[test]
5419985021SZhao Liu fn test_vmstate_uint16() {
5519985021SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
5619985021SZhao Liu 
5719985021SZhao Liu     // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
5819985021SZhao Liu     assert_eq!(
5919985021SZhao Liu         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
6019985021SZhao Liu         b"elem\0"
6119985021SZhao Liu     );
6219985021SZhao Liu     assert_eq!(foo_fields[0].offset, 16);
6319985021SZhao Liu     assert_eq!(foo_fields[0].num_offset, 0);
6419985021SZhao Liu     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
6519985021SZhao Liu     assert_eq!(foo_fields[0].version_id, 0);
6619985021SZhao Liu     assert_eq!(foo_fields[0].size, 1);
6719985021SZhao Liu     assert_eq!(foo_fields[0].num, 0);
6819985021SZhao Liu     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
6919985021SZhao Liu     assert!(foo_fields[0].vmsd.is_null());
7019985021SZhao Liu     assert!(foo_fields[0].field_exists.is_none());
7119985021SZhao Liu }
7219985021SZhao Liu 
7319985021SZhao Liu #[test]
7419985021SZhao Liu fn test_vmstate_unused() {
7519985021SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
7619985021SZhao Liu 
7719985021SZhao Liu     // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
7819985021SZhao Liu     assert_eq!(
7919985021SZhao Liu         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
8019985021SZhao Liu         b"unused\0"
8119985021SZhao Liu     );
8219985021SZhao Liu     assert_eq!(foo_fields[1].offset, 0);
8319985021SZhao Liu     assert_eq!(foo_fields[1].num_offset, 0);
8419985021SZhao Liu     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
8519985021SZhao Liu     assert_eq!(foo_fields[1].version_id, 0);
8619985021SZhao Liu     assert_eq!(foo_fields[1].size, 8);
8719985021SZhao Liu     assert_eq!(foo_fields[1].num, 0);
8819985021SZhao Liu     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
8919985021SZhao Liu     assert!(foo_fields[1].vmsd.is_null());
9019985021SZhao Liu     assert!(foo_fields[1].field_exists.is_none());
9119985021SZhao Liu }
9219985021SZhao Liu 
9319985021SZhao Liu #[test]
9419985021SZhao Liu fn test_vmstate_varray_uint16_unsafe() {
9519985021SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
9619985021SZhao Liu 
9719985021SZhao Liu     // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
9819985021SZhao Liu     // VMSTATE_VARRAY_UINT16_UNSAFE)
9919985021SZhao Liu     assert_eq!(
10019985021SZhao Liu         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
10119985021SZhao Liu         b"arr\0"
10219985021SZhao Liu     );
10319985021SZhao Liu     assert_eq!(foo_fields[2].offset, 0);
10419985021SZhao Liu     assert_eq!(foo_fields[2].num_offset, 4);
10519985021SZhao Liu     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
10619985021SZhao Liu     assert_eq!(foo_fields[2].version_id, 0);
10719985021SZhao Liu     assert_eq!(foo_fields[2].size, 1);
10819985021SZhao Liu     assert_eq!(foo_fields[2].num, 0);
10919985021SZhao Liu     assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
11019985021SZhao Liu     assert!(foo_fields[2].vmsd.is_null());
11119985021SZhao Liu     assert!(foo_fields[2].field_exists.is_none());
11219985021SZhao Liu }
11319985021SZhao Liu 
11419985021SZhao Liu #[test]
11519985021SZhao Liu fn test_vmstate_varray_multiply() {
11619985021SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
11719985021SZhao Liu 
11819985021SZhao Liu     // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
11919985021SZhao Liu     // VMSTATE_VARRAY_MULTIPLY)
12019985021SZhao Liu     assert_eq!(
12119985021SZhao Liu         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
12219985021SZhao Liu         b"arr_mul\0"
12319985021SZhao Liu     );
12419985021SZhao Liu     assert_eq!(foo_fields[3].offset, 6);
12519985021SZhao Liu     assert_eq!(foo_fields[3].num_offset, 12);
12619985021SZhao Liu     assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
12719985021SZhao Liu     assert_eq!(foo_fields[3].version_id, 0);
12819985021SZhao Liu     assert_eq!(foo_fields[3].size, 1);
12919985021SZhao Liu     assert_eq!(foo_fields[3].num, 16);
13019985021SZhao Liu     assert_eq!(
13119985021SZhao Liu         foo_fields[3].flags.0,
13219985021SZhao Liu         VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
13319985021SZhao Liu     );
13419985021SZhao Liu     assert!(foo_fields[3].vmsd.is_null());
13519985021SZhao Liu     assert!(foo_fields[3].field_exists.is_none());
13619985021SZhao Liu 
13719985021SZhao Liu     // The last VMStateField in VMSTATE_FOOA.
13819985021SZhao Liu     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
13919985021SZhao Liu }
14057c327f3SZhao Liu 
14157c327f3SZhao Liu // =========================== Test VMSTATE_FOOB ===========================
14257c327f3SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
14357c327f3SZhao Liu // macro variants:
14457c327f3SZhao Liu //   * VMSTATE_FOOB:
14557c327f3SZhao Liu //     - VMSTATE_BOOL_V
14657c327f3SZhao Liu //     - VMSTATE_U64
14757c327f3SZhao Liu //     - VMSTATE_STRUCT_VARRAY_UINT8
14857c327f3SZhao Liu //     - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
14957c327f3SZhao Liu //     - VMSTATE_ARRAY
15057c327f3SZhao Liu #[repr(C)]
15157c327f3SZhao Liu #[derive(qemu_api_macros::offsets)]
15257c327f3SZhao Liu struct FooB {
15357c327f3SZhao Liu     arr_a: [FooA; FOO_ARRAY_MAX],
15457c327f3SZhao Liu     num_a: u8,
15557c327f3SZhao Liu     arr_a_mul: [FooA; FOO_ARRAY_MAX],
15657c327f3SZhao Liu     num_a_mul: u32,
15757c327f3SZhao Liu     wrap: BqlCell<u64>,
15857c327f3SZhao Liu     val: bool,
15957c327f3SZhao Liu     // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
16057c327f3SZhao Liu     arr_i64: [i64; FOO_ARRAY_MAX],
16157c327f3SZhao Liu }
16257c327f3SZhao Liu 
16357c327f3SZhao Liu static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
16457c327f3SZhao Liu     name: c_str!("foo_b").as_ptr(),
16557c327f3SZhao Liu     version_id: 2,
16657c327f3SZhao Liu     minimum_version_id: 1,
16757c327f3SZhao Liu     fields: vmstate_fields! {
16857c327f3SZhao Liu         vmstate_of!(FooB, val).with_version_id(2),
16957c327f3SZhao Liu         vmstate_of!(FooB, wrap),
17057c327f3SZhao Liu         vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
17157c327f3SZhao Liu         vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
17257c327f3SZhao Liu         vmstate_of!(FooB, arr_i64),
17357c327f3SZhao Liu     },
17457c327f3SZhao Liu     ..Zeroable::ZERO
17557c327f3SZhao Liu };
17657c327f3SZhao Liu 
17757c327f3SZhao Liu #[test]
17857c327f3SZhao Liu fn test_vmstate_bool_v() {
17957c327f3SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
18057c327f3SZhao Liu 
18157c327f3SZhao Liu     // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
18257c327f3SZhao Liu     assert_eq!(
18357c327f3SZhao Liu         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
18457c327f3SZhao Liu         b"val\0"
18557c327f3SZhao Liu     );
18657c327f3SZhao Liu     assert_eq!(foo_fields[0].offset, 136);
18757c327f3SZhao Liu     assert_eq!(foo_fields[0].num_offset, 0);
18857c327f3SZhao Liu     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
18957c327f3SZhao Liu     assert_eq!(foo_fields[0].version_id, 2);
19057c327f3SZhao Liu     assert_eq!(foo_fields[0].size, 1);
19157c327f3SZhao Liu     assert_eq!(foo_fields[0].num, 0);
19257c327f3SZhao Liu     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
19357c327f3SZhao Liu     assert!(foo_fields[0].vmsd.is_null());
19457c327f3SZhao Liu     assert!(foo_fields[0].field_exists.is_none());
19557c327f3SZhao Liu }
19657c327f3SZhao Liu 
19757c327f3SZhao Liu #[test]
19857c327f3SZhao Liu fn test_vmstate_uint64() {
19957c327f3SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
20057c327f3SZhao Liu 
20157c327f3SZhao Liu     // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
20257c327f3SZhao Liu     assert_eq!(
20357c327f3SZhao Liu         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
20457c327f3SZhao Liu         b"wrap\0"
20557c327f3SZhao Liu     );
20657c327f3SZhao Liu     assert_eq!(foo_fields[1].offset, 128);
20757c327f3SZhao Liu     assert_eq!(foo_fields[1].num_offset, 0);
20857c327f3SZhao Liu     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
20957c327f3SZhao Liu     assert_eq!(foo_fields[1].version_id, 0);
21057c327f3SZhao Liu     assert_eq!(foo_fields[1].size, 8);
21157c327f3SZhao Liu     assert_eq!(foo_fields[1].num, 0);
21257c327f3SZhao Liu     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
21357c327f3SZhao Liu     assert!(foo_fields[1].vmsd.is_null());
21457c327f3SZhao Liu     assert!(foo_fields[1].field_exists.is_none());
21557c327f3SZhao Liu }
21657c327f3SZhao Liu 
21757c327f3SZhao Liu #[test]
21857c327f3SZhao Liu fn test_vmstate_struct_varray_uint8() {
21957c327f3SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
22057c327f3SZhao Liu 
22157c327f3SZhao Liu     // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
22257c327f3SZhao Liu     // VMSTATE_STRUCT_VARRAY_UINT8)
22357c327f3SZhao Liu     assert_eq!(
22457c327f3SZhao Liu         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
22557c327f3SZhao Liu         b"arr_a\0"
22657c327f3SZhao Liu     );
22757c327f3SZhao Liu     assert_eq!(foo_fields[2].offset, 0);
22857c327f3SZhao Liu     assert_eq!(foo_fields[2].num_offset, 60);
22957c327f3SZhao Liu     assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
23057c327f3SZhao Liu     assert_eq!(foo_fields[2].version_id, 1);
23157c327f3SZhao Liu     assert_eq!(foo_fields[2].size, 20);
23257c327f3SZhao Liu     assert_eq!(foo_fields[2].num, 0);
23357c327f3SZhao Liu     assert_eq!(
23457c327f3SZhao Liu         foo_fields[2].flags.0,
23557c327f3SZhao Liu         VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
23657c327f3SZhao Liu     );
23757c327f3SZhao Liu     assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
23857c327f3SZhao Liu     assert!(foo_fields[2].field_exists.is_none());
23957c327f3SZhao Liu }
24057c327f3SZhao Liu 
24157c327f3SZhao Liu #[test]
24257c327f3SZhao Liu fn test_vmstate_struct_varray_uint32_multiply() {
24357c327f3SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
24457c327f3SZhao Liu 
24557c327f3SZhao Liu     // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
24657c327f3SZhao Liu     // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
24757c327f3SZhao Liu     assert_eq!(
24857c327f3SZhao Liu         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
24957c327f3SZhao Liu         b"arr_a_mul\0"
25057c327f3SZhao Liu     );
25157c327f3SZhao Liu     assert_eq!(foo_fields[3].offset, 64);
25257c327f3SZhao Liu     assert_eq!(foo_fields[3].num_offset, 124);
25357c327f3SZhao Liu     assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
25457c327f3SZhao Liu     assert_eq!(foo_fields[3].version_id, 2);
25557c327f3SZhao Liu     assert_eq!(foo_fields[3].size, 20);
25657c327f3SZhao Liu     assert_eq!(foo_fields[3].num, 32);
25757c327f3SZhao Liu     assert_eq!(
25857c327f3SZhao Liu         foo_fields[3].flags.0,
25957c327f3SZhao Liu         VMStateFlags::VMS_STRUCT.0
26057c327f3SZhao Liu             | VMStateFlags::VMS_VARRAY_UINT32.0
26157c327f3SZhao Liu             | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
26257c327f3SZhao Liu     );
26357c327f3SZhao Liu     assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
26457c327f3SZhao Liu     assert!(foo_fields[3].field_exists.is_none());
26557c327f3SZhao Liu }
26657c327f3SZhao Liu 
26757c327f3SZhao Liu #[test]
26857c327f3SZhao Liu fn test_vmstate_macro_array() {
26957c327f3SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
27057c327f3SZhao Liu 
27157c327f3SZhao Liu     // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
27257c327f3SZhao Liu     // VMSTATE_ARRAY)
27357c327f3SZhao Liu     assert_eq!(
27457c327f3SZhao Liu         unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
27557c327f3SZhao Liu         b"arr_i64\0"
27657c327f3SZhao Liu     );
27757c327f3SZhao Liu     assert_eq!(foo_fields[4].offset, 144);
27857c327f3SZhao Liu     assert_eq!(foo_fields[4].num_offset, 0);
27957c327f3SZhao Liu     assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
28057c327f3SZhao Liu     assert_eq!(foo_fields[4].version_id, 0);
28157c327f3SZhao Liu     assert_eq!(foo_fields[4].size, 8);
28257c327f3SZhao Liu     assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
28357c327f3SZhao Liu     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
28457c327f3SZhao Liu     assert!(foo_fields[4].vmsd.is_null());
28557c327f3SZhao Liu     assert!(foo_fields[4].field_exists.is_none());
28657c327f3SZhao Liu 
28757c327f3SZhao Liu     // The last VMStateField in VMSTATE_FOOB.
28857c327f3SZhao Liu     assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
28957c327f3SZhao Liu }
290*8df1b001SZhao Liu 
291*8df1b001SZhao Liu // =========================== Test VMSTATE_FOOC ===========================
292*8df1b001SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
293*8df1b001SZhao Liu // macro variants:
294*8df1b001SZhao Liu //   * VMSTATE_FOOC:
295*8df1b001SZhao Liu //     - VMSTATE_POINTER
296*8df1b001SZhao Liu //     - VMSTATE_ARRAY_OF_POINTER
297*8df1b001SZhao Liu struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible.
298*8df1b001SZhao Liu 
299*8df1b001SZhao Liu impl_vmstate_forward!(FooCWrapper);
300*8df1b001SZhao Liu 
301*8df1b001SZhao Liu #[repr(C)]
302*8df1b001SZhao Liu #[derive(qemu_api_macros::offsets)]
303*8df1b001SZhao Liu struct FooC {
304*8df1b001SZhao Liu     ptr: *const i32,
305*8df1b001SZhao Liu     ptr_a: NonNull<FooA>,
306*8df1b001SZhao Liu     arr_ptr: [Box<u8>; FOO_ARRAY_MAX],
307*8df1b001SZhao Liu     arr_ptr_wrap: FooCWrapper,
308*8df1b001SZhao Liu }
309*8df1b001SZhao Liu 
310*8df1b001SZhao Liu static VMSTATE_FOOC: VMStateDescription = VMStateDescription {
311*8df1b001SZhao Liu     name: c_str!("foo_c").as_ptr(),
312*8df1b001SZhao Liu     version_id: 3,
313*8df1b001SZhao Liu     minimum_version_id: 1,
314*8df1b001SZhao Liu     fields: vmstate_fields! {
315*8df1b001SZhao Liu         vmstate_of!(FooC, ptr).with_version_id(2),
316*8df1b001SZhao Liu         // FIXME: Currently vmstate_struct doesn't support the pointer to structure.
317*8df1b001SZhao Liu         // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>)
318*8df1b001SZhao Liu         vmstate_unused!(size_of::<NonNull<FooA>>()),
319*8df1b001SZhao Liu         vmstate_of!(FooC, arr_ptr),
320*8df1b001SZhao Liu         vmstate_of!(FooC, arr_ptr_wrap),
321*8df1b001SZhao Liu     },
322*8df1b001SZhao Liu     ..Zeroable::ZERO
323*8df1b001SZhao Liu };
324*8df1b001SZhao Liu 
325*8df1b001SZhao Liu const PTR_SIZE: usize = size_of::<*mut ()>();
326*8df1b001SZhao Liu 
327*8df1b001SZhao Liu #[test]
328*8df1b001SZhao Liu fn test_vmstate_pointer() {
329*8df1b001SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
330*8df1b001SZhao Liu 
331*8df1b001SZhao Liu     // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER)
332*8df1b001SZhao Liu     assert_eq!(
333*8df1b001SZhao Liu         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
334*8df1b001SZhao Liu         b"ptr\0"
335*8df1b001SZhao Liu     );
336*8df1b001SZhao Liu     assert_eq!(foo_fields[0].offset, 0);
337*8df1b001SZhao Liu     assert_eq!(foo_fields[0].num_offset, 0);
338*8df1b001SZhao Liu     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 });
339*8df1b001SZhao Liu     assert_eq!(foo_fields[0].version_id, 2);
340*8df1b001SZhao Liu     assert_eq!(foo_fields[0].size, 4);
341*8df1b001SZhao Liu     assert_eq!(foo_fields[0].num, 0);
342*8df1b001SZhao Liu     assert_eq!(
343*8df1b001SZhao Liu         foo_fields[0].flags.0,
344*8df1b001SZhao Liu         VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0
345*8df1b001SZhao Liu     );
346*8df1b001SZhao Liu     assert!(foo_fields[0].vmsd.is_null());
347*8df1b001SZhao Liu     assert!(foo_fields[0].field_exists.is_none());
348*8df1b001SZhao Liu }
349*8df1b001SZhao Liu 
350*8df1b001SZhao Liu #[test]
351*8df1b001SZhao Liu fn test_vmstate_macro_array_of_pointer() {
352*8df1b001SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
353*8df1b001SZhao Liu 
354*8df1b001SZhao Liu     // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to
355*8df1b001SZhao Liu     // VMSTATE_ARRAY_OF_POINTER)
356*8df1b001SZhao Liu     assert_eq!(
357*8df1b001SZhao Liu         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
358*8df1b001SZhao Liu         b"arr_ptr\0"
359*8df1b001SZhao Liu     );
360*8df1b001SZhao Liu     assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE);
361*8df1b001SZhao Liu     assert_eq!(foo_fields[2].num_offset, 0);
362*8df1b001SZhao Liu     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
363*8df1b001SZhao Liu     assert_eq!(foo_fields[2].version_id, 0);
364*8df1b001SZhao Liu     assert_eq!(foo_fields[2].size, PTR_SIZE);
365*8df1b001SZhao Liu     assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32);
366*8df1b001SZhao Liu     assert_eq!(
367*8df1b001SZhao Liu         foo_fields[2].flags.0,
368*8df1b001SZhao Liu         VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
369*8df1b001SZhao Liu     );
370*8df1b001SZhao Liu     assert!(foo_fields[2].vmsd.is_null());
371*8df1b001SZhao Liu     assert!(foo_fields[2].field_exists.is_none());
372*8df1b001SZhao Liu }
373*8df1b001SZhao Liu 
374*8df1b001SZhao Liu #[test]
375*8df1b001SZhao Liu fn test_vmstate_macro_array_of_pointer_wrapped() {
376*8df1b001SZhao Liu     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
377*8df1b001SZhao Liu 
378*8df1b001SZhao Liu     // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to
379*8df1b001SZhao Liu     // VMSTATE_ARRAY_OF_POINTER)
380*8df1b001SZhao Liu     assert_eq!(
381*8df1b001SZhao Liu         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
382*8df1b001SZhao Liu         b"arr_ptr_wrap\0"
383*8df1b001SZhao Liu     );
384*8df1b001SZhao Liu     assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
385*8df1b001SZhao Liu     assert_eq!(foo_fields[3].num_offset, 0);
386*8df1b001SZhao Liu     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
387*8df1b001SZhao Liu     assert_eq!(foo_fields[3].version_id, 0);
388*8df1b001SZhao Liu     assert_eq!(foo_fields[3].size, PTR_SIZE);
389*8df1b001SZhao Liu     assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32);
390*8df1b001SZhao Liu     assert_eq!(
391*8df1b001SZhao Liu         foo_fields[2].flags.0,
392*8df1b001SZhao Liu         VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
393*8df1b001SZhao Liu     );
394*8df1b001SZhao Liu     assert!(foo_fields[3].vmsd.is_null());
395*8df1b001SZhao Liu     assert!(foo_fields[3].field_exists.is_none());
396*8df1b001SZhao Liu 
397*8df1b001SZhao Liu     // The last VMStateField in VMSTATE_FOOC.
398*8df1b001SZhao Liu     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
399*8df1b001SZhao Liu }
400