[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 47/48] rust/zeroable: Implement Zeroable with const_zero macro
From: |
Paolo Bonzini |
Subject: |
[PULL 47/48] rust/zeroable: Implement Zeroable with const_zero macro |
Date: |
Fri, 24 Jan 2025 10:44:41 +0100 |
The `const_zero` crate provides a nice macro to zero type-specific
constants, which doesn't need to enumerates the fields one by one.
Introduce the `const_zero` macro to QEMU (along with its documentation), and
use it to simplify the implementation of `Zeroable` trait.
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Link: 20250123163143.679841-1-zhao1.liu@intel.com">https://lore.kernel.org/r/20250123163143.679841-1-zhao1.liu@intel.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api/src/zeroable.rs | 137 +++++++++++++++-------------------
1 file changed, 61 insertions(+), 76 deletions(-)
diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs
index 57cac96de06..7b04947cb6c 100644
--- a/rust/qemu-api/src/zeroable.rs
+++ b/rust/qemu-api/src/zeroable.rs
@@ -1,13 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-use std::ptr;
-
/// 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 {
+/// pub unsafe trait Zeroable {
/// const ZERO: Self = unsafe {
::core::mem::MaybeUninit::<Self>::zeroed().assume_init() };
/// }
/// ```
@@ -29,23 +27,61 @@ pub unsafe trait Zeroable: Default {
const ZERO: Self;
}
-unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {
- const ZERO: Self = Self { i: 0 };
+/// 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_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)
+ }};
}
-unsafe impl Zeroable for crate::bindings::Property {
- const ZERO: Self = Self {
- name: ptr::null(),
- info: ptr::null(),
- offset: 0,
- bitnr: 0,
- bitmask: 0,
- set_default: false,
- defval: Zeroable::ZERO,
- arrayoffset: 0,
- arrayinfo: ptr::null(),
- arrayfieldsize: 0,
- link_type: ptr::null(),
+/// A wrapper to implement the `Zeroable` trait through the `const_zero` macro.
+macro_rules! impl_zeroable {
+ ($type:ty) => {
+ unsafe impl Zeroable for $type {
+ const ZERO: Self = unsafe { const_zero!($type) };
+ }
};
}
@@ -57,61 +93,10 @@ fn default() -> Self {
}
}
-unsafe impl Zeroable for crate::bindings::VMStateFlags {
- const ZERO: Self = Self(0);
-}
-
-unsafe impl Zeroable for crate::bindings::VMStateField {
- const ZERO: Self = Self {
- name: ptr::null(),
- err_hint: ptr::null(),
- offset: 0,
- size: 0,
- start: 0,
- num: 0,
- num_offset: 0,
- size_offset: 0,
- info: ptr::null(),
- flags: Zeroable::ZERO,
- vmsd: ptr::null(),
- version_id: 0,
- struct_version_id: 0,
- field_exists: None,
- };
-}
-
-unsafe impl Zeroable for crate::bindings::VMStateDescription {
- const ZERO: Self = Self {
- name: ptr::null(),
- unmigratable: false,
- early_setup: false,
- version_id: 0,
- minimum_version_id: 0,
- priority: crate::bindings::MigrationPriority::MIG_PRI_DEFAULT,
- pre_load: None,
- post_load: None,
- pre_save: None,
- post_save: None,
- needed: None,
- dev_unplug_pending: None,
- fields: ptr::null(),
- subsections: ptr::null(),
- };
-}
-
-unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {
- const ZERO: Self = Self {
- min_access_size: 0,
- max_access_size: 0,
- unaligned: false,
- accepts: None,
- };
-}
-
-unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {
- const ZERO: Self = Self {
- min_access_size: 0,
- max_access_size: 0,
- unaligned: false,
- };
-}
+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);
--
2.48.1
- [PULL 19/48] docs: Add GNR, SRF and CWF CPU models, (continued)
- [PULL 19/48] docs: Add GNR, SRF and CWF CPU models, Paolo Bonzini, 2025/01/24
- [PULL 30/48] rust: vmstate: add public utility macros to implement VMState, Paolo Bonzini, 2025/01/24
- [PULL 36/48] rust: pl011: remove unnecessary "extern crate", Paolo Bonzini, 2025/01/24
- [PULL 37/48] rust: pl011: hide unnecessarily "pub" items from outside pl011::device, Paolo Bonzini, 2025/01/24
- [PULL 48/48] rust: qemu-api: add sub-subclass to the integration tests, Paolo Bonzini, 2025/01/24
- [PULL 21/48] rust/qdev: Make REALIZE safe, Paolo Bonzini, 2025/01/24
- [PULL 45/48] rust: pl011: drop use of ControlFlow, Paolo Bonzini, 2025/01/24
- [PULL 40/48] rust: pl011: pull interrupt updates out of read/write ops, Paolo Bonzini, 2025/01/24
- [PULL 32/48] rust: pl011: switch vmstate to new-style macros, Paolo Bonzini, 2025/01/24
- [PULL 38/48] rust: pl011: extract conversion to RegisterOffset, Paolo Bonzini, 2025/01/24
- [PULL 47/48] rust/zeroable: Implement Zeroable with const_zero macro,
Paolo Bonzini <=
- [PULL 27/48] rust: vmstate: add varray support to vmstate_of!, Paolo Bonzini, 2025/01/24
- [PULL 28/48] rust: vmstate: implement Zeroable for VMStateField, Paolo Bonzini, 2025/01/24
- [PULL 31/48] rust: qemu_api: add vmstate_struct, Paolo Bonzini, 2025/01/24
- [PULL 39/48] rust: pl011: extract CharBackend receive logic into a separate function, Paolo Bonzini, 2025/01/24
- [PULL 44/48] rust: pl011: pull device-specific code out of MemoryRegionOps callbacks, Paolo Bonzini, 2025/01/24
- [PULL 33/48] rust: vmstate: remove translation of C vmstate macros, Paolo Bonzini, 2025/01/24
- [PULL 41/48] rust: pl011: extract PL011Registers, Paolo Bonzini, 2025/01/24
- [PULL 46/48] rust: qdev: make reset take a shared reference, Paolo Bonzini, 2025/01/24
- Re: [PULL 00/48] i386, rust changes for 2024-01-24, Stefan Hajnoczi, 2025/01/24