Skip to content

Commit cfdbdc5

Browse files
authored
Merge pull request #56 from Rust-for-Linux/dev/zeroed-value
- rename `zeroed()` to `init_zeroed()` - add `Zeroable::init_zeroed()` delegating to `init_zeroed()` - add new `zeroed()`, a safe version of `mem::zeroed()` and also provide it via `Zeroable::zeroed()` - implement `ZeroableOption` for `&T` and `&mut T` - change `NonNull` to also implement `ZeroableOption` - implement `ZeroableOption` for function pointers
2 parents 03e0a0d + f187065 commit cfdbdc5

13 files changed

+139
-56
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
implement it.
1515
- `unsafe fn cast_[pin_]init()` functions to unsafely change the initialized type of an initializer
1616
- `impl<T, E> [Pin]Init<T, E> for Result<T, E>`, so results are now (pin-)initializers
17+
- add `Zeroable::init_zeroed()` delegating to `init_zeroed()`
18+
- add new `zeroed()`, a safe version of `mem::zeroed()` and also provide it via `Zeroable::zeroed()`
19+
- implement `Zeroable` for `Option<&T>` and `Option<&mut T>`
20+
- implement `Zeroable` for `Option<[unsafe] [extern "abi"] fn(...args...) -> ret>` for `"Rust"` and
21+
`"C"` ABIs and up to 20 arguments
1722

1823
### Changed
1924

@@ -23,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2328
- renamed the crate from `pinned-init` to `pin-init` and `pinned-init-macro` to `pin-init-internal`
2429
- blanket impls of `Init` and `PinInit` from `impl<T, E> [Pin]Init<T, E> for T` to
2530
`impl<T> [Pin]Init<T> for T`
31+
- renamed `zeroed()` to `init_zeroed()`
2632

2733
### Fixed
2834

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl DriverData {
125125
fn new() -> impl PinInit<Self, Error> {
126126
try_pin_init!(Self {
127127
status <- CMutex::new(0),
128-
buffer: Box::init(pin_init::zeroed())?,
128+
buffer: Box::init(pin_init::init_zeroed())?,
129129
}? Error)
130130
}
131131
}

