1#![allow(unknown_lints)]
21#![warn(
22 clippy::all,
23 clippy::pedantic,
24 clippy::nursery,
25 clippy::borrow_as_ptr,
26 clippy::undocumented_unsafe_blocks
27)]
28#![warn(unknown_lints)]
29#![allow(
30 unsafe_op_in_unsafe_fn,
31 rustdoc::broken_intra_doc_links,
32 clippy::use_self
34)]
35#![deny(missing_docs, unused_unsafe)]
36#![cfg_attr(not(feature = "std"), no_std)]
37#![cfg_attr(feature = "nightly", feature(allocator_api))]
38#![cfg_attr(feature = "metadata", feature(ptr_metadata))]
39#![cfg_attr(feature = "clone_to_uninit", feature(clone_to_uninit))]
40#![cfg_attr(feature = "sized_hierarchy", feature(sized_hierarchy))]
41
42macro_rules! const_if {
46 (
47 $feature:literal,
48 $docs:literal,
49 $(#[$attr:meta])*
50 pub const fn $name:ident $(<$generic_ty:ident $(: $req:ident)?>)? ( $($args:tt)* )
52 $(-> $ret:ty)?
53 $(where $where_ty:ident : $where_req:ident)?
55 $body:block
56 ) => {
57 #[cfg(feature = $feature)]
59 #[doc = $docs]
60 #[allow(clippy::incompatible_msrv)]
62 $(#[$attr])*
63 pub const fn $name $(<$generic_ty $(: $req)?>)? ($($args)*)
64 $(-> $ret)? $(where $where_ty: $where_req)? $body
65
66 #[cfg(not(feature = $feature))]
68 #[doc = $docs]
69 $(#[$attr])*
70 #[allow(unknown_lints, clippy::missing_const_for_fn)]
71 pub fn $name $(<$generic_ty $(: $req)?>)? ($($args)*)
72 $(-> $ret)? $(where $where_ty: $where_req)? $body
73 };
74 (
76 $feature:literal,
77 $docs:literal,
78 $(#[$attr:meta])*
79 pub const fn $name:ident $(<$lt:lifetime>)? ( $($args:tt)* )
81 $(-> $ret:ty)?
82 $body:block
83 ) => {
84 #[cfg(feature = $feature)]
85 #[doc = $docs]
86 #[allow(clippy::incompatible_msrv)]
87 $(#[$attr])*
88 pub const fn $name $(<$lt>)? ($($args)*)
89 $(-> $ret)? $body
90
91 #[cfg(not(feature = $feature))]
92 #[doc = $docs]
93 $(#[$attr])*
94 pub fn $name $(<$lt>)? ($($args)*) $(-> $ret)? $body
95 };
96 (
98 $feature:literal,
99 $docs:literal,
100 $(#[$attr:meta])*
101 pub const unsafe fn $name:ident $(<$generic_ty:ident $(: $req:ident)?>)? ( $($args:tt)* )
104 $(-> $ret:ty)?
105 $body:block
106 ) => {
107 #[cfg(feature = $feature)]
108 #[doc = $docs]
109 #[allow(clippy::incompatible_msrv)]
110 $(#[$attr])*
111 pub const unsafe fn $name$(<$generic_ty $(: $req)?>)?($($args)*) $(-> $ret)? $body
112
113 #[cfg(not(feature = $feature))]
114 #[doc = $docs]
115 $(#[$attr])*
116 pub unsafe fn $name$(<$generic_ty $(: $req)?>)?($($args)*) $(-> $ret)? $body
117 };
118 (
120 $feature:literal,
121 $docs:literal,
122 $(#[$attr:meta])*
123 pub const fn $name:ident <$generic_ty:ident: ?Sized + $req:ident> ($($args:tt)*)
124 $(-> $ret:ty)?
125 $body:block
126 ) => {
127 #[cfg(feature = $feature)]
128 #[doc = $docs]
129 #[allow(clippy::incompatible_msrv)]
130 $(#[$attr])*
131 pub const fn $name <$generic_ty: ?Sized + $req> ($($args)*)
132 $(-> $ret)? $body
133
134 #[cfg(not(feature = $feature))]
135 #[doc = $docs]
136 $(#[$attr])*
137 pub fn $name <$generic_ty: ?Sized + $req> ($($args)*)
138 $(-> $ret)? $body
139 }
140}
141
142macro_rules! tri {
144 (do $($fallible:expr)+) => {
145 match $($fallible)+ {
146 Ok(s) => s,
147 Err(e) => return Err(e),
148 }
149 };
150 (AllocError::$n:ident($($fallible:expr)+)) => {
151 match $($fallible)+ {
152 Ok(s) => s,
153 Err(e) => return Err(crate::error::AllocError::$n(e)),
154 }
155 };
156 (lay, $sz:expr, $aln:expr) => {
157 match crate::unstable_util::lay_from_size_align($sz, $aln) {
158 Ok(layout) => layout,
159 Err(e) => return Err(
160 crate::error::AllocError::InvalidLayout(crate::error::InvLayout($sz, $aln, e))
161 ),
162 }
163 };
164 (lay_preproc $layout:ident) => {{
165 let pre = preproc_layout($layout);
166 match pre {
167 Ok(layout) => layout,
168 Err(e) => return Err(crate::error::AllocError::InvalidLayout(e)),
169 }
170 }}
171}
172
173#[allow(unused_macros)]
174macro_rules! assume {
175 ($e:expr) => {
176 #[cfg(feature = "assumptions")]
177 {
178 let res = $e;
179
180 #[cfg(debug_assertions)]
181 {
182 assert!(res, concat!("assertion failed: ", stringify!($e)));
183 }
184 crate::assert_unreachable(res);
185 }
186 };
187 (u_pre $e:expr, $msg:literal) => {
188 #[cfg(feature = "assumptions")]
189 {
190 let res = $e;
191 #[cfg(debug_assertions)]
192 {
193 assert!(
194 res,
195 concat!("unsafe precondition `", stringify!($e), "` violated: ", $msg)
196 );
197 }
198 crate::assert_unreachable(res);
199 }
200 };
201}
202
203#[cfg_attr(not(feature = "dev"), doc(hidden))]
210pub const unsafe fn assert_unreachable(cond: bool) {
211 if !cond {
212 #[allow(clippy::incompatible_msrv)]
213 core::hint::unreachable_unchecked();
214 }
215}
216
217extern crate alloc;
221extern crate core;
222
223pub mod data;
227
228pub mod unstable_util;
230
231pub mod error;
233
234use {
235 core::{
236 alloc::Layout,
237 cmp::Ordering,
238 ptr::{self, NonNull}
239 },
240 error::AllocError,
241 helpers::alloc_then
242};
243
244#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
246pub struct DefaultAlloc;
247
248#[allow(unused_macros)]
249macro_rules! default_alloc_impl {
250 ($ty:ty) => {
251 impl crate::Alloc for $ty {
252 #[cfg_attr(miri, track_caller)]
253 #[inline(always)]
254 fn alloc(
255 &self,
256 layout: Layout
257 ) -> Result<core::ptr::NonNull<u8>, crate::error::AllocError> {
258 crate::helpers::null_q_zsl_check(
259 layout,
260 |layout| unsafe { alloc::alloc::alloc(layout) },
262 crate::helpers::null_q_dyn
263 )
264 }
265
266 #[cfg_attr(miri, track_caller)]
267 #[inline(always)]
268 fn zalloc(
269 &self,
270 layout: Layout
271 ) -> Result<core::ptr::NonNull<u8>, crate::error::AllocError> {
272 crate::helpers::null_q_zsl_check(
273 layout,
274 |layout| unsafe { alloc::alloc::alloc_zeroed(layout) },
276 crate::helpers::null_q_dyn
277 )
278 }
279
280 #[cfg_attr(miri, track_caller)]
281 #[inline(always)]
282 unsafe fn dealloc(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
283 if layout.size() != 0 {
284 alloc::alloc::dealloc(ptr.as_ptr(), layout);
285 }
286 }
287 }
288 };
289}
290
291unsafe impl alloc::alloc::GlobalAlloc for DefaultAlloc {
293 #[cfg_attr(miri, track_caller)]
294 #[inline]
295 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
296 alloc::alloc::alloc(layout)
297 }
298
299 #[cfg_attr(miri, track_caller)]
300 #[inline]
301 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
302 alloc::alloc::dealloc(ptr, layout);
303 }
304
305 #[cfg_attr(miri, track_caller)]
306 #[inline]
307 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
308 alloc::alloc::alloc_zeroed(layout)
309 }
310
311 #[cfg_attr(miri, track_caller)]
312 #[inline]
313 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
314 alloc::alloc::realloc(ptr, layout, new_size)
315 }
316}
317
318default_alloc_impl!(DefaultAlloc);
319
320pub trait Alloc {
332 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError>;
339
340 #[cfg_attr(miri, track_caller)]
347 #[inline]
348 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
349 unsafe {
351 alloc_then(self, layout, (), |p, ()| {
352 ptr::write_bytes(p.as_ptr(), 0, layout.size());
353 p
354 })
355 }
356 }
357
358 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout);
371
372 #[cfg_attr(miri, track_caller)]
388 #[inline]
389 unsafe fn grow(
390 &self,
391 ptr: NonNull<u8>,
392 old_layout: Layout,
393 new_layout: Layout
394 ) -> Result<NonNull<u8>, AllocError> {
395 grow(self, ptr, old_layout, new_layout, AllocPattern::Uninitialized)
396 }
397
398 #[cfg_attr(miri, track_caller)]
414 unsafe fn zgrow(
415 &self,
416 ptr: NonNull<u8>,
417 old_layout: Layout,
418 new_layout: Layout
419 ) -> Result<NonNull<u8>, AllocError> {
420 grow(self, ptr, old_layout, new_layout, AllocPattern::Zeroed)
421 }
422
423 #[cfg_attr(miri, track_caller)]
438 unsafe fn shrink(
439 &self,
440 ptr: NonNull<u8>,
441 old_layout: Layout,
442 new_layout: Layout
443 ) -> Result<NonNull<u8>, AllocError> {
444 shrink(self, ptr, old_layout, new_layout)
445 }
446
447 #[cfg_attr(miri, track_caller)]
465 unsafe fn realloc(
466 &self,
467 ptr: NonNull<u8>,
468 old_layout: Layout,
469 new_layout: Layout
470 ) -> Result<NonNull<u8>, AllocError> {
471 ralloc(self, ptr, old_layout, new_layout, AllocPattern::Uninitialized)
472 }
473
474 #[cfg_attr(miri, track_caller)]
489 unsafe fn rezalloc(
490 &self,
491 ptr: NonNull<u8>,
492 old_layout: Layout,
493 new_layout: Layout
494 ) -> Result<NonNull<u8>, AllocError> {
495 ralloc(self, ptr, old_layout, new_layout, AllocPattern::Zeroed)
496 }
497}
498
499#[cfg(feature = "nightly")]
500pub(crate) mod nightly {
502 use core::alloc::Layout;
503 unsafe impl alloc::alloc::Allocator for crate::DefaultAlloc {
507 #[cfg_attr(miri, track_caller)]
508 #[inline]
509 fn allocate(
510 &self,
511 layout: Layout
512 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
513 alloc::alloc::Allocator::allocate(&alloc::alloc::Global, layout)
514 }
515
516 #[cfg_attr(miri, track_caller)]
517 #[inline]
518 fn allocate_zeroed(
519 &self,
520 layout: Layout
521 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
522 alloc::alloc::Allocator::allocate_zeroed(&alloc::alloc::Global, layout)
523 }
524
525 #[cfg_attr(miri, track_caller)]
526 #[inline]
527 unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
528 alloc::alloc::Allocator::deallocate(&alloc::alloc::Global, ptr.cast(), layout);
529 }
530
531 #[cfg_attr(miri, track_caller)]
532 #[inline]
533 unsafe fn grow(
534 &self,
535 ptr: core::ptr::NonNull<u8>,
536 old_layout: Layout,
537 new_layout: Layout
538 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
539 alloc::alloc::Allocator::grow(&alloc::alloc::Global, ptr.cast(), old_layout, new_layout)
540 }
541
542 #[cfg_attr(miri, track_caller)]
543 #[inline]
544 unsafe fn grow_zeroed(
545 &self,
546 ptr: core::ptr::NonNull<u8>,
547 old_layout: Layout,
548 new_layout: Layout
549 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
550 alloc::alloc::Allocator::grow_zeroed(
551 &alloc::alloc::Global,
552 ptr.cast(),
553 old_layout,
554 new_layout
555 )
556 }
557
558 #[cfg_attr(miri, track_caller)]
559 #[inline]
560 unsafe fn shrink(
561 &self,
562 ptr: core::ptr::NonNull<u8>,
563 old_layout: Layout,
564 new_layout: Layout
565 ) -> Result<core::ptr::NonNull<[u8]>, alloc::alloc::AllocError> {
566 alloc::alloc::Allocator::shrink(
567 &alloc::alloc::Global,
568 ptr.cast(),
569 old_layout,
570 new_layout
571 )
572 }
573 }
574
575 default_alloc_impl!(alloc::alloc::Global);
576}
577
578#[allow(clippy::inline_always)]
579impl<A: Alloc + ?Sized> Alloc for &A {
580 #[cfg_attr(miri, track_caller)]
581 #[inline(always)]
582 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
583 (**self).alloc(layout)
584 }
585
586 #[cfg_attr(miri, track_caller)]
587 #[inline(always)]
588 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
589 (**self).zalloc(layout)
590 }
591
592 #[cfg_attr(miri, track_caller)]
593 #[inline(always)]
594 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
595 (**self).dealloc(ptr, layout);
596 }
597}
598
599#[cfg(feature = "std")]
600impl Alloc for std::alloc::System {
601 #[cfg_attr(miri, track_caller)]
602 #[inline]
603 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
604 helpers::null_q_zsl_check(
605 layout,
606 |layout| unsafe { alloc::alloc::GlobalAlloc::alloc(self, layout) },
608 helpers::null_q_dyn
609 )
610 }
611
612 #[cfg_attr(miri, track_caller)]
613 #[inline]
614 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
615 helpers::null_q_zsl_check(
616 layout,
617 |layout| unsafe { alloc::alloc::GlobalAlloc::alloc_zeroed(self, layout) },
620 helpers::null_q_dyn
621 )
622 }
623
624 #[cfg_attr(miri, track_caller)]
625 #[inline]
626 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
627 if layout.size() != 0 {
628 alloc::alloc::GlobalAlloc::dealloc(self, ptr.as_ptr(), layout);
629 }
630 }
631}
632
633#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
636#[cfg_attr(not(feature = "dev"), doc(hidden))]
637#[cfg_attr(miri, track_caller)]
638pub unsafe fn grow<A: Alloc + ?Sized>(
639 a: &A,
640 ptr: NonNull<u8>,
641 old_layout: Layout,
642 new_layout: Layout,
643 pattern: AllocPattern
644) -> Result<NonNull<u8>, AllocError> {
645 match old_layout.size().cmp(&new_layout.size()) {
646 Ordering::Less => grow_unchecked(a, ptr, old_layout, new_layout, pattern),
647 Ordering::Equal => {
648 if new_layout.align() == old_layout.align() {
649 Ok(ptr)
650 } else {
651 grow_unchecked(&a, ptr, old_layout, new_layout, pattern)
652 }
653 }
654 Ordering::Greater => Err(AllocError::grow_smaller(old_layout.size(), new_layout.size()))
655 }
656}
657
658#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
661#[cfg_attr(not(feature = "dev"), doc(hidden))]
662#[cfg_attr(miri, track_caller)]
663pub unsafe fn shrink<A: Alloc + ?Sized>(
664 a: &A,
665 ptr: NonNull<u8>,
666 old_layout: Layout,
667 new_layout: Layout
668) -> Result<NonNull<u8>, AllocError> {
669 match old_layout.size().cmp(&new_layout.size()) {
670 Ordering::Less => Err(AllocError::shrink_larger(old_layout.size(), new_layout.size())),
671 Ordering::Equal => {
672 if new_layout.align() == old_layout.align() {
673 Ok(ptr)
674 } else {
675 shrink_unchecked(&a, ptr, old_layout, new_layout)
676 }
677 }
678 Ordering::Greater => shrink_unchecked(a, ptr, old_layout, new_layout)
679 }
680}
681
682#[allow(clippy::needless_pass_by_value)]
690#[cfg_attr(miri, track_caller)]
691unsafe fn grow_unchecked<A: Alloc + ?Sized>(
692 a: &A,
693 ptr: NonNull<u8>,
694 old_layout: Layout,
695 new_layout: Layout,
696 pattern: AllocPattern
697) -> Result<NonNull<u8>, AllocError> {
698 let old_size = old_layout.size();
699 let new_ptr = match pattern {
700 AllocPattern::Uninitialized => tri!(do a.alloc(new_layout)),
701 AllocPattern::Zeroed => tri!(do a.zalloc(new_layout)),
702 AllocPattern::Shrink => core::hint::unreachable_unchecked()
703 };
704
705 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size);
706 if old_size != 0 {
707 a.dealloc(ptr, old_layout);
708 }
709
710 Ok(new_ptr)
711}
712
713#[cfg_attr(miri, track_caller)]
721unsafe fn shrink_unchecked<A: Alloc + ?Sized>(
722 a: &A,
723 ptr: NonNull<u8>,
724 old_layout: Layout,
725 new_layout: Layout
726) -> Result<NonNull<u8>, AllocError> {
727 let new_ptr = tri!(do a.alloc(new_layout));
728
729 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), new_layout.size());
730 if old_layout.size() != 0 {
731 a.dealloc(ptr, old_layout);
732 }
733
734 Ok(new_ptr)
735}
736
737#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
739#[cfg_attr(not(feature = "dev"), doc(hidden))]
740#[cfg_attr(miri, track_caller)]
741pub unsafe fn ralloc<A: Alloc + ?Sized>(
742 a: &A,
743 ptr: NonNull<u8>,
744 old_layout: Layout,
745 new_layout: Layout,
746 pat: AllocPattern
747) -> Result<NonNull<u8>, AllocError> {
748 match old_layout.size().cmp(&new_layout.size()) {
749 Ordering::Less => grow_unchecked(&a, ptr, old_layout, new_layout, pat),
750 Ordering::Greater => shrink_unchecked(&a, ptr, old_layout, new_layout),
751 Ordering::Equal => {
752 if new_layout.align() == old_layout.align() {
753 Ok(ptr)
754 } else {
755 grow_unchecked(&a, ptr, old_layout, new_layout, pat)
756 }
757 }
758 }
759}
760
761#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
765#[cfg_attr(not(feature = "dev"), doc(hidden))]
766#[repr(u8)]
767pub enum AllocPattern {
768 Uninitialized,
770 Zeroed,
772 Shrink
774}
775
776pub mod helpers;