Skip to content

Commit 275b8ab

Browse files
committed
add [pin_]init_array_from_fn function to initialize arrays
1 parent 1258aa4 commit 275b8ab

2 files changed

Lines changed: 89 additions & 2 deletions

File tree

src/lib.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,93 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
10851085
unsafe { init_from_closure(|_| Ok(())) }
10861086
}
10871087

1088+
/// Initializes an array by initializing each element via the provided initializer.
1089+
///
1090+
/// # Examples
1091+
///
1092+
/// ```rust
1093+
/// # use pinned_init::*;
1094+
/// use pinned_init::init_array_from_fn;
1095+
/// let array: Box<[usize; 1_000]> = Box::init(init_array_from_fn(|i| i)).unwrap();
1096+
/// assert_eq!(array.len(), 1_000);
1097+
/// ```
1098+
pub fn init_array_from_fn<I, const N: usize, T, E>(
1099+
mut make_init: impl FnMut(usize) -> I,
1100+
) -> impl Init<[T; N], E>
1101+
where
1102+
I: Init<T, E>,
1103+
{
1104+
let init = move |slot: *mut [T; N]| {
1105+
let slot = slot.cast::<T>();
1106+
for i in 0..N {
1107+
let init = make_init(i);
1108+
// SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`.
1109+
let ptr = unsafe { slot.add(i) };
1110+
// SAFETY: The pointer is derived from `slot` and thus satisfies the `__init`
1111+
// requirements.
1112+
match unsafe { init.__init(ptr) } {
1113+
Ok(()) => {}
1114+
Err(e) => {
1115+
// SAFETY: The loop has initialized the elements `slot[0..i]` and since we
1116+
// return `Err` below, `slot` will be considered uninitialized memory.
1117+
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) };
1118+
return Err(e);
1119+
}
1120+
}
1121+
}
1122+
Ok(())
1123+
};
1124+
// SAFETY: The initializer above initializes every element of the array. On failure it drops
1125+
// any initialized elements and returns `Err`.
1126+
unsafe { init_from_closure(init) }
1127+
}
1128+
1129+
/// Initializes an array by initializing each element via the provided initializer.
1130+
///
1131+
/// # Examples
1132+
///
1133+
/// ```rust
1134+
/// # #![feature(allocator_api)]
1135+
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
1136+
/// # use pinned_init::*;
1137+
/// # use core::pin::Pin;
1138+
/// use pinned_init::pin_init_array_from_fn;
1139+
/// use std::sync::Arc;
1140+
/// let array: Pin<Arc<[CMutex<usize>; 1_000]>> =
1141+
/// Arc::pin_init(pin_init_array_from_fn(|i| CMutex::new(i))).unwrap();
1142+
/// assert_eq!(array.len(), 1_000);
1143+
/// ```
1144+
pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
1145+
mut make_init: impl FnMut(usize) -> I,
1146+
) -> impl PinInit<[T; N], E>
1147+
where
1148+
I: PinInit<T, E>,
1149+
{
1150+
let init = move |slot: *mut [T; N]| {
1151+
let slot = slot.cast::<T>();
1152+
for i in 0..N {
1153+
let init = make_init(i);
1154+
// SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`.
1155+
let ptr = unsafe { slot.add(i) };
1156+
// SAFETY: The pointer is derived from `slot` and thus satisfies the `__init`
1157+
// requirements.
1158+
match unsafe { init.__pinned_init(ptr) } {
1159+
Ok(()) => {}
1160+
Err(e) => {
1161+
// SAFETY: The loop has initialized the elements `slot[0..i]` and since we
1162+
// return `Err` below, `slot` will be considered uninitialized memory.
1163+
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) };
1164+
return Err(e);
1165+
}
1166+
}
1167+
}
1168+
Ok(())
1169+
};
1170+
// SAFETY: The initializer above initializes every element of the array. On failure it drops
1171+
// any initialized elements and returns `Err`.
1172+
unsafe { pin_init_from_closure(init) }
1173+
}
1174+
10881175
// SAFETY: Every type can be initialized by-value.
10891176
unsafe impl<T, E> Init<T, E> for T {
10901177
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {

tests/ui/no_pin_data_but_pinned_drop.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ error[E0277]: the trait bound `Foo: HasPinData` is not satisfied
55
| ^^^ the trait `HasPinData` is not implemented for `Foo`
66
|
77
note: required by a bound in `PinnedDrop`
8-
--> $SRC_DIR/src/lib.rs:1234:30
8+
--> $SRC_DIR/src/lib.rs:1321:30
99
|
10-
1234 | pub unsafe trait PinnedDrop: __internal::HasPinData {
10+
1321 | pub unsafe trait PinnedDrop: __internal::HasPinData {
1111
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `PinnedDrop`
1212

1313
error: aborting due to 1 previous error

0 commit comments

Comments
 (0)