examples/big_struct_in_place.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub struct ManagedBuf {
2121

2222
impl ManagedBuf {
2323
pub fn new() -> impl Init<Self> {
24-
init!(ManagedBuf { buf <- zeroed() })
24+
init!(ManagedBuf { buf <- init_zeroed() })
2525
}
2626
}
2727

@@ -30,7 +30,7 @@ fn main() {
3030
{
3131
// we want to initialize the struct in-place, otherwise we would get a stackoverflow
3232
let buf: Box<BigStruct> = Box::init(init!(BigStruct {
33-
buf <- zeroed(),
33+
buf <- init_zeroed(),
3434
a: 7,
3535
b: 186,
3636
c: 7789,

src/lib.rs

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
//! fn new() -> impl PinInit<Self, Error> {
149149
//! try_pin_init!(Self {
150150
//! status <- CMutex::new(0),
151-
//! buffer: Box::init(pin_init::zeroed())?,
151+
//! buffer: Box::init(pin_init::init_zeroed())?,
152152
//! }? Error)
153153
//! }
154154
//! }
@@ -742,7 +742,7 @@ macro_rules! stack_try_pin_init {
742742
/// - Fields that you want to initialize in-place have to use `<-` instead of `:`.
743743
/// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]
744744
/// pointer named `this` inside of the initializer.
745-
/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the
745+
/// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the
746746
/// struct, this initializes every field with 0 and then runs all initializers specified in the
747747
/// body. This can only be done if [`Zeroable`] is implemented for the struct.
748748
///
@@ -769,7 +769,7 @@ macro_rules! stack_try_pin_init {
769769
/// });
770770
/// let init = pin_init!(Buf {
771771
/// buf: [1; 64],
772-
/// ..Zeroable::zeroed()
772+
/// ..Zeroable::init_zeroed()
773773
/// });
774774
/// ```
775775
///
@@ -805,7 +805,7 @@ macro_rules! pin_init {
805805
/// ```rust
806806
/// # #![feature(allocator_api)]
807807
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
808-
/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed};
808+
/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed};
809809
///
810810
/// #[pin_data]
811811
/// struct BigBuf {
@@ -817,7 +817,7 @@ macro_rules! pin_init {
817817
/// impl BigBuf {
818818
/// fn new() -> impl PinInit<Self, Error> {
819819
/// try_pin_init!(Self {
820-
/// big: Box::init(zeroed())?,
820+
/// big: Box::init(init_zeroed())?,
821821
/// small: [0; 1024 * 1024],
822822
/// ptr: core::ptr::null_mut(),
823823
/// }? Error)
@@ -866,7 +866,7 @@ macro_rules! try_pin_init {
866866
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
867867
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
868868
/// # use pin_init::InPlaceInit;
869-
/// use pin_init::{init, Init, zeroed};
869+
/// use pin_init::{init, Init, init_zeroed};
870870
///
871871
/// struct BigBuf {
872872
/// small: [u8; 1024 * 1024],
@@ -875,7 +875,7 @@ macro_rules! try_pin_init {
875875
/// impl BigBuf {
876876
/// fn new() -> impl Init<Self> {
877877
/// init!(Self {
878-
/// small <- zeroed(),
878+
/// small <- init_zeroed(),
879879
/// })
880880
/// }
881881
/// }
@@ -913,7 +913,7 @@ macro_rules! init {
913913
/// # #![feature(allocator_api)]
914914
/// # use core::alloc::AllocError;
915915
/// # use pin_init::InPlaceInit;
916-
/// use pin_init::{try_init, Init, zeroed};
916+
/// use pin_init::{try_init, Init, init_zeroed};
917917
///
918918
/// struct BigBuf {
919919
/// big: Box<[u8; 1024 * 1024 * 1024]>,
@@ -923,7 +923,7 @@ macro_rules! init {
923923
/// impl BigBuf {
924924
/// fn new() -> impl Init<Self, AllocError> {
925925
/// try_init!(Self {
926-
/// big: Box::init(zeroed())?,
926+
/// big: Box::init(init_zeroed())?,
927927
/// small: [0; 1024 * 1024],
928928
/// }? AllocError)
929929
/// }
@@ -1170,7 +1170,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
11701170
///
11711171
/// ```rust
11721172
/// # #![expect(clippy::disallowed_names)]
1173-
/// use pin_init::{init, zeroed, Init};
1173+
/// use pin_init::{init, init_zeroed, Init};
11741174
///
11751175
/// struct Foo {
11761176
/// buf: [u8; 1_000_000],
@@ -1183,7 +1183,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
11831183
/// }
11841184
///
11851185
/// let foo = init!(Foo {
1186-
/// buf <- zeroed()
1186+
/// buf <- init_zeroed()
11871187
/// }).chain(|foo| {
11881188
/// foo.setup();
11891189
/// Ok(())
@@ -1495,7 +1495,45 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {
14951495
/// ```rust,ignore
14961496
/// let val: Self = unsafe { core::mem::zeroed() };
14971497
/// ```
1498-
pub unsafe trait Zeroable {}
1498+
pub unsafe trait Zeroable {
1499+
/// Create a new zeroed `Self`.
1500+
///
1501+
/// The returned initializer will write `0x00` to every byte of the given `slot`.
1502+
#[inline]
1503+
fn init_zeroed() -> impl Init<Self>
1504+
where
1505+
Self: Sized,
1506+
{
1507+
init_zeroed()
1508+
}
1509+
1510+
/// Create a `Self` consisting of all zeroes.
1511+
///
1512+
/// Whenever a type implements [`Zeroable`], this function should be preferred over
1513+
/// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
1514+
///
1515+
/// # Examples
1516+
///
1517+
/// ```
1518+
/// use pin_init::{Zeroable, zeroed};
1519+
///
1520+
/// #[derive(Zeroable)]
1521+
/// struct Point {
1522+
/// x: u32,
1523+
/// y: u32,
1524+
/// }
1525+
///
1526+
/// let point: Point = zeroed();
1527+
/// assert_eq!(point.x, 0);
1528+
/// assert_eq!(point.y, 0);
1529+
/// ```
1530+
fn zeroed() -> Self
1531+
where
1532+
Self: Sized,
1533+
{
1534+
zeroed()
1535+
}
1536+
}
14991537

15001538
/// Marker trait for types that allow `Option<Self>` to be set to all zeroes in order to write
15011539
/// `None` to that location.
@@ -1508,11 +1546,21 @@ pub unsafe trait ZeroableOption {}
15081546
// SAFETY: by the safety requirement of `ZeroableOption`, this is valid.
15091547
unsafe impl<T: ZeroableOption> Zeroable for Option<T> {}
15101548

1511-
/// Create a new zeroed T.
1549+
// SAFETY: `Option<&T>` is part of the option layout optimization guarantee:
1550+
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
1551+
unsafe impl<T> ZeroableOption for &T {}
1552+
// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee:
1553+
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
1554+
unsafe impl<T> ZeroableOption for &mut T {}
1555+
// SAFETY: `Option<NonNull<T>>` is part of the option layout optimization guarantee:
1556+
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
1557+
unsafe impl<T> ZeroableOption for NonNull<T> {}
1558+
1559+
/// Create an initializer for a zeroed `T`.
15121560
///
15131561
/// The returned initializer will write `0x00` to every byte of the given `slot`.
15141562
#[inline]
1515-
pub fn zeroed<T: Zeroable>() -> impl Init<T> {
1563+
pub fn init_zeroed<T: Zeroable>() -> impl Init<T> {
15161564
// SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T`
15171565
// and because we write all zeroes, the memory is initialized.
15181566
unsafe {
@@ -1523,6 +1571,31 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> {
15231571
}
15241572
}
15251573

1574+
/// Create a `T` consisting of all zeroes.
1575+
///
1576+
/// Whenever a type implements [`Zeroable`], this function should be preferred over
1577+
/// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
1578+
///
1579+
/// # Examples
1580+
///
1581+
/// ```
1582+
/// use pin_init::{Zeroable, zeroed};
1583+
///
1584+
/// #[derive(Zeroable)]
1585+
/// struct Point {
1586+
/// x: u32,
1587+
/// y: u32,
1588+
/// }
1589+
///
1590+
/// let point: Point = zeroed();
1591+
/// assert_eq!(point.x, 0);
1592+
/// assert_eq!(point.y, 0);
1593+
/// ```
1594+
pub const fn zeroed<T: Zeroable>() -> T {
1595+
// SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`.
1596+
unsafe { core::mem::zeroed() }
1597+
}
1598+
15261599
macro_rules! impl_zeroable {
15271600
($($({$($generics:tt)*})? $t:ty, )*) => {
15281601
// SAFETY: Safety comments written in the macro invocation.
@@ -1560,7 +1633,6 @@ impl_zeroable! {
15601633
Option<NonZeroU128>, Option<NonZeroUsize>,
15611634
Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
15621635
Option<NonZeroI128>, Option<NonZeroIsize>,
1563-
{<T>} Option<NonNull<T>>,
15641636

15651637
// SAFETY: `null` pointer is valid.
15661638
//
@@ -1590,6 +1662,22 @@ macro_rules! impl_tuple_zeroable {
15901662

15911663
impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);
15921664

1665+
macro_rules! impl_fn_zeroable_option {
1666+
([$($abi:literal),* $(,)?] $args:tt) => {
1667+
$(impl_fn_zeroable_option!({extern $abi} $args);)*
1668+
$(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
1669+
};
1670+
({$($prefix:tt)*} {$(,)?}) => {};
1671+
({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
1672+
// SAFETY: function pointers are part of the option layout optimization:
1673+
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
1674+
unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
1675+
impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,});
1676+
};
1677+
}
1678+
1679+
impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U });
1680+
15931681
/// This trait allows creating an instance of `Self` which contains exactly one
15941682
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
15951683
///

src/macros.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ macro_rules! __pin_data {
10301030
///
10311031
/// This macro has multiple internal call configurations, these are always the very first ident:
10321032
/// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros.
1033-
/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled.
1033+
/// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax has been handled.
10341034
/// - `init_slot`: recursively creates the code that initializes all fields in `slot`.
10351035
/// - `make_initializer`: recursively create the struct initializer that guarantees that every
10361036
/// field has been initialized exactly once.
@@ -1059,7 +1059,7 @@ macro_rules! __init_internal {
10591059
@data($data, $($use_data)?),
10601060
@has_data($has_data, $get_data),
10611061
@construct_closure($construct_closure),
1062-
@zeroed(), // Nothing means default behavior.
1062+
@init_zeroed(), // Nothing means default behavior.
10631063
)
10641064
};
10651065
(
@@ -1074,7 +1074,7 @@ macro_rules! __init_internal {
10741074
@has_data($has_data:ident, $get_data:ident),
10751075
// `pin_init_from_closure` or `init_from_closure`.
10761076
@construct_closure($construct_closure:ident),
1077-
@munch_fields(..Zeroable::zeroed()),
1077+
@munch_fields(..Zeroable::init_zeroed()),
10781078
) => {
10791079
$crate::__init_internal!(with_update_parsed:
10801080
@this($($this)?),
@@ -1084,7 +1084,7 @@ macro_rules! __init_internal {
10841084
@data($data, $($use_data)?),
10851085
@has_data($has_data, $get_data),
10861086
@construct_closure($construct_closure),
1087-
@zeroed(()), // `()` means zero all fields not mentioned.
1087+
@init_zeroed(()), // `()` means zero all fields not mentioned.
10881088
)
10891089
};
10901090
(
@@ -1124,7 +1124,7 @@ macro_rules! __init_internal {
11241124
@has_data($has_data:ident, $get_data:ident),
11251125
// `pin_init_from_closure` or `init_from_closure`.
11261126
@construct_closure($construct_closure:ident),
1127-
@zeroed($($init_zeroed:expr)?),
1127+
@init_zeroed($($init_zeroed:expr)?),
11281128
) => {{
11291129
// We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
11301130
// type and shadow it later when we insert the arbitrary user code. That way there will be
@@ -1196,7 +1196,7 @@ macro_rules! __init_internal {
11961196
@data($data:ident),
11971197
@slot($slot:ident),
11981198
@guards($($guards:ident,)*),
1199-
@munch_fields($(..Zeroable::zeroed())? $(,)?),
1199+
@munch_fields($(..Zeroable::init_zeroed())? $(,)?),
12001200
) => {
12011201
// Endpoint of munching, no fields are left. If execution reaches this point, all fields
12021202
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -1300,11 +1300,11 @@ macro_rules! __init_internal {
13001300
(make_initializer:
13011301
@slot($slot:ident),
13021302
@type_name($t:path),
1303-
@munch_fields(..Zeroable::zeroed() $(,)?),
1303+
@munch_fields(..Zeroable::init_zeroed() $(,)?),
13041304
@acc($($acc:tt)*),
13051305
) => {
13061306
// Endpoint, nothing more to munch, create the initializer. Since the users specified
1307-
// `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have
1307+
// `..Zeroable::init_zeroed()`, the slot will already have been zeroed and all field that have
13081308
// not been overwritten are thus zero and initialized. We still check that all fields are
13091309
// actually accessible by using the struct update syntax ourselves.
13101310
// We are inside of a closure that is never executed and thus we can abuse `slot` to

tests/alloc_fail.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ fn too_big_in_place() {
1717

1818
// should be too big with current hardware.
1919
assert!(matches!(
20-
Box::init(zeroed::<[u8; 1024 * 1024 * 1024 * 1024]>()),
20+
Box::init(init_zeroed::<[u8; 1024 * 1024 * 1024 * 1024]>()),
2121
Err(AllocError)
2222
));
2323
// should be too big with current hardware.
2424
assert!(matches!(
25-
Arc::init(zeroed::<[u8; 1024 * 1024 * 1024 * 1024]>()),
25+
Arc::init(init_zeroed::<[u8; 1024 * 1024 * 1024 * 1024]>()),
2626
Err(AllocError)
2727
));
2828
}

tests/const-generic-default.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ struct Array<const N: usize = 0> {
99

1010
#[test]
1111
fn create_array() {
12-
stack_pin_init!(let array: Array<1024> = init!(Array { array <- zeroed() }));
12+
stack_pin_init!(let array: Array<1024> = init!(Array { array <- init_zeroed() }));
1313
println!("{}", array.array.len());
1414
}

0 commit comments

Comments
 (0)