Skip to content

Commit 9e49439

Browse files
y86-devojeda
authored andcommitted
rust: init: add functions to create array initializers
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 <[email protected]> Reviewed-by: Björn Roy Baron <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Martin Rodriguez Reboredo <[email protected]> Signed-off-by: Benno Lossin <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Cleaned a couple trivial nits. ] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 35e7fca commit 9e49439

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

Diff for: rust/kernel/init.rs

+88
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@
202202
use crate::{
203203
error::{self, Error},
204204
sync::UniqueArc,
205+
types::ScopeGuard,
205206
};
206207
use alloc::boxed::Box;
207208
use core::{
@@ -867,6 +868,93 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
867868
unsafe { init_from_closure(|_| Ok(())) }
868869
}
869870

871+
/// Initializes an array by initializing each element via the provided initializer.
872+
///
873+
/// # Examples
874+
///
875+
/// ```rust
876+
/// use kernel::{error::Error, init::init_array_from_fn};
877+
/// let array: Box<[usize; 1_000]>= Box::init::<Error>(init_array_from_fn(|i| i)).unwrap();
878+
/// assert_eq!(array.len(), 1_000);
879+
/// ```
880+
pub fn init_array_from_fn<I, const N: usize, T, E>(
881+
mut make_init: impl FnMut(usize) -> I,
882+
) -> impl Init<[T; N], E>
883+
where
884+
I: Init<T, E>,
885+
{
886+
let init = move |slot: *mut [T; N]| {
887+
let slot = slot.cast::<T>();
888+
// Counts the number of initialized elements and when dropped drops that many elements from
889+
// `slot`.
890+
let mut init_count = ScopeGuard::new_with_data(0, |i| {
891+
// We now free every element that has been initialized before:
892+
// SAFETY: The loop initialized exactly the values from 0..i and since we
893+
// return `Err` below, the caller will consider the memory at `slot` as
894+
// uninitialized.
895+
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) };
896+
});
897+
for i in 0..N {
898+
let init = make_init(i);
899+
// SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`.
900+
let ptr = unsafe { slot.add(i) };
901+
// SAFETY: The pointer is derived from `slot` and thus satisfies the `__init`
902+
// requirements.
903+
unsafe { init.__init(ptr) }?;
904+
*init_count += 1;
905+
}
906+
init_count.dismiss();
907+
Ok(())
908+
};
909+
// SAFETY: The initializer above initializes every element of the array. On failure it drops
910+
// any initialized elements and returns `Err`.
911+
unsafe { init_from_closure(init) }
912+
}
913+
914+
/// Initializes an array by initializing each element via the provided initializer.
915+
///
916+
/// # Examples
917+
///
918+
/// ```rust
919+
/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex};
920+
/// let array: Arc<[Mutex<usize>; 1_000]>=
921+
/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i))).unwrap();
922+
/// assert_eq!(array.len(), 1_000);
923+
/// ```
924+
pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
925+
mut make_init: impl FnMut(usize) -> I,
926+
) -> impl PinInit<[T; N], E>
927+
where
928+
I: PinInit<T, E>,
929+
{
930+
let init = move |slot: *mut [T; N]| {
931+
let slot = slot.cast::<T>();
932+
// Counts the number of initialized elements and when dropped drops that many elements from
933+
// `slot`.
934+
let mut init_count = ScopeGuard::new_with_data(0, |i| {
935+
// We now free every element that has been initialized before:
936+
// SAFETY: The loop initialized exactly the values from 0..i and since we
937+
// return `Err` below, the caller will consider the memory at `slot` as
938+
// uninitialized.
939+
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) };
940+
});
941+
for i in 0..N {
942+
let init = make_init(i);
943+
// SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`.
944+
let ptr = unsafe { slot.add(i) };
945+
// SAFETY: The pointer is derived from `slot` and thus satisfies the `__init`
946+
// requirements.
947+
unsafe { init.__pinned_init(ptr) }?;
948+
*init_count += 1;
949+
}
950+
init_count.dismiss();
951+
Ok(())
952+
};
953+
// SAFETY: The initializer above initializes every element of the array. On failure it drops
954+
// any initialized elements and returns `Err`.
955+
unsafe { pin_init_from_closure(init) }
956+
}
957+
870958
// SAFETY: Every type can be initialized by-value.
871959
unsafe impl<T, E> Init<T, E> for T {
872960
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {

0 commit comments

Comments
 (0)