22// Author(s): Zhao Liu <[email protected] > 33// SPDX-License-Identifier: GPL-2.0-or-later
44
5- use std:: { ffi:: CStr , mem:: size_of, ptr:: NonNull , slice} ;
5+ use std:: { ffi:: CStr , mem:: size_of, os :: raw :: c_void , ptr:: NonNull , slice} ;
66
77use qemu_api:: {
88 bindings:: {
@@ -13,7 +13,7 @@ use qemu_api::{
1313 cell:: { BqlCell , Opaque } ,
1414 impl_vmstate_forward,
1515 vmstate:: { VMStateDescription , VMStateField } ,
16- vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused,
16+ vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate ,
1717 zeroable:: Zeroable ,
1818} ;
1919
@@ -397,3 +397,81 @@ fn test_vmstate_macro_array_of_pointer_wrapped() {
397397 // The last VMStateField in VMSTATE_FOOC.
398398 assert_eq ! ( foo_fields[ 4 ] . flags, VMStateFlags :: VMS_END ) ;
399399}
400+
401+ // =========================== Test VMSTATE_FOOD ===========================
402+ // Test the use cases of the vmstate macro, corresponding to the following C
403+ // macro variants:
404+ // * VMSTATE_FOOD:
405+ // - VMSTATE_VALIDATE
406+
407+ // Add more member fields when vmstate_of/vmstate_struct support "test"
408+ // parameter.
409+ struct FooD ;
410+
411+ impl FooD {
412+ fn validate_food_0 ( & self , _version_id : u8 ) -> bool {
413+ true
414+ }
415+
416+ fn validate_food_1 ( _state : & FooD , _version_id : u8 ) -> bool {
417+ false
418+ }
419+ }
420+
421+ fn validate_food_2 ( _state : & FooD , _version_id : u8 ) -> bool {
422+ true
423+ }
424+
425+ static VMSTATE_FOOD : VMStateDescription = VMStateDescription {
426+ name : c_str ! ( "foo_d" ) . as_ptr ( ) ,
427+ version_id : 3 ,
428+ minimum_version_id : 1 ,
429+ fields : vmstate_fields ! {
430+ vmstate_validate!( FooD , c_str!( "foo_d_0" ) , FooD :: validate_food_0) ,
431+ vmstate_validate!( FooD , c_str!( "foo_d_1" ) , FooD :: validate_food_1) ,
432+ vmstate_validate!( FooD , c_str!( "foo_d_2" ) , validate_food_2) ,
433+ } ,
434+ ..Zeroable :: ZERO
435+ } ;
436+
437+ #[ test]
438+ fn test_vmstate_validate ( ) {
439+ let foo_fields: & [ VMStateField ] = unsafe { slice:: from_raw_parts ( VMSTATE_FOOD . fields , 4 ) } ;
440+ let mut foo_d = FooD ;
441+ let foo_d_p = std:: ptr:: addr_of_mut!( foo_d) . cast :: < c_void > ( ) ;
442+
443+ // 1st VMStateField in VMSTATE_FOOD
444+ assert_eq ! (
445+ unsafe { CStr :: from_ptr( foo_fields[ 0 ] . name) } . to_bytes_with_nul( ) ,
446+ b"foo_d_0\0 "
447+ ) ;
448+ assert_eq ! ( foo_fields[ 0 ] . offset, 0 ) ;
449+ assert_eq ! ( foo_fields[ 0 ] . num_offset, 0 ) ;
450+ assert ! ( foo_fields[ 0 ] . info. is_null( ) ) ;
451+ assert_eq ! ( foo_fields[ 0 ] . version_id, 0 ) ;
452+ assert_eq ! ( foo_fields[ 0 ] . size, 0 ) ;
453+ assert_eq ! ( foo_fields[ 0 ] . num, 0 ) ;
454+ assert_eq ! (
455+ foo_fields[ 0 ] . flags. 0 ,
456+ VMStateFlags :: VMS_ARRAY . 0 | VMStateFlags :: VMS_MUST_EXIST . 0
457+ ) ;
458+ assert ! ( foo_fields[ 0 ] . vmsd. is_null( ) ) ;
459+ assert ! ( unsafe { foo_fields[ 0 ] . field_exists. unwrap( ) ( foo_d_p, 0 ) } ) ;
460+
461+ // 2nd VMStateField in VMSTATE_FOOD
462+ assert_eq ! (
463+ unsafe { CStr :: from_ptr( foo_fields[ 1 ] . name) } . to_bytes_with_nul( ) ,
464+ b"foo_d_1\0 "
465+ ) ;
466+ assert ! ( !unsafe { foo_fields[ 1 ] . field_exists. unwrap( ) ( foo_d_p, 1 ) } ) ;
467+
468+ // 3rd VMStateField in VMSTATE_FOOD
469+ assert_eq ! (
470+ unsafe { CStr :: from_ptr( foo_fields[ 2 ] . name) } . to_bytes_with_nul( ) ,
471+ b"foo_d_2\0 "
472+ ) ;
473+ assert ! ( unsafe { foo_fields[ 2 ] . field_exists. unwrap( ) ( foo_d_p, 2 ) } ) ;
474+
475+ // The last VMStateField in VMSTATE_FOOD.
476+ assert_eq ! ( foo_fields[ 3 ] . flags, VMStateFlags :: VMS_END ) ;
477+ }
0 commit comments