Skip to main content

bump_scope/features/
allocator_util.rs

1// spellchecker:off because of "othr"
2macro_rules! allocator_compat_wrapper {
3    (
4        $(#[$attr:meta])*
5        struct $struct:ident for $othr:ident
6    ) => {
7        $(#[$attr])*
8        #[repr(transparent)]
9        #[derive(Debug, Default, Clone)]
10        pub struct $struct<A: ?Sized>(pub A);
11
12        impl<A: ?Sized> $struct<A> {
13            #[inline(always)]
14            #[expect(missing_docs)]
15            pub fn from_ref(allocator: &A) -> &Self {
16                unsafe { &*(core::ptr::from_ref(allocator) as *const Self) }
17            }
18
19            #[inline(always)]
20            #[expect(missing_docs)]
21            pub fn from_mut(allocator: &mut A) -> &mut Self {
22                unsafe { &mut *(core::ptr::from_mut(allocator) as *mut Self) }
23            }
24        }
25
26        impl_allocator_via_allocator! {
27            self;
28
29            use {&self.0} for crate as $othr impl[A: ?Sized + $othr::alloc::Allocator] $struct<A>
30            use {&self.0} for $othr as crate impl[A: ?Sized + crate::alloc::Allocator] $struct<A>
31        }
32
33        #[test]
34        fn test_compat() {
35            use core::{alloc::Layout, ptr::NonNull};
36
37            #[derive(Clone)]
38            struct OthrAllocator;
39
40            unsafe impl $othr::alloc::Allocator for OthrAllocator {
41                fn allocate(&self, _: Layout) -> Result<NonNull<[u8]>, $othr::alloc::AllocError> {
42                    unimplemented!()
43                }
44
45                unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {
46                    unimplemented!()
47                }
48            }
49
50            fn is_base_allocator<T: $crate::alloc::Allocator>(_: T) {}
51
52            #[cfg(feature = "alloc")]
53            is_base_allocator(Global);
54            is_base_allocator($struct(OthrAllocator));
55            is_base_allocator($struct::from_ref(&OthrAllocator));
56
57            struct CrateAllocator;
58
59            unsafe impl $crate::alloc::Allocator for CrateAllocator {
60                fn allocate(&self, _: Layout) -> Result<NonNull<[u8]>, $crate::alloc::AllocError> {
61                    unimplemented!()
62                }
63
64                unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {
65                    unimplemented!()
66                }
67            }
68
69            fn is_othr_allocator<T: $othr::alloc::Allocator>(_: T) {}
70
71            is_othr_allocator($struct(CrateAllocator));
72            is_othr_allocator($struct::from_ref(&CrateAllocator));
73        }
74    };
75}
76// spellchecker:on
77
78macro_rules! impl_allocator_via_allocator {
79    (
80        $self:ident;
81        $(
82            $(#[$attr:meta])*
83            use {$accessor:expr} for $target_crate:ident as $source_crate:ident
84            impl [$($($args:tt)+)?]
85            $ty:ty
86            $(where [$($bounds:tt)*])?
87        )*
88    ) => {
89        $(
90            const _: () = {
91                use core::{alloc::Layout, ptr::NonNull};
92
93                use $target_crate::alloc::{
94                    Allocator as TargetAllocator,
95                    AllocError as TargetAllocError,
96                };
97
98                use $source_crate::alloc::{
99                    Allocator as SourceAllocator,
100                };
101
102                $(#[$attr])*
103                unsafe impl $(<$($args)*>)? TargetAllocator for $ty
104                $(where $($bounds)*)?
105                {
106                    #[inline(always)]
107                    fn allocate(&$self, layout: Layout) -> Result<NonNull<[u8]>, TargetAllocError> {
108                        SourceAllocator::allocate($accessor, layout).map_err(Into::into)
109                    }
110
111                    #[inline(always)]
112                    unsafe fn deallocate(&$self, ptr: NonNull<u8>, layout: Layout) {
113                        unsafe { SourceAllocator::deallocate($accessor, ptr, layout) };
114                    }
115
116                    #[inline(always)]
117                    unsafe fn grow(
118                        &$self,
119                        ptr: NonNull<u8>,
120                        old_layout: Layout,
121                        new_layout: Layout,
122                    ) -> Result<NonNull<[u8]>, TargetAllocError> {
123                        unsafe { SourceAllocator::grow($accessor, ptr, old_layout, new_layout).map_err(Into::into) }
124                    }
125
126                    #[inline(always)]
127                    unsafe fn grow_zeroed(
128                        &$self,
129                        ptr: NonNull<u8>,
130                        old_layout: Layout,
131                        new_layout: Layout,
132                    ) -> Result<NonNull<[u8]>, TargetAllocError> {
133                        unsafe {
134                            SourceAllocator::grow_zeroed($accessor, ptr, old_layout, new_layout).map_err(Into::into)
135                        }
136                    }
137
138                    #[inline(always)]
139                    unsafe fn shrink(
140                        &$self,
141                        ptr: NonNull<u8>,
142                        old_layout: Layout,
143                        new_layout: Layout,
144                    ) -> Result<NonNull<[u8]>, TargetAllocError> {
145                        unsafe { SourceAllocator::shrink($accessor, ptr, old_layout, new_layout).map_err(Into::into) }
146                    }
147                }
148            };
149        )*
150    };
151}
152
153pub(crate) use allocator_compat_wrapper;
154pub(crate) use impl_allocator_via_allocator;