1extern crate alloc;
3#[cfg(windows)]
4use crate::os::windows::alloc::{
5 nstd_os_windows_alloc_allocate, nstd_os_windows_alloc_allocate_zeroed,
6 nstd_os_windows_alloc_deallocate,
7};
8use crate::{
9 core::{
10 alloc::{
11 nstd_core_alloc_layout_align, nstd_core_alloc_layout_new,
12 nstd_core_alloc_layout_new_unchecked, nstd_core_alloc_layout_size, NSTDAllocError,
13 NSTDAllocLayout, NSTDAllocator,
14 },
15 mem::{nstd_core_mem_copy, nstd_core_mem_dangling_mut},
16 optional::NSTDOptional,
17 },
18 NSTDAny, NSTDAnyMut, NSTD_NULL,
19};
20use cfg_if::cfg_if;
21use core::{
22 alloc::Layout,
23 marker::PhantomData,
24 ops::{Deref, DerefMut},
25 ptr::addr_of,
26};
27use nstdapi::nstdapi;
28
29#[repr(transparent)]
31#[allow(dead_code)]
32pub(crate) struct CBox<T>(NSTDAnyMut, PhantomData<T>);
33#[allow(dead_code)]
34impl<T> CBox<T> {
35 pub(crate) fn new(value: T) -> Option<Self> {
37 match core::mem::size_of::<T>() {
38 #[allow(unused_unsafe)]
39 0 => unsafe { Some(Self(nstd_core_mem_dangling_mut(), PhantomData)) },
41 size => {
42 #[allow(unused_unsafe)]
43 match unsafe { nstd_core_alloc_layout_new(size, core::mem::align_of::<T>()) } {
45 NSTDOptional::Some(layout) => match unsafe { nstd_alloc_allocate(layout) } {
47 NSTD_NULL => None,
48 mem => {
49 unsafe { nstd_core_mem_copy(mem.cast(), addr_of!(value).cast(), size) };
51 core::mem::forget(value);
52 Some(Self(mem, PhantomData))
53 }
54 },
55 NSTDOptional::None => None,
56 }
57 }
58 }
59 }
60
61 pub(crate) fn into_inner(self) -> T {
63 let value = unsafe { (self.0 as *const T).read() };
65 let size = core::mem::size_of::<T>();
66 if size > 0 {
67 let align = core::mem::align_of::<T>();
68 let layout = unsafe { nstd_core_alloc_layout_new_unchecked(size, align) };
72 unsafe { nstd_alloc_deallocate(self.0, layout) };
76 }
77 core::mem::forget(self);
78 value
79 }
80}
81impl<T> Deref for CBox<T> {
82 type Target = T;
84
85 #[inline]
87 fn deref(&self) -> &Self::Target {
88 unsafe { &*(self.0 as *const _) }
90 }
91}
92impl<T> DerefMut for CBox<T> {
93 #[inline]
95 fn deref_mut(&mut self) -> &mut Self::Target {
96 unsafe { &mut *self.0.cast() }
98 }
99}
100impl<T> Drop for CBox<T> {
101 fn drop(&mut self) {
103 unsafe {
107 drop(self.0.cast::<T>().read());
108 let size = core::mem::size_of::<T>();
109 if size > 0 {
110 let align = core::mem::align_of::<T>();
111 let layout = nstd_core_alloc_layout_new_unchecked(size, align);
112 nstd_alloc_deallocate(self.0, layout);
113 }
114 }
115 }
116}
117
118#[inline]
120unsafe extern "C" fn allocate(_: NSTDAny, layout: NSTDAllocLayout) -> NSTDAnyMut {
121 nstd_alloc_allocate(layout)
122}
123
124#[inline]
126unsafe extern "C" fn allocate_zeroed(_: NSTDAny, layout: NSTDAllocLayout) -> NSTDAnyMut {
127 nstd_alloc_allocate_zeroed(layout)
128}
129
130#[inline]
132unsafe extern "C" fn reallocate(
133 _: NSTDAny,
134 ptr: &mut NSTDAnyMut,
135 old_layout: NSTDAllocLayout,
136 new_layout: NSTDAllocLayout,
137) -> NSTDAllocError {
138 nstd_alloc_reallocate(ptr, old_layout, new_layout)
139}
140
141#[inline]
143unsafe extern "C" fn deallocate(
144 _: NSTDAny,
145 ptr: NSTDAnyMut,
146 layout: NSTDAllocLayout,
147) -> NSTDAllocError {
148 nstd_alloc_deallocate(ptr, layout)
149}
150
151#[nstdapi]
153pub static NSTD_ALLOCATOR: NSTDAllocator = NSTDAllocator {
154 state: NSTD_NULL,
155 allocate,
156 allocate_zeroed,
157 reallocate,
158 deallocate,
159};
160
161#[inline]
163unsafe extern "C" fn rust_allocate(_: NSTDAny, layout: NSTDAllocLayout) -> NSTDAnyMut {
164 let size = nstd_core_alloc_layout_size(layout);
165 let align = nstd_core_alloc_layout_align(layout);
166 if let Ok(layout) = Layout::from_size_align(size, align) {
167 return alloc::alloc::alloc(layout).cast();
168 }
169 NSTD_NULL
170}
171
172#[inline]
174unsafe extern "C" fn rust_allocate_zeroed(_: NSTDAny, layout: NSTDAllocLayout) -> NSTDAnyMut {
175 let size = nstd_core_alloc_layout_size(layout);
176 let align = nstd_core_alloc_layout_align(layout);
177 if let Ok(layout) = Layout::from_size_align(size, align) {
178 return alloc::alloc::alloc_zeroed(layout).cast();
179 }
180 NSTD_NULL
181}
182
183unsafe extern "C" fn rust_reallocate(
185 this: NSTDAny,
186 ptr: &mut NSTDAnyMut,
187 old_layout: NSTDAllocLayout,
188 new_layout: NSTDAllocLayout,
189) -> NSTDAllocError {
190 if old_layout != new_layout {
191 let new_mem = rust_allocate(this, new_layout);
192 if new_mem.is_null() {
193 return NSTDAllocError::NSTD_ALLOC_ERROR_OUT_OF_MEMORY;
194 }
195 let old_size = nstd_core_alloc_layout_size(old_layout);
196 let new_size = nstd_core_alloc_layout_size(new_layout);
197 nstd_core_mem_copy(new_mem.cast(), (*ptr).cast(), old_size.min(new_size));
198 rust_deallocate(this, *ptr, old_layout);
199 *ptr = new_mem;
200 }
201 NSTDAllocError::NSTD_ALLOC_ERROR_NONE
202}
203
204unsafe extern "C" fn rust_deallocate(
206 _: NSTDAny,
207 ptr: NSTDAnyMut,
208 layout: NSTDAllocLayout,
209) -> NSTDAllocError {
210 let size = nstd_core_alloc_layout_size(layout);
211 let align = nstd_core_alloc_layout_align(layout);
212 if let Ok(layout) = Layout::from_size_align(size, align) {
213 alloc::alloc::dealloc(ptr.cast(), layout);
214 return NSTDAllocError::NSTD_ALLOC_ERROR_NONE;
215 }
216 NSTDAllocError::NSTD_ALLOC_ERROR_INVALID_LAYOUT
217}
218
219#[allow(dead_code)]
221pub(crate) static GLOBAL_ALLOCATOR: NSTDAllocator = NSTDAllocator {
222 state: NSTD_NULL,
223 allocate: rust_allocate,
224 allocate_zeroed: rust_allocate_zeroed,
225 reallocate: rust_reallocate,
226 deallocate: rust_deallocate,
227};
228
229#[inline]
266#[nstdapi]
267pub unsafe fn nstd_alloc_allocate(layout: NSTDAllocLayout) -> NSTDAnyMut {
268 cfg_if! {
269 if #[cfg(any(
270 all(
271 target_os = "linux",
272 target_env = "gnu",
273 any(
274 target_arch = "arm",
275 target_arch = "aarch64",
276 target_arch = "csky",
277 target_arch = "loongarch64",
278 target_arch = "m68k",
279 target_arch = "mips",
280 target_arch = "mips32r6",
281 target_arch = "mips64",
282 target_arch = "mips64r6",
283 target_arch = "powerpc64",
284 target_arch = "sparc",
285 target_arch = "sparc64",
286 target_arch = "x86",
287 target_arch = "x86_64"
288 )
289 ),
290 all(
291 target_os = "linux",
292 any(target_env = "musl", target_env = "ohos"),
293 any(
294 target_arch = "arm",
295 target_arch = "aarch64",
296 target_arch = "mips",
297 target_arch = "riscv32",
298 target_arch = "x86",
299 target_arch = "x86_64"
300 )
301 ),
302 all(
303 target_os = "android",
304 any(
305 target_arch = "aarch64",
306 target_arch = "riscv64",
307 target_arch = "x86",
308 target_arch = "x86_64"
309 )
310 ),
311 all(
312 any(
313 target_os = "macos",
314 target_os = "ios",
315 target_os = "tvos",
316 target_os = "watchos"
317 ),
318 any(target_pointer_width = "32", target_arch = "aarch64", target_arch = "x86_64")
319 ),
320 all(target_os = "freebsd", target_arch = "x86_64"),
321 target_env = "wasi",
322 target_os = "wasi",
323 target_os = "emscripten"
324 ))] {
325 let align = nstd_core_alloc_layout_align(layout);
326 if align <= core::mem::align_of::<libc::max_align_t>() {
327 libc::malloc(nstd_core_alloc_layout_size(layout))
328 } else {
329 let size = nstd_core_alloc_layout_size(layout);
330 let min_align = core::mem::size_of::<NSTDAnyMut>();
331 let mut ptr = NSTD_NULL;
332 libc::posix_memalign(&mut ptr, align.max(min_align), size);
333 ptr
334 }
335 } else if #[cfg(any(unix, target_os = "teeos"))] {
336 let size = nstd_core_alloc_layout_size(layout);
337 let min_align = core::mem::size_of::<NSTDAnyMut>();
338 let align = nstd_core_alloc_layout_align(layout).max(min_align);
339 let mut ptr = NSTD_NULL;
340 libc::posix_memalign(&mut ptr, align, size);
341 ptr
342 } else if #[cfg(target_os = "solid_asp3")] {
343 use crate::NSTD_INT_MAX;
344 let mut size = nstd_core_alloc_layout_size(layout);
345 let align = nstd_core_alloc_layout_align(layout);
346 #[allow(clippy::arithmetic_side_effects)]
347 let off = size % align;
348 #[allow(clippy::arithmetic_side_effects)]
349 if off != 0 {
350 size = match size.checked_add(align - off) {
351 Some(size) if size <= NSTD_INT_MAX => size,
352 _ => return NSTD_NULL,
353 };
354 }
355 libc::aligned_alloc(align, size)
356 } else if #[cfg(windows)] {
357 nstd_os_windows_alloc_allocate(layout)
358 } else {
359 let size = nstd_core_alloc_layout_size(layout);
360 let align = nstd_core_alloc_layout_align(layout);
361 if let Ok(layout) = Layout::from_size_align(size, align) {
362 return alloc::alloc::alloc(layout).cast();
363 }
364 NSTD_NULL
365 }
366 }
367}
368
369#[inline]
408#[nstdapi]
409pub unsafe fn nstd_alloc_allocate_zeroed(layout: NSTDAllocLayout) -> NSTDAnyMut {
410 cfg_if! {
411 if #[cfg(any(
412 unix,
413 any(target_env = "wasi", target_os = "wasi"),
414 target_os = "solid_asp3",
415 target_os = "teeos"
416 ))] {
417 use crate::core::mem::nstd_core_mem_zero;
418 let ptr = nstd_alloc_allocate(layout);
419 if !ptr.is_null() {
420 nstd_core_mem_zero(ptr.cast(), nstd_core_alloc_layout_size(layout));
421 }
422 ptr
423 } else if #[cfg(windows)] {
424 nstd_os_windows_alloc_allocate_zeroed(layout)
425 } else {
426 let size = nstd_core_alloc_layout_size(layout);
427 let align = nstd_core_alloc_layout_align(layout);
428 if let Ok(layout) = Layout::from_size_align(size, align) {
429 return alloc::alloc::alloc_zeroed(layout).cast();
430 }
431 NSTD_NULL
432 }
433 }
434}
435
436#[inline]
489#[nstdapi]
490pub unsafe fn nstd_alloc_reallocate(
491 ptr: &mut NSTDAnyMut,
492 old_layout: NSTDAllocLayout,
493 new_layout: NSTDAllocLayout,
494) -> NSTDAllocError {
495 if old_layout != new_layout {
496 let new_mem = nstd_alloc_allocate(new_layout);
497 if new_mem.is_null() {
498 return NSTDAllocError::NSTD_ALLOC_ERROR_OUT_OF_MEMORY;
499 }
500 let old_size = nstd_core_alloc_layout_size(old_layout);
501 let new_size = nstd_core_alloc_layout_size(new_layout);
502 nstd_core_mem_copy(new_mem.cast(), (*ptr).cast(), old_size.min(new_size));
503 nstd_alloc_deallocate(*ptr, old_layout);
504 *ptr = new_mem;
505 }
506 NSTDAllocError::NSTD_ALLOC_ERROR_NONE
507}
508
509#[inline]
543#[nstdapi]
544#[allow(unused_variables)]
545pub unsafe fn nstd_alloc_deallocate(ptr: NSTDAnyMut, layout: NSTDAllocLayout) -> NSTDAllocError {
546 cfg_if! {
547 if #[cfg(any(
548 unix,
549 any(target_env = "wasi", target_os = "wasi"),
550 target_os = "solid_asp3",
551 target_os = "teeos"
552 ))] {
553 libc::free(ptr);
554 NSTDAllocError::NSTD_ALLOC_ERROR_NONE
555 } else if #[cfg(windows)] {
556 nstd_os_windows_alloc_deallocate(ptr);
557 NSTDAllocError::NSTD_ALLOC_ERROR_NONE
558 } else {
559 let size = nstd_core_alloc_layout_size(layout);
560 let align = nstd_core_alloc_layout_align(layout);
561 if let Ok(layout) = Layout::from_size_align(size, align) {
562 alloc::alloc::dealloc(ptr.cast(), layout);
563 return NSTDAllocError::NSTD_ALLOC_ERROR_NONE;
564 }
565 NSTDAllocError::NSTD_ALLOC_ERROR_INVALID_LAYOUT
566 }
567 }
568}