1use std::{ffi::c_void, ptr::NonNull};
2
3use crate::{GcToken, gc};
4
5pub fn from_fn<T>(
6 _token: &impl GcToken,
7 len: usize,
8 mut f: impl FnMut(usize) -> T,
9) -> &'static mut [T] {
10 let vec = VecInner::<T>::new(len);
11 for i in 0..len {
12 unsafe { vec.as_ptr().add(i).write(f(i)) };
13 }
14 vec.set_len(len);
15
16 register_finalizer(vec.as_ptr());
17
18 unsafe { std::slice::from_raw_parts_mut(vec.as_ptr(), len) }
19}
20
21pub fn repeat<T: Clone>(token: &impl GcToken, val: T, len: usize) -> &'static mut [T] {
22 from_fn(token, len, |_| val.clone())
23}
24
25pub fn from_iter<T, I: IntoIterator<Item = T>>(_token: &impl GcToken, iter: I) -> &'static mut [T] {
26 let iter = iter.into_iter();
27 let (lower, _) = iter.size_hint();
28
29 let mut cap = lower.max(1);
30 let mut vec = VecInner::<T>::new(cap);
31 let mut len = 0;
32 for item in iter {
33 if len == cap {
34 cap = cap.checked_mul(2).expect("Capacity overflow");
35 let new_vec = VecInner::<T>::new(cap);
36 unsafe { std::ptr::copy_nonoverlapping(vec.as_ptr(), new_vec.as_ptr(), len) };
37 vec = new_vec;
38 }
39 unsafe { vec.as_ptr().add(len).write(item) };
40 len += 1;
41 }
42 vec.set_len(len);
43
44 register_finalizer(vec.as_ptr());
45
46 unsafe { std::slice::from_raw_parts_mut(vec.as_ptr(), len) }
47}
48
49fn register_finalizer<T>(ptr: *mut T) {
50 if std::mem::needs_drop::<T>() {
51 extern "C" fn finalizer<T>(obj: *mut c_void, _: *mut c_void) {
52 let vec = VecInner(unsafe { NonNull::new_unchecked(obj as *mut T) });
53 let len = vec.num_to_drop();
54 for i in 0..len {
55 unsafe { std::ptr::drop_in_place(vec.as_ptr().add(i)) };
56 }
57 }
58
59 unsafe {
60 gc::GC_register_finalizer(
61 ptr as *mut std::ffi::c_void,
62 Some(finalizer::<T>),
63 std::ptr::null_mut(),
64 std::ptr::null_mut(),
65 std::ptr::null_mut(),
66 );
67 }
68 }
69}
70
71struct VecInner<T>(NonNull<T>);
72
73impl<T> VecInner<T> {
74 fn new(cap: usize) -> Self {
75 if std::mem::needs_drop::<T>() {
76 let padding = usize::max(std::mem::size_of::<usize>(), std::mem::size_of::<T>());
77 let alignment = usize::max(std::mem::align_of::<usize>(), std::mem::align_of::<T>());
78
79 let ptr = unsafe {
80 gc::GC_memalign(
81 std::mem::size_of::<T>().strict_mul(cap).strict_add(padding),
82 alignment,
83 ) as *mut T
84 };
85 let ptr = unsafe {
86 NonNull::new(ptr)
87 .expect("Allocation failed")
88 .byte_add(padding)
89 };
90 VecInner(ptr)
91 } else {
92 let ptr = unsafe {
93 gc::GC_memalign(
94 std::mem::size_of::<T>().strict_mul(cap),
95 std::mem::align_of::<T>(),
96 ) as *mut T
97 };
98 let ptr = NonNull::new(ptr).expect("Allocation failed");
99 VecInner(ptr)
100 }
101 }
102
103 fn as_ptr(&self) -> *mut T {
104 self.0.as_ptr()
105 }
106
107 fn num_to_drop(&self) -> usize {
108 if std::mem::needs_drop::<T>() {
109 let p_len =
110 unsafe { self.0.as_ptr().byte_sub(std::mem::size_of::<usize>()) as *const usize };
111 unsafe { p_len.read() }
112 } else {
113 0
114 }
115 }
116
117 fn set_len(&self, len: usize) {
118 if std::mem::needs_drop::<T>() {
119 let p_len =
120 unsafe { self.0.as_ptr().byte_sub(std::mem::size_of::<usize>()) as *mut usize };
121 unsafe { p_len.write(len) };
122 }
123 }
124}