rstsr_common/
alloc_vec.rs

1extern crate alloc;
2use crate::prelude_dev::*;
3use core::ptr::NonNull;
4
5/// Create an uninitialized vector with the given size.
6///
7/// This function depends on `aligned_alloc` feature.
8/// If `aligned_alloc` is enabled, it will align at 64-bit when size of vector
9/// elements is larger than 128.
10///
11/// # Safety
12///
13/// Caller must ensure that the vector is properly initialized before using it.
14///
15/// This is not a very good function, since `set_len` on uninitialized memory is
16/// undefined-behavior (UB).
17/// Nevertheless, if `T` is some type of `MaybeUninit`, then this will not UB.
18pub unsafe fn uninitialized_vec<T>(size: usize) -> Result<Vec<T>> {
19    #[cfg(not(feature = "aligned_alloc"))]
20    return unaligned_uninitialized_vec(size);
21    #[cfg(feature = "aligned_alloc")]
22    return aligned_uninitialized_vec::<T, 128>(size, 64);
23}
24
25/// Create an unaligned uninitialized vector with the given size.
26///
27/// # Safety
28///
29/// Caller must ensure that the vector is properly initialized before using it.
30///
31/// This is not a very good function, since `set_len` on uninitialized memory is
32/// undefined-behavior (UB).
33/// Nevertheless, if `T` is some type of `MaybeUninit`, then this will not UB.
34#[allow(clippy::uninit_vec)]
35pub unsafe fn unaligned_uninitialized_vec<T>(size: usize) -> Result<Vec<T>> {
36    let mut v: Vec<T> = vec![];
37    v.try_reserve_exact(size)?;
38    unsafe { v.set_len(size) };
39    return Ok(v);
40}
41
42/// Create an uninitialized vector with the given size and alignment.
43///
44/// - Error: `LayoutError` if the layout cannot be created.
45/// - Ok(None): if the size is 0 or allocation fails.
46/// - Ok(Some): pointer to the allocated memory.
47///
48/// <https://users.rust-lang.org/t/how-can-i-allocate-aligned-memory-in-rust/33293>
49pub fn aligned_alloc(numbytes: usize, alignment: usize) -> Result<Option<NonNull<()>>> {
50    if numbytes == 0 {
51        return Ok(None);
52    }
53    let layout = alloc::alloc::Layout::from_size_align(numbytes, alignment)?;
54    let pointer = NonNull::new(unsafe { alloc::alloc::alloc(layout) }).map(|p| p.cast::<()>());
55    Ok(pointer)
56}
57
58/// Create an conditionally aligned uninitialized vector with the given size.
59///
60/// The alignment is always 64 bytes.
61///
62/// - `N`: condition for alignment; if `N < size`, then this function will not allocate aligned
63///   vector.
64///
65/// # Safety
66///
67/// Caller must ensure that the vector is properly initialized before using it.
68///
69/// This is not a very good function, since `set_len` on uninitialized memory is
70/// undefined-behavior (UB).
71/// Nevertheless, if `T` is some type of `MaybeUninit`, then this will not UB.
72#[allow(clippy::uninit_vec)]
73pub unsafe fn aligned_uninitialized_vec<T, const N: usize>(size: usize, alignment: usize) -> Result<Vec<T>> {
74    if size == 0 {
75        return Ok(vec![]);
76    } else if size < N {
77        return unaligned_uninitialized_vec(size);
78    } else {
79        let sizeof = core::mem::size_of::<T>();
80        let pointer = aligned_alloc(size * sizeof, alignment)?;
81        if let Some(pointer) = pointer {
82            let mut v = Vec::from_raw_parts(pointer.as_ptr() as *mut T, size, size);
83            unsafe { v.set_len(size) };
84            return Ok(v);
85        } else {
86            rstsr_raise!(RuntimeError, "Allocation failed (probably due to out-of-memory)")?
87        }
88    }
89}