1use core::mem;
2
3use crate::{
4 collect::{Collect, Trace},
5 context::Mutation,
6 gc::Gc,
7};
8
9#[derive(Copy, Clone)]
18pub struct ZstCache<'gc, const MAX_ALIGN: usize> {
19 cached_ptr: Gc<'gc, ()>,
20}
21
22unsafe impl<'gc, const MAX_ALIGN: usize> Collect<'gc> for ZstCache<'gc, MAX_ALIGN> {
23 const NEEDS_TRACE: bool = true;
24
25 fn trace<T: Trace<'gc>>(&self, cc: &mut T) {
26 cc.trace_gc(self.cached_ptr);
27 }
28}
29
30impl<'gc, const MAX_ALIGN: usize> ZstCache<'gc, MAX_ALIGN>
31where
32 Alignment<MAX_ALIGN>: ValidAlignment,
33{
34 pub fn new(mc: &Mutation<'gc>) -> Self {
35 let cached_ptr = Gc::erase(Gc::new_static(
36 mc,
37 <Alignment<MAX_ALIGN> as HasAlignedType>::AlignedType::default(),
38 ));
39 ZstCache { cached_ptr }
40 }
41
42 pub fn cached_ptr(&self) -> Gc<'gc, ()> {
46 self.cached_ptr
47 }
48
49 #[inline]
51 pub fn is_cached<T: ?Sized>(&self, p: Gc<'gc, T>) -> bool {
52 Gc::ptr_eq(self.cached_ptr, Gc::erase(p))
53 }
54
55 #[inline]
62 pub fn alloc_zst<T: 'gc>(&self) -> Option<Gc<'gc, T>> {
63 if mem::size_of::<T>() == 0 && mem::align_of::<T>() <= MAX_ALIGN {
64 debug_assert!(Gc::as_ptr(self.cached_ptr).align_offset(mem::align_of::<T>()) == 0);
65 Some(unsafe { Gc::cast::<T>(self.cached_ptr) })
68 } else {
69 None
70 }
71 }
72
73 #[inline]
75 pub fn alloc<T: Collect<'gc>>(&self, mc: &Mutation<'gc>, t: T) -> Gc<'gc, T> {
76 if let Some(ptr) = self.alloc_zst() {
77 ptr
78 } else {
79 Gc::new(mc, t)
80 }
81 }
82
83 #[inline]
85 pub fn alloc_static<T: 'static>(&self, mc: &Mutation<'gc>, t: T) -> Gc<'gc, T> {
86 if let Some(ptr) = self.alloc_zst() {
87 ptr
88 } else {
89 Gc::new_static(mc, t)
90 }
91 }
92}
93
94pub struct Alignment<const ALIGN: usize>;
95
96#[allow(private_bounds)]
101pub trait ValidAlignment: HasAlignedType {}
102
103impl<T: HasAlignedType> ValidAlignment for T {}
104
105trait HasAlignedType {
106 type AlignedType: Default;
107}
108
109macro_rules! impl_has_aligned_type {
110 ($($align:expr),* $(,)?) => {
111 $(
112 const _: () = {
113 #[repr(align($align))]
114 struct AlignedType;
115
116 impl Default for AlignedType {
117 #[inline(always)]
118 fn default() -> Self {
119 Self
120 }
121 }
122
123 impl HasAlignedType for Alignment<$align> {
124 type AlignedType = AlignedType;
125 }
126 };
127 )*
128 };
129}
130
131impl_has_aligned_type!(
132 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072,
133 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728,
134 268435456, 536870912
135);