storage_api/
global_storage.rs

1extern crate alloc;
2
3use crate::{MultipleStorage, Storage, StorageAllocError, StorageHandle};
4use core::{alloc::Layout, ptr::NonNull};
5
6/// The [`StorageHandle`] for [`Global`],
7/// this is a wrapper around a [`NonNull<()>`]
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct GlobalHandle(pub NonNull<()>);
10
11unsafe impl Send for GlobalHandle {}
12unsafe impl Sync for GlobalHandle {}
13
14impl StorageHandle for GlobalHandle {}
15
16/// This represents the global allocator registered with the `#[global_allocator]` attribute
17///
18/// See [`GlobalAlloc`](alloc::alloc::GlobalAlloc) for more info
19#[derive(Default, Clone, Copy)]
20pub struct Global;
21
22unsafe impl Storage for Global {
23    type Handle = GlobalHandle;
24
25    unsafe fn resolve(&self, handle: Self::Handle) -> NonNull<()> {
26        handle.0
27    }
28
29    fn allocate(&self, layout: Layout) -> Result<(Self::Handle, usize), StorageAllocError> {
30        match layout.size() {
31            0 => Ok((
32                GlobalHandle(unsafe {
33                    NonNull::new_unchecked(core::ptr::without_provenance_mut(layout.align()))
34                }),
35                0,
36            )),
37            size => match NonNull::new(unsafe { alloc::alloc::alloc(layout) }.cast()) {
38                Some(ptr) => Ok((GlobalHandle(ptr), size)),
39                None => Err(StorageAllocError),
40            },
41        }
42    }
43
44    unsafe fn deallocate(&self, layout: Layout, handle: Self::Handle) {
45        match layout.size() {
46            0 => (),
47            _ => unsafe { alloc::alloc::dealloc(handle.0.as_ptr().cast(), layout) },
48        }
49    }
50
51    unsafe fn grow(
52        &self,
53        old_layout: Layout,
54        new_layout: Layout,
55        handle: Self::Handle,
56    ) -> Result<(Self::Handle, usize), StorageAllocError> {
57        unsafe { self.realloc(old_layout, new_layout, handle.0) }
58    }
59
60    unsafe fn shrink(
61        &self,
62        old_layout: Layout,
63        new_layout: Layout,
64        handle: Self::Handle,
65    ) -> Result<(Self::Handle, usize), StorageAllocError> {
66        unsafe { self.realloc(old_layout, new_layout, handle.0) }
67    }
68}
69
70impl Global {
71    unsafe fn realloc(
72        &self,
73        old_layout: Layout,
74        new_layout: Layout,
75        old_alloc: NonNull<()>,
76    ) -> Result<(GlobalHandle, usize), StorageAllocError> {
77        match (old_layout.size(), new_layout.size()) {
78            (0, 0) => Ok((GlobalHandle(old_alloc), 0)),
79            (0, _) => self.allocate(new_layout),
80            (_, 0) => {
81                let new_alloc = self.allocate(new_layout)?;
82                unsafe {
83                    self.deallocate(old_layout, GlobalHandle(old_alloc));
84                }
85                Ok(new_alloc)
86            }
87            (old_size, new_size) => {
88                if old_layout.align() >= new_layout.align() {
89                    let ptr = NonNull::new(
90                        unsafe {
91                            alloc::alloc::realloc(old_alloc.as_ptr().cast(), old_layout, new_size)
92                        }
93                        .cast(),
94                    )
95                    .ok_or(StorageAllocError)?;
96                    Ok((GlobalHandle(ptr), new_size))
97                } else {
98                    let (new_alloc, _) = self.allocate(new_layout)?;
99                    unsafe {
100                        core::ptr::copy_nonoverlapping(
101                            old_alloc.as_ptr().cast::<u8>(),
102                            new_alloc.0.as_ptr().cast::<u8>(),
103                            old_size,
104                        );
105                        self.deallocate(old_layout, GlobalHandle(old_alloc));
106                    }
107                    Ok((new_alloc, new_size))
108                }
109            }
110        }
111    }
112}
113
114unsafe impl MultipleStorage for Global {}