nanvm_lib/mem/flexible_array/
mod.rs1pub mod constructor;
2pub mod header;
3use core::{
4 marker::PhantomData,
5 mem::{align_of, size_of},
6 ptr::drop_in_place,
7 slice::{from_raw_parts, from_raw_parts_mut},
8};
9
10use self::header::FlexibleArrayHeader;
11
12use super::{field_layout::FieldLayout, object::Object};
13
14#[repr(transparent)]
15#[derive(Debug)]
16pub struct FlexibleArray<I, T: FlexibleArrayHeader = usize> {
17 pub header: T,
18 _0: PhantomData<I>,
19}
20
21impl<I, T: FlexibleArrayHeader> FlexibleArray<I, T> {
22 const FLEXIBLE_HEADER_LAYOUT: FieldLayout<T, I> = FieldLayout::align_to(align_of::<I>());
23 #[inline(always)]
24 pub fn items(&self) -> &[I] {
25 unsafe {
26 from_raw_parts(
27 Self::FLEXIBLE_HEADER_LAYOUT.to_adjacent(&self.header),
28 self.header.len(),
29 )
30 }
31 }
32 #[inline(always)]
33 pub fn items_mut(&mut self) -> &mut [I] {
34 unsafe {
35 from_raw_parts_mut(
36 Self::FLEXIBLE_HEADER_LAYOUT.into_adjacent_mut(&mut self.header),
37 self.header.len(),
38 )
39 }
40 }
41 #[inline(always)]
42 pub const fn flexible_size(len: usize) -> usize {
43 Self::FLEXIBLE_HEADER_LAYOUT.size + len * size_of::<I>()
44 }
45}
46
47impl<T: FlexibleArrayHeader, I> Object for FlexibleArray<I, T> {
48 const OBJECT_ALIGN: usize = Self::FLEXIBLE_HEADER_LAYOUT.align;
49 #[inline(always)]
50 fn object_size(&self) -> usize {
51 Self::flexible_size(self.header.len())
52 }
53 unsafe fn object_drop(&mut self) {
54 drop_in_place(self.items_mut());
55 drop_in_place(self);
56 }
57}
58
59#[cfg(test)]
60mod test {
61 use core::{
62 fmt::Debug,
63 marker::PhantomData,
64 mem::{align_of, forget, size_of},
65 sync::atomic::{AtomicUsize, Ordering},
66 };
67
68 use wasm_bindgen_test::wasm_bindgen_test;
69
70 use crate::{
71 common::ref_mut::RefMut,
72 mem::{field_layout::FieldLayout, object::Object},
73 };
74
75 use super::{FlexibleArray, FlexibleArrayHeader};
76
77 struct X<H, I>(H, PhantomData<I>);
78
79 impl<H: Into<usize> + Copy, I> FlexibleArrayHeader for X<H, I> {
80 fn len(&self) -> usize {
82 self.0.into()
83 }
84 }
85
86 #[repr(C)]
87 struct Y<H, I, const N: usize> {
88 len: H,
89 items: [I; N],
90 }
91
92 fn ptr<T>(x: &mut T) -> *mut T {
93 x as *mut T
94 }
95
96 #[test]
97 #[wasm_bindgen_test]
98 fn test_u8_5() {
99 let mut y = Y::<u16, u8, 5> {
100 len: 5,
101 items: [42, 43, 44, 45, 46],
102 };
103 let v = ptr(&mut y) as *mut FlexibleArray<u8, X<u16, u8>>;
104 unsafe {
105 assert_eq!((*v).header.len(), 5);
106 assert_eq!((*v).object_size(), 7);
107 let items = (*v).items_mut();
108 assert_eq!(items, &[42, 43, 44, 45, 46]);
109 }
110 }
111
112 #[test]
113 #[wasm_bindgen_test]
114 fn test_u32_3() {
115 let mut y = Y::<u16, u32, 3> {
116 len: 3,
117 items: [42, 43, 44],
118 };
119 let v = ptr(&mut y) as *mut FlexibleArray<u32, X<u16, u32>>;
120 unsafe {
121 assert_eq!((*v).header.len(), 3);
122 assert_eq!((*v).object_size(), 16);
123 let items = (*v).items_mut();
124 assert_eq!(items, &[42, 43, 44]);
125 }
126 }
127
128 fn generic_test<
129 H: Into<usize> + Copy + TryFrom<usize>,
130 I: PartialEq + Debug + Copy,
131 const N: usize,
132 >(
133 items: [I; N],
134 size: usize,
135 ) {
136 let old = items;
137 let mut y = Y::<H, I, N> {
138 len: unsafe { N.try_into().unwrap_unchecked() },
139 items,
140 };
141 let v = ptr(&mut y) as *mut FlexibleArray<I, X<H, I>>;
142 unsafe {
143 assert_eq!((*v).header.len(), N);
144 assert_eq!((*v).object_size(), size);
145 assert_eq!(&*(*v).items_mut(), &old[..]);
146 }
147 }
148
149 #[test]
150 #[wasm_bindgen_test]
151 fn test1() {
152 generic_test::<u8, u8, 1>([42], 2);
153 generic_test::<u16, u32, 6>([42, 56, 78, 90, 101, 102], 28);
154 generic_test::<u16, u8, 3>([90, 101, 102], 5);
155 }
156
157 #[repr(transparent)]
158 struct DropCount(*const AtomicUsize);
159
160 impl Drop for DropCount {
161 fn drop(&mut self) {
162 unsafe {
163 (*self.0).fetch_add(1, Ordering::Relaxed);
164 }
165 }
166 }
167
168 impl FlexibleArrayHeader for DropCount {
169 fn len(&self) -> usize {
171 3
172 }
173 }
174
175 #[repr(C)]
176 struct DropCountX {
177 header: DropCount,
178 items: [DropCount; 3],
179 }
180
181 #[test]
182 #[wasm_bindgen_test]
183 fn drop_test() {
184 let i = AtomicUsize::new(0);
185 {
186 let mut x = DropCountX {
187 header: DropCount(&i as *const AtomicUsize),
188 items: [
189 DropCount(&i as *const AtomicUsize),
190 DropCount(&i as *const AtomicUsize),
191 DropCount(&i as *const AtomicUsize),
192 ],
193 };
194 let v = unsafe { x.to_mut_ptr() as *mut FlexibleArray<DropCount, DropCount> };
195 unsafe {
196 assert_eq!((*v).header.len(), 3);
197 assert_eq!((*v).object_size(), size_of::<DropCountX>());
198 assert_eq!((*v).object_size(), size_of::<DropCount>() * 4);
199 let a = &*(*v).items_mut();
200 assert_eq!(a.len(), 3);
201 assert_eq!(a[0].0, &i as *const AtomicUsize);
202 assert_eq!(a[1].0, &i as *const AtomicUsize);
203 assert_eq!(a[2].0, &i as *const AtomicUsize);
204 }
205 assert_eq!(i.load(Ordering::Relaxed), 0);
206 unsafe { (*v).object_drop() };
207 assert_eq!(i.load(Ordering::Relaxed), 4);
208 forget(x);
209 }
210 assert_eq!(i.load(Ordering::Relaxed), 4);
211 }
212
213 #[repr(C)]
214 struct StaticVariable<T: FlexibleArrayHeader, I, const L: usize> {
215 header: T,
216 items: [I; L],
217 }
218
219 struct E();
220
221 impl FlexibleArrayHeader for E {
222 fn len(&self) -> usize {
224 3
225 }
226 }
227
228 const _: () = assert!(size_of::<StaticVariable<E, u64, 3>>() == 24);
229
230 const _: () = assert!(FlexibleArray::<u64, E>::OBJECT_ALIGN == 8);
231 const _: () = assert!(FlexibleArray::<u64, E>::FLEXIBLE_HEADER_LAYOUT.align == 8);
232 const _: () = assert!(size_of::<E>() == 0);
233 const _FL: FieldLayout<E, u64> = FieldLayout::align_to(align_of::<u64>());
234 const _: () = assert!(_FL.align == 8);
235 const _: () = assert!(_FL.size == 0);
236 const _: () = assert!(FlexibleArray::<u64, E>::FLEXIBLE_HEADER_LAYOUT.size == 0);
237
238 #[test]
239 #[wasm_bindgen_test]
240 fn empty_header_test() {
241 static mut I: u8 = 0;
242 unsafe { I = 0 };
243 struct EmptyHeader();
244 impl Drop for EmptyHeader {
245 fn drop(&mut self) {
246 unsafe { I += 1 };
247 }
248 }
249 impl FlexibleArrayHeader for EmptyHeader {
250 fn len(&self) -> usize {
252 3
253 }
254 }
255 let items: [u64; 3] = [0x1234567890abcdef, 0x1234567890abcdef, 0x1234567890abcdef];
256 {
257 let mut x = StaticVariable::<EmptyHeader, u64, 3> {
258 header: EmptyHeader(),
259 items,
260 };
261 let y = unsafe { &mut *(x.to_mut_ptr() as *mut FlexibleArray<u64, EmptyHeader>) };
262 assert_eq!(size_of::<StaticVariable<EmptyHeader, u64, 3>>(), 24);
263 assert_eq!(size_of::<EmptyHeader>(), 0);
264 assert_eq!(y.object_size(), 24);
265 assert_eq!(
266 y.items_mut(),
267 &[0x1234567890abcdef, 0x1234567890abcdef, 0x1234567890abcdef]
268 );
269 assert_eq!(unsafe { I }, 0);
270 unsafe { y.object_drop() };
271 assert_eq!(unsafe { I }, 1);
272 forget(x)
273 }
274 assert_eq!(unsafe { I }, 1);
275 }
276}