Messages in this thread | | | Date | Mon, 3 Jul 2023 12:03:31 +0000 | Subject | [PATCH 6/7] rust: init: Add functions to create array initializers | From | Alice Ryhl <> |
| |
Benno Lossin <benno.lossin@proton.me> writes: > Add two functions `pin_init_array_from_fn` and `init_array_from_fn` that > take a function that generates initializers for `T` from usize, the added > functions then return an initializer for `[T; N]` where every element is > initialized by an element returned from the generator function. > > Suggested-by: Asahi Lina <lina@asahilina.net> > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > +/// Initializes an array by initializing each element via the provided initializer. > +/// > +/// # Examples > +/// > +/// ```rust > +/// let array: Box<[usize; 1000_000_000]>= Box::init(init_array_from_fn(|i| i)).unwrap(); > +/// println!("{array:?}"); > +/// ``` > +pub fn init_array_from_fn<I, const N: usize, T, E>( > + mut make_init: impl FnMut(usize) -> I, > +) -> impl Init<[T; N], E> > +where > + I: Init<T, E>, > +{ > + let init = move |slot: *mut [T; N]| { > + let slot = slot.cast::<T>(); > + for i in 0..N { > + let init = make_init(i); > + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. > + let ptr = unsafe { slot.add(i) }; > + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` > + // requirements. > + match unsafe { init.__init(ptr) } { > + Ok(()) => {} > + Err(e) => { > + // We now free every element that has been initialized before: > + for j in 0..i { > + let ptr = unsafe { slot.add(j) }; > + // SAFETY: The value was initialized in a previous iteration of the loop > + // and since we return `Err` below, the caller will consider the memory at > + // `slot` as uninitialized. > + unsafe { ptr::drop_in_place(ptr) }; > + }
The loop can be simplified like this:
ptr::drop_in_place(ptr::slice_from_raw_parts(slot, i));
Yes, this actually works and will run the destructor of each value.
Alice
| |