heap_arr/
lib.rs

1#![warn(clippy::pedantic)]
2#![no_std]
3
4use core::mem::{self, MaybeUninit};
5
6use alloc::{
7    alloc::{handle_alloc_error, Layout, LayoutError},
8    boxed::Box,
9};
10
11extern crate alloc;
12
13/// Allocates `[T; N]` on the heap and initializes its entries to `initial`.
14///
15/// For now, this function uses the global allocator. This will change once the
16/// [`Allocator`](core::alloc::Allocator) trait becomes stable.
17///
18/// # Safety
19/// The result of this function is undefined if `mem::size_of::<T>() == 0`, or
20/// if `N == 0`
21///
22/// # Errors
23/// See [`Layout::array`]
24pub unsafe fn new<T, const N: usize>(initial: &T) -> Result<Box<[T; N]>, LayoutError>
25where
26    T: Clone,
27{
28    let mut arr = new_uninit::<T, N>()?;
29    for v in arr.as_mut() {
30        v.write(initial.clone());
31    }
32
33    Ok(mem::transmute(arr))
34}
35
36/// Allocates `[T; N]` on the heap and initializes its entries to `T::default()`.
37///
38/// For now, this function uses the global allocator. This will change once the
39/// [`Allocator`](core::alloc::Allocator) trait becomes stable.
40///
41/// # Safety
42/// The result of this function is undefined if `mem::size_of::<T>() == 0`, or
43/// if `N == 0`
44///
45/// # Errors
46/// See [`Layout::array`]
47pub unsafe fn new_default<T, const N: usize>() -> Result<Box<[T; N]>, LayoutError>
48where
49    T: Default,
50{
51    let mut arr = new_uninit::<T, N>()?;
52    for v in arr.as_mut() {
53        v.write(T::default());
54    }
55
56    Ok(mem::transmute(arr))
57}
58
59/// Allocates `[T; N]` on the heap.
60///
61/// For now, this function uses the global allocator. This will change once the
62/// [`Allocator`](core::alloc::Allocator) trait becomes stable.
63///
64/// # Safety
65/// The result of this function is undefined if `mem::size_of::<T>() == 0`, or
66/// if `N == 0`
67///
68/// # Errors
69/// See [`Layout::array`]
70///
71/// # Examples
72/// ```
73/// use std::mem;
74///
75/// unsafe {
76///     const LEN: usize = 1024 * 1024 * 1024;
77///
78///     let mut arr = heap_arr::new_uninit::<usize, LEN>().unwrap();
79///     for (i, v) in arr.as_mut().iter_mut().enumerate() {
80///         v.write(i);
81///     }
82///
83///     let arr: Box::<[usize; LEN]> = mem::transmute(arr);
84/// }
85/// ```
86pub unsafe fn new_uninit<T, const N: usize>() -> Result<Box<[MaybeUninit<T>; N]>, LayoutError> {
87    let layout = Layout::array::<T>(N)?;
88    let ptr = alloc::alloc::alloc(layout);
89
90    if ptr.is_null() {
91        handle_alloc_error(layout);
92    }
93    Ok(Box::from_raw(ptr.cast()))
94}
95
96#[cfg(test)]
97mod tests {
98    #[test]
99    fn test_new() {
100        let arr = unsafe { super::new::<Option<bool>, 1_000>(&Some(false)).unwrap() };
101        assert_eq!(arr.len(), 1_000);
102        assert_eq!(arr[999], Some(false));
103    }
104
105    #[test]
106    fn test_default() {
107        let arr = unsafe { super::new_default::<Option<bool>, 1_000>().unwrap() };
108        assert_eq!(arr.len(), 1_000);
109        assert_eq!(arr[999], None);
110    }
111
112    #[test]
113    fn test_uninit() {
114        let _ = unsafe { super::new_uninit::<u64, 1_000>().unwrap() };
115    }
116}