#![cfg_attr(not(feature = "std"), no_std)]
use alloc::{alloc::alloc, boxed::Box};
use core::{alloc::Layout, mem::size_of, ptr::NonNull};
extern crate alloc;
pub unsafe trait BuildArray<C, F> {
unsafe fn build_into(space: *mut Self, build_component: &mut impl FnMut(*mut C));
}
unsafe impl<T, const N: usize> BuildArray<T, ()> for [T; N] {
unsafe fn build_into(space: *mut Self, build_component: &mut impl FnMut(*mut T)) {
let space = space as *mut T;
for n in 0..N {
let container_ptr = space.add(n);
build_component(container_ptr);
}
}
}
unsafe impl<T, Q, F, const N: usize> BuildArray<T, (F,)> for [Q; N]
where
Q: BuildArray<T, F>,
{
unsafe fn build_into(space: *mut Self, build_component: &mut impl FnMut(*mut T)) {
let space = space as *mut Q;
for n in 0..N {
let container_ptr = space.add(n);
Q::build_into(container_ptr, build_component);
}
}
}
pub fn with<T, A, F>(mut construct: impl FnMut() -> T) -> Box<A>
where
A: BuildArray<T, F>,
{
if size_of::<A>() == 0 {
return unsafe { Box::from_raw(NonNull::dangling().as_mut()) };
}
let space = unsafe { alloc(Layout::new::<A>()) };
#[cfg(all(test, not(miri)))]
{
for i in 0..size_of::<A>() {
unsafe { space.add(i).write(0x69) }
}
}
let space = space as *mut A;
let mut build_component = move |storage: *mut T| unsafe { storage.write(construct()) };
unsafe {
A::build_into(space, &mut build_component);
}
unsafe { Box::from_raw(space) }
}
pub fn from_default<T, A, F>() -> Box<A>
where
A: BuildArray<T, F>,
T: Default,
{
with(|| Default::default())
}
pub fn from_cloned<T, A, F>(val: &T) -> Box<A>
where
A: BuildArray<T, F>,
T: Clone,
{
with(|| val.clone())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_it_works() {
let mut n = 5;
let thing: Box<[[[i32; 5]; 5]; 5]> = with(|| {
n += 1;
n
});
#[cfg(feature = "std")]
println!("{:?}", thing);
let thing2: Box<[[[i32; 5]; 5]; 5]> = from_default::<i32, _, _>();
#[cfg(feature = "std")]
println!("{:?}", thing2);
}
}