1use alloc::alloc::{alloc, dealloc, handle_alloc_error};
2use core::{alloc::Layout, ptr::NonNull};
3
4use crate::item::Item;
5
6#[repr(C)]
7struct Header {
8 item: &'static Item,
9}
10
11fn layout(body: Layout) -> (Layout, usize) {
12 Layout::new::<Header>()
13 .extend(body)
14 .unwrap_or_else(|_| handle_alloc_error(body))
15}
16
17impl Header {
18 #[inline]
19 fn body(&self) -> NonNull<()> {
20 let (_, offset) = layout(self.item.layout);
21 unsafe {
22 NonNull::new_unchecked(self as *const Self as *mut Self)
24 .cast::<()>()
25 .byte_add(offset)
26 }
27 }
28}
29
30impl Drop for Header {
31 fn drop(&mut self) {
32 (self.item.drop)(self.body());
33 }
34}
35
36pub(crate) struct ItemBox {
37 ptr: NonNull<Header>,
38}
39
40unsafe impl Send for ItemBox {}
41unsafe impl Sync for ItemBox {}
42
43impl ItemBox {
44 pub(crate) fn new(item: &'static Item) -> Self {
45 let (layout, offset) = layout(item.layout);
46 let ptr = NonNull::new(unsafe { alloc(layout) })
47 .unwrap_or_else(|| handle_alloc_error(layout))
48 .cast();
49
50 unsafe {
51 ptr.write(Header { item });
52 (item.init)(ptr.cast().byte_add(offset));
53 }
54
55 Self { ptr }
56 }
57
58 #[inline]
59 fn header(&self) -> &Header {
60 unsafe { self.ptr.as_ref() }
61 }
62}
63
64impl<T> AsRef<T> for ItemBox {
65 #[inline]
66 fn as_ref(&self) -> &T {
67 unsafe { self.header().body().cast().as_ref() }
68 }
69}
70
71impl<T> AsMut<T> for ItemBox {
72 #[inline]
73 fn as_mut(&mut self) -> &mut T {
74 unsafe { self.header().body().cast().as_mut() }
75 }
76}
77
78impl Drop for ItemBox {
79 fn drop(&mut self) {
80 let item = self.header().item;
81 let (layout, offset) = layout(item.layout);
82 unsafe {
83 (item.drop)(self.ptr.cast().byte_add(offset));
84 dealloc(self.ptr.cast().as_ptr(), layout);
85 }
86 }
87}