1#![cfg_attr(not(feature = "std"), no_std)]
2
3use alloc::{alloc::alloc, boxed::Box};
4use core::{alloc::Layout, mem::size_of, ptr::NonNull};
5
6extern crate alloc;
7
8pub unsafe trait BuildArray<C, F> {
15 unsafe fn build_into(space: *mut Self, build_component: &mut impl FnMut(*mut C));
16}
17
18unsafe impl<T, const N: usize> BuildArray<T, ()> for [T; N] {
19 unsafe fn build_into(space: *mut Self, build_component: &mut impl FnMut(*mut T)) {
20 let space = space as *mut T;
21
22 for n in 0..N {
23 let container_ptr = space.add(n);
24 build_component(container_ptr);
25 }
26 }
27}
28
29unsafe impl<T, Q, F, const N: usize> BuildArray<T, (F,)> for [Q; N]
30where
31 Q: BuildArray<T, F>,
32{
33 unsafe fn build_into(space: *mut Self, build_component: &mut impl FnMut(*mut T)) {
34 let space = space as *mut Q;
35
36 for n in 0..N {
37 let container_ptr = space.add(n);
38 Q::build_into(container_ptr, build_component);
39 }
40 }
41}
42
43pub fn with<T, A, F>(mut construct: impl FnMut() -> T) -> Box<A>
50where
51 A: BuildArray<T, F>,
52{
53 if size_of::<A>() == 0 {
54 return unsafe { Box::from_raw(NonNull::dangling().as_mut()) };
56 }
57
58 let space = unsafe { alloc(Layout::new::<A>()) };
60
61 #[cfg(all(test, not(miri)))]
62 {
63 for i in 0..size_of::<A>() {
64 unsafe { space.add(i).write(0x69) }
66 }
67 }
68
69 let space = space as *mut A;
71
72 let mut build_component = move |storage: *mut T| unsafe { storage.write(construct()) };
74
75 unsafe {
76 A::build_into(space, &mut build_component);
77 }
78
79 unsafe { Box::from_raw(space) }
81}
82
83pub fn from_default<T, A, F>() -> Box<A>
94where
95 A: BuildArray<T, F>,
96 T: Default,
97{
98 with(|| Default::default())
99}
100
101pub fn from_cloned<T, A, F>(val: &T) -> Box<A>
105where
106 A: BuildArray<T, F>,
107 T: Clone,
108{
109 with(|| val.clone())
110}
111
112#[cfg(test)]
113mod test {
114 use super::*;
115 #[test]
116 fn test_it_works() {
117 let mut n = 5;
118 let thing: Box<[[[i32; 5]; 5]; 5]> = with(|| {
119 n += 1;
120 n
121 });
122
123 #[cfg(feature = "std")]
124 println!("{:?}", thing);
125
126 let thing2: Box<[[[i32; 5]; 5]; 5]> = from_default::<i32, _, _>();
127
128 #[cfg(feature = "std")]
129 println!("{:?}", thing2);
130 }
131}