Skip to content

Commit 9cdcb5d

Browse files
committed
Merged latest changes from main into current branch
Signed-off-by: Liam Davis <davisliam123@gmail.com>
2 parents 3ba944f + 64df950 commit 9cdcb5d

18 files changed

+181
-83
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- `MaybeZeroable` derive macro to try to derive `Zeroable`, but not error if not all fields
1414
implement it.
1515
- `unsafe fn cast_[pin_]init()` functions to unsafely change the initialized type of an initializer
16+
- `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
1622

1723
### Changed
1824

1925
- `InPlaceInit` now only exists when the `alloc` or `std` features are enabled
2026
- added support for visibility in `Zeroable` derive macro
2127
- added support for `union`s in `Zeroable` derive macro
2228
- renamed the crate from `pinned-init` to `pin-init` and `pinned-init-macro` to `pin-init-internal`
29+
- blanket impls of `Init` and `PinInit` from `impl<T, E> [Pin]Init<T, E> for T` to
30+
`impl<T> [Pin]Init<T> for T`
31+
- renamed `zeroed()` to `init_zeroed()`
2332

2433
### Fixed
2534

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,

examples/pthread_mutex.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ mod pthread_mtx {
139139
}
140140
}
141141

142-
#[cfg_attr(all(test, not(miri)), test)]
142+
#[cfg_attr(test, test)]
143+
#[cfg_attr(all(test, miri), ignore)]
143144
fn main() {
144145
#[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))]
145146
{

src/lib.rs

Lines changed: 125 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
///
@@ -772,7 +772,7 @@ macro_rules! stack_try_pin_init {
772772
/// });
773773
/// let init = pin_init!(Buf {
774774
/// buf: [1; 64],
775-
/// ..Zeroable::zeroed()
775+
/// ..Zeroable::init_zeroed()
776776
/// });
777777
/// ```
778778
///
@@ -808,7 +808,7 @@ macro_rules! pin_init {
808808
/// ```rust
809809
/// # #![feature(allocator_api)]
810810
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
811-
/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed};
811+
/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed};
812812
///
813813
/// #[pin_data]
814814
/// struct BigBuf {
@@ -820,7 +820,7 @@ macro_rules! pin_init {
820820
/// impl BigBuf {
821821
/// fn new() -> impl PinInit<Self, Error> {
822822
/// try_pin_init!(Self {
823-
/// big: Box::init(zeroed())?,
823+
/// big: Box::init(init_zeroed())?,
824824
/// small: [0; 1024 * 1024],
825825
/// ptr: core::ptr::null_mut(),
826826
/// }? Error)
@@ -869,7 +869,7 @@ macro_rules! try_pin_init {
869869
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
870870
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
871871
/// # use pin_init::InPlaceInit;
872-
/// use pin_init::{init, Init, zeroed};
872+
/// use pin_init::{init, Init, init_zeroed};
873873
///
874874
/// struct BigBuf {
875875
/// small: [u8; 1024 * 1024],
@@ -878,7 +878,7 @@ macro_rules! try_pin_init {
878878
/// impl BigBuf {
879879
/// fn new() -> impl Init<Self> {
880880
/// init!(Self {
881-
/// small <- zeroed(),
881+
/// small <- init_zeroed(),
882882
/// })
883883
/// }
884884
/// }
@@ -916,7 +916,7 @@ macro_rules! init {
916916
/// # #![feature(allocator_api)]
917917
/// # use core::alloc::AllocError;
918918
/// # use pin_init::InPlaceInit;
919-
/// use pin_init::{try_init, Init, zeroed};
919+
/// use pin_init::{try_init, Init, init_zeroed};
920920
///
921921
/// struct BigBuf {
922922
/// big: Box<[u8; 1024 * 1024 * 1024]>,
@@ -926,7 +926,7 @@ macro_rules! init {
926926
/// impl BigBuf {
927927
/// fn new() -> impl Init<Self, AllocError> {
928928
/// try_init!(Self {
929-
/// big: Box::init(zeroed())?,
929+
/// big: Box::init(init_zeroed())?,
930930
/// small: [0; 1024 * 1024],
931931
/// }? AllocError)
932932
/// }
@@ -1173,7 +1173,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
11731173
///
11741174
/// ```rust
11751175
/// # #![expect(clippy::disallowed_names)]
1176-
/// use pin_init::{init, zeroed, Init};
1176+
/// use pin_init::{init, init_zeroed, Init};
11771177
///
11781178
/// struct Foo {
11791179
/// buf: [u8; 1_000_000],
@@ -1186,7 +1186,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
11861186
/// }
11871187
///
11881188
/// let foo = init!(Foo {
1189-
/// buf <- zeroed()
1189+
/// buf <- init_zeroed()
11901190
/// }).chain(|foo| {
11911191
/// foo.setup();
11921192
/// Ok(())
@@ -1412,6 +1412,28 @@ unsafe impl<T> PinInit<T> for T {
14121412
}
14131413
}
14141414

1415+
// SAFETY: when the `__init` function returns with
1416+
// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld.
1417+
// - `Err(err)`, slot was not written to.
1418+
unsafe impl<T, E> Init<T, E> for Result<T, E> {
1419+
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
1420+
// SAFETY: `slot` is valid for writes by the safety requirements of this function.
1421+
unsafe { slot.write(self?) };
1422+
Ok(())
1423+
}
1424+
}
1425+
1426+
// SAFETY: when the `__pinned_init` function returns with
1427+
// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld.
1428+
// - `Err(err)`, slot was not written to.
1429+
unsafe impl<T, E> PinInit<T, E> for Result<T, E> {
1430+
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
1431+
// SAFETY: `slot` is valid for writes by the safety requirements of this function.
1432+
unsafe { slot.write(self?) };
1433+
Ok(())
1434+
}
1435+
}
1436+
14151437
/// Smart pointer containing uninitialized memory and that can write a value.
14161438
pub trait InPlaceWrite<T> {
14171439
/// The type `Self` turns into when the contents are initialized.
@@ -1476,7 +1498,45 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {
14761498
/// ```rust,ignore
14771499
/// let val: Self = unsafe { core::mem::zeroed() };
14781500
/// ```
1479-
pub unsafe trait Zeroable {}
1501+
pub unsafe trait Zeroable {
1502+
/// Create a new zeroed `Self`.
1503+
///
1504+
/// The returned initializer will write `0x00` to every byte of the given `slot`.
1505+
#[inline]
1506+
fn init_zeroed() -> impl Init<Self>
1507+
where
1508+
Self: Sized,
1509+
{
1510+
init_zeroed()
1511+
}
1512+
1513+
/// Create a `Self` consisting of all zeroes.
1514+
///
1515+
/// Whenever a type implements [`Zeroable`], this function should be preferred over
1516+
/// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
1517+
///
1518+
/// # Examples
1519+
///
1520+
/// ```
1521+
/// use pin_init::{Zeroable, zeroed};
1522+
///
1523+
/// #[derive(Zeroable)]
1524+
/// struct Point {
1525+
/// x: u32,
1526+
/// y: u32,
1527+
/// }
1528+
///
1529+
/// let point: Point = zeroed();
1530+
/// assert_eq!(point.x, 0);
1531+
/// assert_eq!(point.y, 0);
1532+
/// ```
1533+
fn zeroed() -> Self
1534+
where
1535+
Self: Sized,
1536+
{
1537+
zeroed()
1538+
}
1539+
}
14801540

14811541
/// Marker trait for types that allow `Option<Self>` to be set to all zeroes in order to write
14821542
/// `None` to that location.
@@ -1489,11 +1549,21 @@ pub unsafe trait ZeroableOption {}
14891549
// SAFETY: by the safety requirement of `ZeroableOption`, this is valid.
14901550
unsafe impl<T: ZeroableOption> Zeroable for Option<T> {}
14911551

1492-
/// Create a new zeroed T.
1552+
// SAFETY: `Option<&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 &T {}
1555+
// SAFETY: `Option<&mut 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 &mut T {}
1558+
// SAFETY: `Option<NonNull<T>>` is part of the option layout optimization guarantee:
1559+
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
1560+
unsafe impl<T> ZeroableOption for NonNull<T> {}
1561+
1562+
/// Create an initializer for a zeroed `T`.
14931563
///
14941564
/// The returned initializer will write `0x00` to every byte of the given `slot`.
14951565
#[inline]
1496-
pub fn zeroed<T: Zeroable>() -> impl Init<T> {
1566+
pub fn init_zeroed<T: Zeroable>() -> impl Init<T> {
14971567
// SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T`
14981568
// and because we write all zeroes, the memory is initialized.
14991569
unsafe {
@@ -1504,6 +1574,31 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> {
15041574
}
15051575
}
15061576

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

15461640
// SAFETY: `null` pointer is valid.
15471641
//
@@ -1571,6 +1665,22 @@ macro_rules! impl_tuple_zeroable {
15711665

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

1668+
macro_rules! impl_fn_zeroable_option {
1669+
([$($abi:literal),* $(,)?] $args:tt) => {
1670+
$(impl_fn_zeroable_option!({extern $abi} $args);)*
1671+
$(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
1672+
};
1673+
({$($prefix:tt)*} {$(,)?}) => {};
1674+
({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
1675+
// SAFETY: function pointers are part of the option layout optimization:
1676+
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
1677+
unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
1678+
impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,});
1679+
};
1680+
}
1681+
1682+
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 });
1683+
15741684
/// This trait allows creating an instance of `Self` which contains exactly one
15751685
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
15761686
///

src/macros.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ macro_rules! __pin_data {
10501050
///
10511051
/// This macro has multiple internal call configurations, these are always the very first ident:
10521052
/// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros.
1053-
/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled.
1053+
/// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax has been handled.
10541054
/// - `init_slot`: recursively creates the code that initializes all fields in `slot`.
10551055
/// - `make_initializer`: recursively create the struct initializer that guarantees that every
10561056
/// field has been initialized exactly once.
@@ -1079,7 +1079,7 @@ macro_rules! __init_internal {
10791079
@data($data, $($use_data)?),
10801080
@has_data($has_data, $get_data),
10811081
@construct_closure($construct_closure),
1082-
@zeroed(), // Nothing means default behavior.
1082+
@init_zeroed(), // Nothing means default behavior.
10831083
)
10841084
};
10851085
(
@@ -1094,7 +1094,7 @@ macro_rules! __init_internal {
10941094
@has_data($has_data:ident, $get_data:ident),
10951095
// `pin_init_from_closure` or `init_from_closure`.
10961096
@construct_closure($construct_closure:ident),
1097-
@munch_fields(..Zeroable::zeroed()),
1097+
@munch_fields(..Zeroable::init_zeroed()),
10981098
) => {
10991099
$crate::__init_internal!(with_update_parsed:
11001100
@this($($this)?),
@@ -1104,7 +1104,7 @@ macro_rules! __init_internal {
11041104
@data($data, $($use_data)?),
11051105
@has_data($has_data, $get_data),
11061106
@construct_closure($construct_closure),
1107-
@zeroed(()), // `()` means zero all fields not mentioned.
1107+
@init_zeroed(()), // `()` means zero all fields not mentioned.
11081108
)
11091109
};
11101110
(
@@ -1144,7 +1144,7 @@ macro_rules! __init_internal {
11441144
@has_data($has_data:ident, $get_data:ident),
11451145
// `pin_init_from_closure` or `init_from_closure`.
11461146
@construct_closure($construct_closure:ident),
1147-
@zeroed($($init_zeroed:expr)?),
1147+
@init_zeroed($($init_zeroed:expr)?),
11481148
) => {{
11491149
// We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
11501150
// type and shadow it later when we insert the arbitrary user code. That way there will be
@@ -1225,7 +1225,7 @@ macro_rules! __init_internal {
12251225
@data($data:ident),
12261226
@slot($slot:ident),
12271227
@guards($($guards:ident,)*),
1228-
@munch_fields($(..Zeroable::zeroed())? $(,)?),
1228+
@munch_fields($(..Zeroable::init_zeroed())? $(,)?),
12291229
) => {
12301230
// Endpoint of munching, no fields are left. If execution reaches this point, all fields
12311231
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -1329,11 +1329,11 @@ macro_rules! __init_internal {
13291329
(make_initializer:
13301330
@slot($slot:ident),
13311331
@type_name($t:path),
1332-
@munch_fields(..Zeroable::zeroed() $(,)?),
1332+
@munch_fields(..Zeroable::init_zeroed() $(,)?),
13331333
@acc($($acc:tt)*),
13341334
) => {
13351335
// Endpoint, nothing more to munch, create the initializer. Since the users specified
1336-
// `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have
1336+
// `..Zeroable::init_zeroed()`, the slot will already have been zeroed and all field that have
13371337
// not been overwritten are thus zero and initialized. We still check that all fields are
13381338
// actually accessible by using the struct update syntax ourselves.
13391339
// We are inside of a closure that is never executed and thus we can abuse `slot` to

0 commit comments

Comments
 (0)