musli_core/alloc/
global.rs1use core::alloc::Layout;
2use core::cmp;
3use core::mem::{align_of, size_of};
4use core::ptr::NonNull;
5
6use rust_alloc::alloc;
7
8use super::{Alloc, AllocError, Allocator, FromAllocator, GlobalAllocator, Vec};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[non_exhaustive]
36pub struct Global;
37
38impl Global {
39 #[inline]
41 pub const fn new() -> Self {
42 Self
43 }
44}
45
46impl Default for Global {
47 #[inline]
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53unsafe impl GlobalAllocator for Global {
54 #[inline]
55 fn __do_not_implement() {}
56
57 #[inline]
58 fn new() -> Self {
59 Self
60 }
61
62 #[inline]
63 fn clone_alloc<T>(alloc: &Self::Alloc<T>) -> Self::Alloc<T> {
64 if size_of::<T>() == 0 {
65 return GlobalAlloc {
68 data: NonNull::dangling(),
69 size: alloc.size,
70 };
71 }
72
73 if alloc.size == 0 {
74 return GlobalAlloc::DANGLING;
75 }
76
77 unsafe {
78 let layout =
80 Layout::from_size_align_unchecked(alloc.size * size_of::<T>(), align_of::<T>());
81 let data = alloc::alloc(layout);
82
83 if data.is_null() {
84 alloc::handle_alloc_error(layout);
85 }
86
87 GlobalAlloc {
88 data: NonNull::new_unchecked(data).cast(),
89 size: alloc.size,
90 }
91 }
92 }
93
94 #[inline]
95 unsafe fn slice_from_raw_parts<T>(ptr: NonNull<T>, len: usize) -> Self::Alloc<T> {
96 GlobalAlloc {
97 data: ptr,
98 size: len,
99 }
100 }
101}
102
103impl<A> FromAllocator<A> for Global {
106 #[inline]
107 fn from_allocator(_: A) -> Self {
108 Self
109 }
110
111 #[inline]
112 fn __from_vec<T>(vec: Vec<T, A>) -> Result<Vec<T, Self>, Vec<T, A>>
113 where
114 A: Allocator,
115 {
116 Ok(Vec::from(vec.into_std()?))
119 }
120}
121
122unsafe impl Allocator for Global {
123 #[inline]
124 fn __do_not_implement() {}
125
126 const IS_GLOBAL: bool = true;
127
128 type Alloc<T> = GlobalAlloc<T>;
129
130 #[inline]
131 fn alloc<T>(self, value: T) -> Result<Self::Alloc<T>, AllocError> {
132 let mut raw = GlobalAlloc::<T>::alloc()?;
133
134 if size_of::<T>() != 0 {
135 unsafe {
137 raw.as_mut_ptr().write(value);
138 }
139 }
140
141 Ok(raw)
142 }
143
144 #[inline]
145 fn alloc_empty<T>(self) -> Self::Alloc<T> {
146 GlobalAlloc::DANGLING
147 }
148}
149
150pub struct GlobalAlloc<T> {
152 data: NonNull<T>,
154 size: usize,
156}
157
158impl<T> GlobalAlloc<T> {
159 #[must_use = "allocating is fallible and must be checked"]
165 fn alloc() -> Result<Self, AllocError> {
166 if size_of::<T>() == 0 {
167 return Ok(Self {
168 data: NonNull::dangling(),
169 size: 1,
170 });
171 }
172
173 unsafe {
174 let data = alloc::alloc(Layout::new::<T>());
175
176 if data.is_null() {
177 return Err(AllocError);
178 }
179
180 Ok(Self {
181 data: NonNull::new_unchecked(data).cast(),
182 size: 1,
183 })
184 }
185 }
186}
187
188unsafe impl<T> Send for GlobalAlloc<T> where T: Send {}
189unsafe impl<T> Sync for GlobalAlloc<T> where T: Sync {}
190
191impl<T> Alloc<T> for GlobalAlloc<T> {
192 #[inline]
193 fn as_ptr(&self) -> *const T {
194 self.data.as_ptr().cast_const().cast()
195 }
196
197 #[inline]
198 fn as_mut_ptr(&mut self) -> *mut T {
199 self.data.as_ptr().cast()
200 }
201
202 #[inline]
203 fn capacity(&self) -> usize {
204 if size_of::<T>() == 0 {
205 usize::MAX
206 } else {
207 self.size
208 }
209 }
210
211 #[inline]
212 fn resize(&mut self, len: usize, additional: usize) -> Result<(), AllocError> {
213 if size_of::<T>() == 0 {
214 return Ok(());
215 }
216
217 if !self.reserve(len, additional) {
218 return Err(AllocError);
219 }
220
221 Ok(())
222 }
223
224 #[inline]
225 fn try_merge<B>(&mut self, _: usize, other: B, _: usize) -> Result<(), B>
226 where
227 B: Alloc<T>,
228 {
229 if size_of::<T>() == 0 {
230 return Ok(());
231 }
232
233 Err(other)
234 }
235}
236
237impl<T> GlobalAlloc<T> {
238 const MIN_NON_ZERO_CAP: usize = if size_of::<T>() == 1 {
239 8
240 } else if size_of::<T>() <= 1024 {
241 4
242 } else {
243 1
244 };
245
246 const DANGLING: Self = Self {
247 data: NonNull::dangling(),
248 size: 0,
249 };
250
251 #[must_use = "allocating is fallible and must be checked"]
257 fn realloc(&mut self, new_layout: Layout) -> bool {
258 unsafe {
259 let data = {
260 if self.size > 0 {
261 let old_layout = Layout::from_size_align_unchecked(
262 self.size.wrapping_mul(size_of::<T>()),
263 align_of::<T>(),
264 );
265
266 alloc::realloc(self.data.as_ptr().cast(), old_layout, new_layout.size())
267 } else {
268 alloc::alloc(new_layout)
269 }
270 };
271
272 if data.is_null() {
273 return false;
274 }
275
276 self.data = NonNull::new_unchecked(data).cast();
277 }
278
279 true
280 }
281
282 #[must_use = "allocating is fallible and must be checked"]
283 fn reserve(&mut self, len: usize, additional: usize) -> bool {
284 debug_assert_ne!(size_of::<T>(), 0, "ZSTs should not get here");
285
286 let Some(required_cap) = len.checked_add(additional) else {
287 return false;
288 };
289
290 if self.size >= required_cap {
291 return true;
292 }
293
294 let cap = cmp::max(self.size * 2, required_cap);
295 let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
296
297 let Ok(new_layout) = Layout::array::<T>(cap) else {
298 return false;
299 };
300
301 if !self.realloc(new_layout) {
302 return false;
303 }
304
305 self.size = cap;
306 true
307 }
308
309 fn free(&mut self) {
310 if size_of::<T>() == 0 || self.size == 0 {
311 return;
312 }
313
314 unsafe {
317 let layout =
318 Layout::from_size_align_unchecked(self.size * size_of::<T>(), align_of::<T>());
319 alloc::dealloc(self.data.as_ptr().cast(), layout);
320 self.data = NonNull::dangling();
321 self.size = 0;
322 }
323 }
324}
325
326impl<T> Drop for GlobalAlloc<T> {
327 #[inline]
328 fn drop(&mut self) {
329 self.free();
330 }
331}