2
0

vmstate_tests.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. // Copyright (C) 2025 Intel Corporation.
  2. // Author(s): Zhao Liu <zhai1.liu@intel.com>
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. use std::{ffi::CStr, mem::size_of, os::raw::c_void, ptr::NonNull, slice};
  5. use qemu_api::{
  6. bindings::{
  7. vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8,
  8. vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
  9. },
  10. c_str,
  11. cell::{BqlCell, Opaque},
  12. impl_vmstate_forward,
  13. vmstate::{VMStateDescription, VMStateField},
  14. vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate,
  15. zeroable::Zeroable,
  16. };
  17. const FOO_ARRAY_MAX: usize = 3;
  18. // =========================== Test VMSTATE_FOOA ===========================
  19. // Test the use cases of the vmstate macro, corresponding to the following C
  20. // macro variants:
  21. // * VMSTATE_FOOA:
  22. // - VMSTATE_U16
  23. // - VMSTATE_UNUSED
  24. // - VMSTATE_VARRAY_UINT16_UNSAFE
  25. // - VMSTATE_VARRAY_MULTIPLY
  26. #[repr(C)]
  27. #[derive(qemu_api_macros::offsets)]
  28. struct FooA {
  29. arr: [u8; FOO_ARRAY_MAX],
  30. num: u16,
  31. arr_mul: [i8; FOO_ARRAY_MAX],
  32. num_mul: u32,
  33. elem: i8,
  34. }
  35. static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
  36. name: c_str!("foo_a").as_ptr(),
  37. version_id: 1,
  38. minimum_version_id: 1,
  39. fields: vmstate_fields! {
  40. vmstate_of!(FooA, elem),
  41. vmstate_unused!(size_of::<i64>()),
  42. vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
  43. vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
  44. },
  45. ..Zeroable::ZERO
  46. };
  47. #[test]
  48. fn test_vmstate_uint16() {
  49. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
  50. // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
  51. assert_eq!(
  52. unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
  53. b"elem\0"
  54. );
  55. assert_eq!(foo_fields[0].offset, 16);
  56. assert_eq!(foo_fields[0].num_offset, 0);
  57. assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
  58. assert_eq!(foo_fields[0].version_id, 0);
  59. assert_eq!(foo_fields[0].size, 1);
  60. assert_eq!(foo_fields[0].num, 0);
  61. assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
  62. assert!(foo_fields[0].vmsd.is_null());
  63. assert!(foo_fields[0].field_exists.is_none());
  64. }
  65. #[test]
  66. fn test_vmstate_unused() {
  67. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
  68. // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
  69. assert_eq!(
  70. unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
  71. b"unused\0"
  72. );
  73. assert_eq!(foo_fields[1].offset, 0);
  74. assert_eq!(foo_fields[1].num_offset, 0);
  75. assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
  76. assert_eq!(foo_fields[1].version_id, 0);
  77. assert_eq!(foo_fields[1].size, 8);
  78. assert_eq!(foo_fields[1].num, 0);
  79. assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
  80. assert!(foo_fields[1].vmsd.is_null());
  81. assert!(foo_fields[1].field_exists.is_none());
  82. }
  83. #[test]
  84. fn test_vmstate_varray_uint16_unsafe() {
  85. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
  86. // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
  87. // VMSTATE_VARRAY_UINT16_UNSAFE)
  88. assert_eq!(
  89. unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
  90. b"arr\0"
  91. );
  92. assert_eq!(foo_fields[2].offset, 0);
  93. assert_eq!(foo_fields[2].num_offset, 4);
  94. assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
  95. assert_eq!(foo_fields[2].version_id, 0);
  96. assert_eq!(foo_fields[2].size, 1);
  97. assert_eq!(foo_fields[2].num, 0);
  98. assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
  99. assert!(foo_fields[2].vmsd.is_null());
  100. assert!(foo_fields[2].field_exists.is_none());
  101. }
  102. #[test]
  103. fn test_vmstate_varray_multiply() {
  104. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
  105. // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
  106. // VMSTATE_VARRAY_MULTIPLY)
  107. assert_eq!(
  108. unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
  109. b"arr_mul\0"
  110. );
  111. assert_eq!(foo_fields[3].offset, 6);
  112. assert_eq!(foo_fields[3].num_offset, 12);
  113. assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
  114. assert_eq!(foo_fields[3].version_id, 0);
  115. assert_eq!(foo_fields[3].size, 1);
  116. assert_eq!(foo_fields[3].num, 16);
  117. assert_eq!(
  118. foo_fields[3].flags.0,
  119. VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
  120. );
  121. assert!(foo_fields[3].vmsd.is_null());
  122. assert!(foo_fields[3].field_exists.is_none());
  123. // The last VMStateField in VMSTATE_FOOA.
  124. assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
  125. }
  126. // =========================== Test VMSTATE_FOOB ===========================
  127. // Test the use cases of the vmstate macro, corresponding to the following C
  128. // macro variants:
  129. // * VMSTATE_FOOB:
  130. // - VMSTATE_BOOL_V
  131. // - VMSTATE_U64
  132. // - VMSTATE_STRUCT_VARRAY_UINT8
  133. // - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
  134. // - VMSTATE_ARRAY
  135. #[repr(C)]
  136. #[derive(qemu_api_macros::offsets)]
  137. struct FooB {
  138. arr_a: [FooA; FOO_ARRAY_MAX],
  139. num_a: u8,
  140. arr_a_mul: [FooA; FOO_ARRAY_MAX],
  141. num_a_mul: u32,
  142. wrap: BqlCell<u64>,
  143. val: bool,
  144. // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
  145. arr_i64: [i64; FOO_ARRAY_MAX],
  146. }
  147. static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
  148. name: c_str!("foo_b").as_ptr(),
  149. version_id: 2,
  150. minimum_version_id: 1,
  151. fields: vmstate_fields! {
  152. vmstate_of!(FooB, val).with_version_id(2),
  153. vmstate_of!(FooB, wrap),
  154. vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
  155. vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
  156. vmstate_of!(FooB, arr_i64),
  157. },
  158. ..Zeroable::ZERO
  159. };
  160. #[test]
  161. fn test_vmstate_bool_v() {
  162. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
  163. // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
  164. assert_eq!(
  165. unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
  166. b"val\0"
  167. );
  168. assert_eq!(foo_fields[0].offset, 136);
  169. assert_eq!(foo_fields[0].num_offset, 0);
  170. assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
  171. assert_eq!(foo_fields[0].version_id, 2);
  172. assert_eq!(foo_fields[0].size, 1);
  173. assert_eq!(foo_fields[0].num, 0);
  174. assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
  175. assert!(foo_fields[0].vmsd.is_null());
  176. assert!(foo_fields[0].field_exists.is_none());
  177. }
  178. #[test]
  179. fn test_vmstate_uint64() {
  180. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
  181. // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
  182. assert_eq!(
  183. unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
  184. b"wrap\0"
  185. );
  186. assert_eq!(foo_fields[1].offset, 128);
  187. assert_eq!(foo_fields[1].num_offset, 0);
  188. assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
  189. assert_eq!(foo_fields[1].version_id, 0);
  190. assert_eq!(foo_fields[1].size, 8);
  191. assert_eq!(foo_fields[1].num, 0);
  192. assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
  193. assert!(foo_fields[1].vmsd.is_null());
  194. assert!(foo_fields[1].field_exists.is_none());
  195. }
  196. #[test]
  197. fn test_vmstate_struct_varray_uint8() {
  198. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
  199. // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
  200. // VMSTATE_STRUCT_VARRAY_UINT8)
  201. assert_eq!(
  202. unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
  203. b"arr_a\0"
  204. );
  205. assert_eq!(foo_fields[2].offset, 0);
  206. assert_eq!(foo_fields[2].num_offset, 60);
  207. assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
  208. assert_eq!(foo_fields[2].version_id, 1);
  209. assert_eq!(foo_fields[2].size, 20);
  210. assert_eq!(foo_fields[2].num, 0);
  211. assert_eq!(
  212. foo_fields[2].flags.0,
  213. VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
  214. );
  215. assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
  216. assert!(foo_fields[2].field_exists.is_none());
  217. }
  218. #[test]
  219. fn test_vmstate_struct_varray_uint32_multiply() {
  220. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
  221. // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
  222. // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
  223. assert_eq!(
  224. unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
  225. b"arr_a_mul\0"
  226. );
  227. assert_eq!(foo_fields[3].offset, 64);
  228. assert_eq!(foo_fields[3].num_offset, 124);
  229. assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
  230. assert_eq!(foo_fields[3].version_id, 2);
  231. assert_eq!(foo_fields[3].size, 20);
  232. assert_eq!(foo_fields[3].num, 32);
  233. assert_eq!(
  234. foo_fields[3].flags.0,
  235. VMStateFlags::VMS_STRUCT.0
  236. | VMStateFlags::VMS_VARRAY_UINT32.0
  237. | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
  238. );
  239. assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
  240. assert!(foo_fields[3].field_exists.is_none());
  241. }
  242. #[test]
  243. fn test_vmstate_macro_array() {
  244. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
  245. // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
  246. // VMSTATE_ARRAY)
  247. assert_eq!(
  248. unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
  249. b"arr_i64\0"
  250. );
  251. assert_eq!(foo_fields[4].offset, 144);
  252. assert_eq!(foo_fields[4].num_offset, 0);
  253. assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
  254. assert_eq!(foo_fields[4].version_id, 0);
  255. assert_eq!(foo_fields[4].size, 8);
  256. assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
  257. assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
  258. assert!(foo_fields[4].vmsd.is_null());
  259. assert!(foo_fields[4].field_exists.is_none());
  260. // The last VMStateField in VMSTATE_FOOB.
  261. assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
  262. }
  263. // =========================== Test VMSTATE_FOOC ===========================
  264. // Test the use cases of the vmstate macro, corresponding to the following C
  265. // macro variants:
  266. // * VMSTATE_FOOC:
  267. // - VMSTATE_POINTER
  268. // - VMSTATE_ARRAY_OF_POINTER
  269. struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible.
  270. impl_vmstate_forward!(FooCWrapper);
  271. #[repr(C)]
  272. #[derive(qemu_api_macros::offsets)]
  273. struct FooC {
  274. ptr: *const i32,
  275. ptr_a: NonNull<FooA>,
  276. arr_ptr: [Box<u8>; FOO_ARRAY_MAX],
  277. arr_ptr_wrap: FooCWrapper,
  278. }
  279. static VMSTATE_FOOC: VMStateDescription = VMStateDescription {
  280. name: c_str!("foo_c").as_ptr(),
  281. version_id: 3,
  282. minimum_version_id: 1,
  283. fields: vmstate_fields! {
  284. vmstate_of!(FooC, ptr).with_version_id(2),
  285. // FIXME: Currently vmstate_struct doesn't support the pointer to structure.
  286. // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>)
  287. vmstate_unused!(size_of::<NonNull<FooA>>()),
  288. vmstate_of!(FooC, arr_ptr),
  289. vmstate_of!(FooC, arr_ptr_wrap),
  290. },
  291. ..Zeroable::ZERO
  292. };
  293. const PTR_SIZE: usize = size_of::<*mut ()>();
  294. #[test]
  295. fn test_vmstate_pointer() {
  296. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
  297. // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER)
  298. assert_eq!(
  299. unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
  300. b"ptr\0"
  301. );
  302. assert_eq!(foo_fields[0].offset, 0);
  303. assert_eq!(foo_fields[0].num_offset, 0);
  304. assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 });
  305. assert_eq!(foo_fields[0].version_id, 2);
  306. assert_eq!(foo_fields[0].size, 4);
  307. assert_eq!(foo_fields[0].num, 0);
  308. assert_eq!(
  309. foo_fields[0].flags.0,
  310. VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0
  311. );
  312. assert!(foo_fields[0].vmsd.is_null());
  313. assert!(foo_fields[0].field_exists.is_none());
  314. }
  315. #[test]
  316. fn test_vmstate_macro_array_of_pointer() {
  317. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
  318. // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to
  319. // VMSTATE_ARRAY_OF_POINTER)
  320. assert_eq!(
  321. unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
  322. b"arr_ptr\0"
  323. );
  324. assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE);
  325. assert_eq!(foo_fields[2].num_offset, 0);
  326. assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
  327. assert_eq!(foo_fields[2].version_id, 0);
  328. assert_eq!(foo_fields[2].size, PTR_SIZE);
  329. assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32);
  330. assert_eq!(
  331. foo_fields[2].flags.0,
  332. VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
  333. );
  334. assert!(foo_fields[2].vmsd.is_null());
  335. assert!(foo_fields[2].field_exists.is_none());
  336. }
  337. #[test]
  338. fn test_vmstate_macro_array_of_pointer_wrapped() {
  339. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
  340. // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to
  341. // VMSTATE_ARRAY_OF_POINTER)
  342. assert_eq!(
  343. unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
  344. b"arr_ptr_wrap\0"
  345. );
  346. assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
  347. assert_eq!(foo_fields[3].num_offset, 0);
  348. assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
  349. assert_eq!(foo_fields[3].version_id, 0);
  350. assert_eq!(foo_fields[3].size, PTR_SIZE);
  351. assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32);
  352. assert_eq!(
  353. foo_fields[2].flags.0,
  354. VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
  355. );
  356. assert!(foo_fields[3].vmsd.is_null());
  357. assert!(foo_fields[3].field_exists.is_none());
  358. // The last VMStateField in VMSTATE_FOOC.
  359. assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
  360. }
  361. // =========================== Test VMSTATE_FOOD ===========================
  362. // Test the use cases of the vmstate macro, corresponding to the following C
  363. // macro variants:
  364. // * VMSTATE_FOOD:
  365. // - VMSTATE_VALIDATE
  366. // Add more member fields when vmstate_of/vmstate_struct support "test"
  367. // parameter.
  368. struct FooD;
  369. impl FooD {
  370. fn validate_food_0(&self, _version_id: u8) -> bool {
  371. true
  372. }
  373. fn validate_food_1(_state: &FooD, _version_id: u8) -> bool {
  374. false
  375. }
  376. }
  377. fn validate_food_2(_state: &FooD, _version_id: u8) -> bool {
  378. true
  379. }
  380. static VMSTATE_FOOD: VMStateDescription = VMStateDescription {
  381. name: c_str!("foo_d").as_ptr(),
  382. version_id: 3,
  383. minimum_version_id: 1,
  384. fields: vmstate_fields! {
  385. vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0),
  386. vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1),
  387. vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2),
  388. },
  389. ..Zeroable::ZERO
  390. };
  391. #[test]
  392. fn test_vmstate_validate() {
  393. let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) };
  394. let mut foo_d = FooD;
  395. let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>();
  396. // 1st VMStateField in VMSTATE_FOOD
  397. assert_eq!(
  398. unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
  399. b"foo_d_0\0"
  400. );
  401. assert_eq!(foo_fields[0].offset, 0);
  402. assert_eq!(foo_fields[0].num_offset, 0);
  403. assert!(foo_fields[0].info.is_null());
  404. assert_eq!(foo_fields[0].version_id, 0);
  405. assert_eq!(foo_fields[0].size, 0);
  406. assert_eq!(foo_fields[0].num, 0);
  407. assert_eq!(
  408. foo_fields[0].flags.0,
  409. VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0
  410. );
  411. assert!(foo_fields[0].vmsd.is_null());
  412. assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) });
  413. // 2nd VMStateField in VMSTATE_FOOD
  414. assert_eq!(
  415. unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
  416. b"foo_d_1\0"
  417. );
  418. assert!(!unsafe { foo_fields[1].field_exists.unwrap()(foo_d_p, 1) });
  419. // 3rd VMStateField in VMSTATE_FOOD
  420. assert_eq!(
  421. unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
  422. b"foo_d_2\0"
  423. );
  424. assert!(unsafe { foo_fields[2].field_exists.unwrap()(foo_d_p, 2) });
  425. // The last VMStateField in VMSTATE_FOOD.
  426. assert_eq!(foo_fields[3].flags, VMStateFlags::VMS_END);
  427. }