1#![allow(unknown_lints)]
21#![warn(
22 clippy::all,
23 clippy::pedantic,
24 clippy::nursery,
25 )]
30#![allow(clippy::borrow_as_ptr)]
31#![warn(unknown_lints)]
32#![allow(
33 rustdoc::broken_intra_doc_links,
34 clippy::use_self
36)]
37#![deny(missing_docs, unused_unsafe)]
38#![cfg_attr(not(feature = "std"), no_std)]
39#![cfg_attr(feature = "nightly", feature(allocator_api))]
40#![cfg_attr(feature = "metadata", feature(ptr_metadata))]
41#![cfg_attr(feature = "clone_to_uninit", feature(clone_to_uninit))]
42#![cfg_attr(feature = "sized_hierarchy", feature(sized_hierarchy))]
43
44macro_rules! const_if {
48 (
49 $feature:literal,
50 $docs:literal,
51 $(#[$attr:meta])*
52 pub const fn $name:ident $(<$generic_ty:ident $(: $req:ident)?>)? ( $($args:tt)* )
54 $(-> $ret:ty)?
55 $(where $where_ty:ident : $where_req:ident)?
57 $body:block
58 ) => {
59 #[cfg(feature = $feature)]
61 #[doc = $docs]
62 #[allow(clippy::incompatible_msrv)]
64 $(#[$attr])*
65 pub const fn $name $(<$generic_ty $(: $req)?>)? ($($args)*)
66 $(-> $ret)? $(where $where_ty: $where_req)? $body
67
68 #[cfg(not(feature = $feature))]
70 #[doc = $docs]
71 $(#[$attr])*
72 #[allow(unknown_lints, clippy::missing_const_for_fn)]
73 pub fn $name $(<$generic_ty $(: $req)?>)? ($($args)*)
74 $(-> $ret)? $(where $where_ty: $where_req)? $body
75 };
76
77 (
78 $feature:literal,
79 $docs:literal,
80 $(#[$attr:meta])*
81 const unsafe fn $name:ident $(<$generic_ty:ident $(: ?$req:ident)?>)? ( $($args:tt)* )
83 $(-> $ret:ty)?
84 $(where $where_ty:ident : $where_req:ident)?
86 $body:block
87 ) => {
88 #[cfg(feature = $feature)]
90 #[doc = $docs]
91 #[allow(clippy::incompatible_msrv)]
93 $(#[$attr])*
94 const unsafe fn $name $(<$generic_ty $(: ?$req)?>)? ($($args)*)
95 $(-> $ret)? $(where $where_ty: $where_req)? $body
96
97 #[cfg(not(feature = $feature))]
99 #[doc = $docs]
100 $(#[$attr])*
101 #[allow(unknown_lints, clippy::missing_const_for_fn)]
102 unsafe fn $name $(<$generic_ty $(: ?$req)?>)? ($($args)*)
103 $(-> $ret)? $(where $where_ty: $where_req)? $body
104 };
105
106 (
108 $feature:literal,
109 $docs:literal,
110 $(#[$attr:meta])*
111 pub const fn $name:ident $(<$lt:lifetime>)? ( $($args:tt)* )
113 $(-> $ret:ty)?
114 $body:block
115 ) => {
116 #[cfg(feature = $feature)]
117 #[doc = $docs]
118 #[allow(clippy::incompatible_msrv)]
119 $(#[$attr])*
120 pub const fn $name $(<$lt>)? ($($args)*)
121 $(-> $ret)? $body
122
123 #[cfg(not(feature = $feature))]
124 #[doc = $docs]
125 $(#[$attr])*
126 pub fn $name $(<$lt>)? ($($args)*) $(-> $ret)? $body
127 };
128 (
130 $feature:literal,
131 $docs:literal,
132 $(#[$attr:meta])*
133 pub const unsafe fn $name:ident $(<$generic_ty:ident $(: $req:ident)?>)? ( $($args:tt)* )
136 $(-> $ret:ty)?
137 $body:block
138 ) => {
139 #[cfg(feature = $feature)]
140 #[doc = $docs]
141 #[allow(clippy::incompatible_msrv)]
142 $(#[$attr])*
143 pub const unsafe fn $name$(<$generic_ty $(: $req)?>)?($($args)*) $(-> $ret)? $body
144
145 #[cfg(not(feature = $feature))]
146 #[doc = $docs]
147 $(#[$attr])*
148 pub unsafe fn $name$(<$generic_ty $(: $req)?>)?($($args)*) $(-> $ret)? $body
149 };
150 (
152 $feature:literal,
153 $docs:literal,
154 $(#[$attr:meta])*
155 pub const fn $name:ident <$generic_ty:ident: ?Sized + $req:ident> ($($args:tt)*)
156 $(-> $ret:ty)?
157 $body:block
158 ) => {
159 #[cfg(feature = $feature)]
160 #[doc = $docs]
161 #[allow(clippy::incompatible_msrv)]
162 $(#[$attr])*
163 pub const fn $name <$generic_ty: ?Sized + $req> ($($args)*)
164 $(-> $ret)? $body
165
166 #[cfg(not(feature = $feature))]
167 #[doc = $docs]
168 $(#[$attr])*
169 pub fn $name <$generic_ty: ?Sized + $req> ($($args)*)
170 $(-> $ret)? $body
171 }
172}
173
174macro_rules! tri {
176 (do $($fallible:expr)+) => {
177 match $($fallible)+ {
178 Ok(s) => s,
179 Err(e) => return Err(e),
180 }
181 };
182 }
189
190extern crate alloc;
239extern crate core;
240
241pub mod data;
245
246pub mod unstable_util;
248
249pub mod error;
251
252use {
253 core::{
254 alloc::Layout,
255 cmp::Ordering,
256 ptr::{self, NonNull}
257 },
258 error::AllocError,
259 helpers::alloc_then
260};
261
262#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
264pub struct DefaultAlloc;
265
266#[allow(unused_macros)]
267macro_rules! default_alloc_impl {
268 ($ty:ty) => {
269 impl crate::Alloc for $ty {
270 #[cfg_attr(miri, track_caller)]
271 #[inline(always)]
272 fn alloc(
273 &self,
274 layout: Layout
275 ) -> Result<core::ptr::NonNull<u8>, crate::error::AllocError> {
276 crate::helpers::null_q_zsl_check(
277 layout,
278 |layout| unsafe { alloc::alloc::alloc(layout) },
280 crate::helpers::null_q_dyn
281 )
282 }
283
284 #[cfg_attr(miri, track_caller)]
285 #[inline(always)]
286 fn zalloc(
287 &self,
288 layout: Layout
289 ) -> Result<core::ptr::NonNull<u8>, crate::error::AllocError> {
290 crate::helpers::null_q_zsl_check(
291 layout,
292 |layout| unsafe { alloc::alloc::alloc_zeroed(layout) },
294 crate::helpers::null_q_dyn
295 )
296 }
297
298 #[cfg_attr(miri, track_caller)]
299 #[inline(always)]
300 unsafe fn dealloc(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
301 if layout.size() != 0 {
302 alloc::alloc::dealloc(ptr.as_ptr(), layout);
303 }
304 }
305 }
306 };
307}
308
309unsafe impl alloc::alloc::GlobalAlloc for DefaultAlloc {
311 #[cfg_attr(miri, track_caller)]
312 #[inline]
313 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
314 alloc::alloc::alloc(layout)
315 }
316
317 #[cfg_attr(miri, track_caller)]
318 #[inline]
319 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
320 alloc::alloc::dealloc(ptr, layout);
321 }
322
323 #[cfg_attr(miri, track_caller)]
324 #[inline]
325 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
326 alloc::alloc::alloc_zeroed(layout)
327 }
328
329 #[cfg_attr(miri, track_caller)]
330 #[inline]
331 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
332 alloc::alloc::realloc(ptr, layout, new_size)
333 }
334}
335
336default_alloc_impl!(DefaultAlloc);
337
338pub trait Alloc {
350 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError>;
357
358 #[cfg_attr(miri, track_caller)]
365 #[inline]
366 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
367 unsafe {
369 alloc_then(self, layout, (), |p, ()| {
370 ptr::write_bytes(p.as_ptr(), 0, layout.size());
371 p
372 })
373 }
374 }
375
376 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout);
389
390 #[cfg_attr(miri, track_caller)]
406 #[inline]
407 unsafe fn grow(
408 &self,
409 ptr: NonNull<u8>,
410 old_layout: Layout,
411 new_layout: Layout
412 ) -> Result<NonNull<u8>, AllocError> {
413 grow(self, ptr, old_layout, new_layout, AllocPattern::Uninitialized)
414 }
415
416 #[cfg_attr(miri, track_caller)]
432 unsafe fn zgrow(
433 &self,
434 ptr: NonNull<u8>,
435 old_layout: Layout,
436 new_layout: Layout
437 ) -> Result<NonNull<u8>, AllocError> {
438 grow(self, ptr, old_layout, new_layout, AllocPattern::Zeroed)
439 }
440
441 #[cfg_attr(miri, track_caller)]
456 unsafe fn shrink(
457 &self,
458 ptr: NonNull<u8>,
459 old_layout: Layout,
460 new_layout: Layout
461 ) -> Result<NonNull<u8>, AllocError> {
462 shrink(self, ptr, old_layout, new_layout)
463 }
464
465 #[cfg_attr(miri, track_caller)]
483 unsafe fn realloc(
484 &self,
485 ptr: NonNull<u8>,
486 old_layout: Layout,
487 new_layout: Layout
488 ) -> Result<NonNull<u8>, AllocError> {
489 ralloc(self, ptr, old_layout, new_layout, AllocPattern::Uninitialized)
490 }
491
492 #[cfg_attr(miri, track_caller)]
507 unsafe fn rezalloc(
508 &self,
509 ptr: NonNull<u8>,
510 old_layout: Layout,
511 new_layout: Layout
512 ) -> Result<NonNull<u8>, AllocError> {
513 ralloc(self, ptr, old_layout, new_layout, AllocPattern::Zeroed)
514 }
515}
516
517#[cfg(feature = "nightly")]
518pub(crate) mod nightly {
520 use core::alloc::Layout;
521 unsafe impl alloc::alloc::Allocator for crate::DefaultAlloc {
525 #[cfg_attr(miri, track_caller)]
526 #[inline]
527 fn allocate(
528 &self,
529 layout: Layout
530 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
531 alloc::alloc::Allocator::allocate(&alloc::alloc::Global, layout)
532 }
533
534 #[cfg_attr(miri, track_caller)]
535 #[inline]
536 fn allocate_zeroed(
537 &self,
538 layout: Layout
539 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
540 alloc::alloc::Allocator::allocate_zeroed(&alloc::alloc::Global, layout)
541 }
542
543 #[cfg_attr(miri, track_caller)]
544 #[inline]
545 unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
546 alloc::alloc::Allocator::deallocate(&alloc::alloc::Global, ptr.cast(), layout);
547 }
548
549 #[cfg_attr(miri, track_caller)]
550 #[inline]
551 unsafe fn grow(
552 &self,
553 ptr: core::ptr::NonNull<u8>,
554 old_layout: Layout,
555 new_layout: Layout
556 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
557 alloc::alloc::Allocator::grow(&alloc::alloc::Global, ptr.cast(), old_layout, new_layout)
558 }
559
560 #[cfg_attr(miri, track_caller)]
561 #[inline]
562 unsafe fn grow_zeroed(
563 &self,
564 ptr: core::ptr::NonNull<u8>,
565 old_layout: Layout,
566 new_layout: Layout
567 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
568 alloc::alloc::Allocator::grow_zeroed(
569 &alloc::alloc::Global,
570 ptr.cast(),
571 old_layout,
572 new_layout
573 )
574 }
575
576 #[cfg_attr(miri, track_caller)]
577 #[inline]
578 unsafe fn shrink(
579 &self,
580 ptr: core::ptr::NonNull<u8>,
581 old_layout: Layout,
582 new_layout: Layout
583 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
584 alloc::alloc::Allocator::shrink(
585 &alloc::alloc::Global,
586 ptr.cast(),
587 old_layout,
588 new_layout
589 )
590 }
591 }
592
593 default_alloc_impl!(alloc::alloc::Global);
594}
595
596#[allow(clippy::inline_always)]
597impl<A: Alloc + ?Sized> Alloc for &A {
598 #[cfg_attr(miri, track_caller)]
599 #[inline(always)]
600 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
601 (**self).alloc(layout)
602 }
603
604 #[cfg_attr(miri, track_caller)]
605 #[inline(always)]
606 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
607 (**self).zalloc(layout)
608 }
609
610 #[cfg_attr(miri, track_caller)]
611 #[inline(always)]
612 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
613 (**self).dealloc(ptr, layout);
614 }
615}
616
617#[cfg(feature = "std")]
618impl Alloc for std::alloc::System {
619 #[cfg_attr(miri, track_caller)]
620 #[inline]
621 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
622 helpers::null_q_zsl_check(
623 layout,
624 |layout| unsafe { alloc::alloc::GlobalAlloc::alloc(self, layout) },
626 helpers::null_q_dyn
627 )
628 }
629
630 #[cfg_attr(miri, track_caller)]
631 #[inline]
632 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
633 helpers::null_q_zsl_check(
634 layout,
635 |layout| unsafe { alloc::alloc::GlobalAlloc::alloc_zeroed(self, layout) },
638 helpers::null_q_dyn
639 )
640 }
641
642 #[cfg_attr(miri, track_caller)]
643 #[inline]
644 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
645 if layout.size() != 0 {
646 alloc::alloc::GlobalAlloc::dealloc(self, ptr.as_ptr(), layout);
647 }
648 }
649}
650
651#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
654#[cfg_attr(not(feature = "dev"), doc(hidden))]
655#[cfg_attr(miri, track_caller)]
656pub unsafe fn grow<A: Alloc + ?Sized>(
657 a: &A,
658 ptr: NonNull<u8>,
659 old_layout: Layout,
660 new_layout: Layout,
661 pattern: AllocPattern
662) -> Result<NonNull<u8>, AllocError> {
663 match old_layout.size().cmp(&new_layout.size()) {
664 Ordering::Less => grow_unchecked(a, ptr, old_layout, new_layout, pattern),
665 Ordering::Equal => {
666 if new_layout.align() == old_layout.align() {
667 Ok(ptr)
668 } else {
669 grow_unchecked(&a, ptr, old_layout, new_layout, pattern)
670 }
671 }
672 Ordering::Greater => Err(AllocError::grow_smaller(old_layout.size(), new_layout.size()))
673 }
674}
675
676#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
679#[cfg_attr(not(feature = "dev"), doc(hidden))]
680#[cfg_attr(miri, track_caller)]
681pub unsafe fn shrink<A: Alloc + ?Sized>(
682 a: &A,
683 ptr: NonNull<u8>,
684 old_layout: Layout,
685 new_layout: Layout
686) -> Result<NonNull<u8>, AllocError> {
687 match old_layout.size().cmp(&new_layout.size()) {
688 Ordering::Less => Err(AllocError::shrink_larger(old_layout.size(), new_layout.size())),
689 Ordering::Equal => {
690 if new_layout.align() == old_layout.align() {
691 Ok(ptr)
692 } else {
693 shrink_unchecked(&a, ptr, old_layout, new_layout)
694 }
695 }
696 Ordering::Greater => shrink_unchecked(a, ptr, old_layout, new_layout)
697 }
698}
699
700#[allow(clippy::needless_pass_by_value)]
708#[cfg_attr(miri, track_caller)]
709unsafe fn grow_unchecked<A: Alloc + ?Sized>(
710 a: &A,
711 ptr: NonNull<u8>,
712 old_layout: Layout,
713 new_layout: Layout,
714 pattern: AllocPattern
715) -> Result<NonNull<u8>, AllocError> {
716 let old_size = old_layout.size();
717 let new_ptr = match pattern {
718 AllocPattern::Uninitialized => tri!(do a.alloc(new_layout)),
719 AllocPattern::Zeroed => tri!(do a.zalloc(new_layout)),
720 AllocPattern::Shrink => core::hint::unreachable_unchecked()
721 };
722
723 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size);
724 if old_size != 0 {
725 a.dealloc(ptr, old_layout);
726 }
727
728 Ok(new_ptr)
729}
730
731#[cfg_attr(miri, track_caller)]
739unsafe fn shrink_unchecked<A: Alloc + ?Sized>(
740 a: &A,
741 ptr: NonNull<u8>,
742 old_layout: Layout,
743 new_layout: Layout
744) -> Result<NonNull<u8>, AllocError> {
745 let new_ptr = tri!(do a.alloc(new_layout));
746
747 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), new_layout.size());
748 if old_layout.size() != 0 {
749 a.dealloc(ptr, old_layout);
750 }
751
752 Ok(new_ptr)
753}
754
755#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
757#[cfg_attr(not(feature = "dev"), doc(hidden))]
758#[cfg_attr(miri, track_caller)]
759pub unsafe fn ralloc<A: Alloc + ?Sized>(
760 a: &A,
761 ptr: NonNull<u8>,
762 old_layout: Layout,
763 new_layout: Layout,
764 pat: AllocPattern
765) -> Result<NonNull<u8>, AllocError> {
766 match old_layout.size().cmp(&new_layout.size()) {
767 Ordering::Less => grow_unchecked(&a, ptr, old_layout, new_layout, pat),
768 Ordering::Greater => shrink_unchecked(&a, ptr, old_layout, new_layout),
769 Ordering::Equal => {
770 if new_layout.align() == old_layout.align() {
771 Ok(ptr)
772 } else {
773 grow_unchecked(&a, ptr, old_layout, new_layout, pat)
774 }
775 }
776 }
777}
778
779#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
783#[cfg_attr(not(feature = "dev"), doc(hidden))]
784#[repr(u8)]
785pub enum AllocPattern {
786 Uninitialized,
788 Zeroed,
790 Shrink
792}
793
794pub mod helpers;