diff --git a/static-alloc/src/bump.rs b/static-alloc/src/bump.rs index 43e4dd7..9a14802 100644 --- a/static-alloc/src/bump.rs +++ b/static-alloc/src/bump.rs @@ -286,7 +286,7 @@ pub struct Level(pub(crate) usize); /// /// [`Level`]: struct.Level.html #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Allocation<'a, T = u8> { +pub struct Allocation<'a, T: ?Sized = u8> { /// Pointer to the uninitialized region with specified layout. pub ptr: NonNull, @@ -570,6 +570,48 @@ impl Bump { self.as_view().get_at(level) } + /// Get an allocation for a slice of a type. + /// + /// Returns `None` if the allocation fails (see [`Self::get`]) or if the slice layout can not be + /// computed due to an overflow with this size. + /// + /// # Examples + /// + /// ``` + /// # use static_alloc::bump::Bump; + /// + /// let slab: Bump<[usize; 6]> = Bump::uninit(); + /// + /// let first = slab.get_slice::(4).unwrap(); + /// let second = slab.get_slice::(2).unwrap(); + /// assert!(slab.get_slice::(1).is_none()); + /// + /// assert_eq!(first.ptr.len(), 4); + /// assert_eq!(second.ptr.len(), 2); + /// ``` + /// + /// ``` + /// # use static_alloc::bump::Bump; + /// + /// let slab: Bump<[usize; 1]> = Bump::uninit(); + /// + /// let lots_of_empty = slab.get_slice::<()>(usize::MAX).unwrap(); + /// assert_eq!(lots_of_empty.ptr.len(), usize::MAX); + /// ``` + /// + /// ``` + /// # use static_alloc::bump::Bump; + /// + /// let slab: Bump<[usize; 1]> = Bump::uninit(); + /// + /// let _exhaust = slab.get_slice::(1).unwrap(); + /// assert!(slab.get_slice::(1).is_none()); + /// let empty_slice = slab.get_slice::(0).unwrap(); + /// ``` + pub fn get_slice(&self, len: usize) -> Option> { + self.as_view().get_slice(len) + } + /// Move a value into an owned allocation. /// /// For safely initializing a value _after_ a successful allocation, see [`LeakBox::write`]. @@ -920,6 +962,51 @@ impl BumpSlice { self.as_view().get_at(level) } + /// Get an allocation for a slice of a type. + /// + /// Returns `None` if the allocation fails (see [`Self::get`]) or if the slice layout can not be + /// computed due to an overflow with this size. + /// + /// # Examples + /// + /// ``` + /// # use static_alloc::bump::{Bump, BumpSlice}; + /// + /// let backing: Bump<[usize; 6]> = Bump::uninit(); + /// let slab = backing.as_bump_slice().unwrap(); + /// + /// let first = slab.get_slice::(4).unwrap(); + /// let second = slab.get_slice::(2).unwrap(); + /// assert!(slab.get_slice::(1).is_none()); + /// + /// assert_eq!(first.ptr.len(), 4); + /// assert_eq!(second.ptr.len(), 2); + /// ``` + /// + /// ``` + /// # use static_alloc::bump::{Bump, BumpSlice}; + /// + /// let backing: Bump<[usize; 1]> = Bump::uninit(); + /// let slab = backing.as_bump_slice().unwrap(); + /// + /// let lots_of_empty = slab.get_slice::<()>(usize::MAX).unwrap(); + /// assert_eq!(lots_of_empty.ptr.len(), usize::MAX); + /// ``` + /// + /// ``` + /// # use static_alloc::bump::{Bump, BumpSlice}; + /// + /// let backing: Bump<[usize; 1]> = Bump::uninit(); + /// let slab = backing.as_bump_slice().unwrap(); + /// + /// let _exhaust = slab.get_slice::(1).unwrap(); + /// assert!(slab.get_slice::(1).is_none()); + /// let empty_slice = slab.get_slice::(0).unwrap(); + /// ``` + pub fn get_slice(&self, len: usize) -> Option> { + self.as_view().get_slice(len) + } + /// Move a value into an owned allocation. /// /// For safely initializing a value _after_ a successful allocation, see [`LeakBox::write`]. @@ -1211,6 +1298,27 @@ impl<'lt> BumpView<'lt> { }) } + pub fn get_slice(&self, len: usize) -> Option> { + if len == 0 { + return Some(Allocation::for_empty_slice(self.level())); + } + + let (layout, _) = Layout::new::().repeat(len).ok()?; + + if layout.size() == 0 { + // Synthesize the slice for this ZST. + return Some(Allocation::for_zst_slice(len, self.level())); + }; + + let alloc = self.get_layout(layout)?; + + Some(Allocation { + ptr: NonNull::slice_from_raw_parts(alloc.ptr.cast(), len), + lifetime: alloc.lifetime, + level: alloc.level, + }) + } + pub fn leak_box(self, val: V) -> Option> { let Allocation { ptr, lifetime, .. } = self.get::()?; Some(unsafe { LeakBox::new_from_raw_non_null(ptr, val, lifetime) }) @@ -1232,7 +1340,7 @@ impl<'lt> BumpView<'lt> { /// - As a corollary, particular it must be in-bounds of the allocator's memory. /// - Another consequence, the result pointer must be aligned for the requested type. pub unsafe fn get_unchecked(self, level: Level) -> Allocation<'lt, V> { - debug_assert!(level.0 <= mem::size_of_val(&self.storage)); + debug_assert!(level.0 <= mem::size_of_val(self.storage)); debug_assert!( level <= self.level(), @@ -1257,6 +1365,7 @@ impl<'lt> BumpView<'lt> { } } + // FIXME: should take `NonZeroLayout`. fn try_alloc(self, layout: Layout) -> Option> { // Guess zero, this will fail when we try to access it and it isn't. let mut consumed = 0; @@ -1277,6 +1386,7 @@ impl<'lt> BumpView<'lt> { /// /// # Panics /// This function panics if `expect_consumed` is larger than `length`. + /// FIXME: should take `NonZeroLayout`. fn try_alloc_at( self, layout: Layout, @@ -1442,6 +1552,27 @@ impl<'alloc, T> Allocation<'alloc, T> { level, } } + + pub(crate) fn for_zst_slice(len: usize, level: Level) -> Allocation<'alloc, [T]> { + assert!(mem::size_of::() == 0); + let alloc: &[T; 0] = &[]; + + Allocation { + ptr: NonNull::slice_from_raw_parts(NonNull::from(alloc).cast(), len), + lifetime: AllocTime::default(), + level, + } + } + + pub(crate) fn for_empty_slice(level: Level) -> Allocation<'alloc, [T]> { + let alloc: &[T; 0] = &[]; + + Allocation { + ptr: NonNull::from(alloc), + lifetime: AllocTime::default(), + level, + } + } } impl LeakError { @@ -1485,6 +1616,24 @@ unsafe impl GlobalAlloc for Bump { } } +unsafe impl GlobalAlloc for &'static BumpSlice { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // Safety: just handing over arguments exactly as is. These two allocators are 'compatible' + // in the sense they hold onto the same value handles. + unsafe { GlobalAlloc::alloc(&self.as_view(), layout) } + } + + unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 { + // Safety: just handing over arguments exactly as is. These two allocators are 'compatible' + // in the sense they hold onto the same value handles. + unsafe { GlobalAlloc::realloc(&self.as_view(), ptr, current, new_size) } + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + // We are a slab allocator and do not deallocate. + } +} + unsafe impl GlobalAlloc for BumpView<'_> { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { BumpView::alloc(*self, layout) diff --git a/static-alloc/src/leaked.rs b/static-alloc/src/leaked.rs index 9ea4b03..ee29172 100644 --- a/static-alloc/src/leaked.rs +++ b/static-alloc/src/leaked.rs @@ -2,13 +2,12 @@ //! //! FIXME(breaking): Naming. `leaking` implies the `Drop` of the value as well but we do the //! precise opposite. -use core::pin::Pin; use alloc_traits::AllocTime; +use core::pin::Pin; use core::{ alloc::Layout, - fmt, - hash, + fmt, hash, marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, @@ -50,10 +49,7 @@ impl Alloca { /// llvm might still reserve stack space for all variants including a probe and thus /// prematurely assume we have hit the bottom of the available stack space. This is not very /// likely to occur in practice. - pub fn run( - &self, - run: impl FnOnce(&mut [MaybeUninit]) -> R - ) -> R { + pub fn run(&self, run: impl FnOnce(&mut [MaybeUninit]) -> R) -> R { // Required size to surely have enough space for an aligned allocation. let required_size = self.padded_layout().size(); @@ -98,10 +94,7 @@ impl Alloca { } } - fn run_with]) -> R>( - &self, - run: F - ) -> R { + fn run_with]) -> R>(&self, run: F) -> R { use crate::unsync::Bump; let mem = Bump::::uninit(); let slot = mem.bump_array::(self.len).unwrap(); @@ -175,7 +168,7 @@ impl<'ctx, T> LeakBox<'ctx, T> { // * It is valid for write as it is the only pointer to it. // * The allocation lives for at least `'ctx`. unsafe { core::ptr::write(pointer.as_ptr(), val) }; - Self { pointer, lifetime, } + Self { pointer, lifetime } } } @@ -236,12 +229,15 @@ impl<'ctx, T: ?Sized> LeakBox<'ctx, T> { /// Dropping this `LeakBox` will drop the instance, which the caller must also guarantee to be /// sound. pub unsafe fn from_raw(pointer: *mut T) -> Self { - debug_assert!(!pointer.is_null(), "Null pointer passed to LeakBox::from_raw"); + debug_assert!( + !pointer.is_null(), + "Null pointer passed to LeakBox::from_raw" + ); LeakBox { lifetime: AllocTime::default(), // Safety: caller guarantees this points to a valid instance. Null never does that. - pointer: unsafe { NonNull::new_unchecked(pointer) }, + pointer: unsafe { NonNull::new_unchecked(pointer) }, } } @@ -315,7 +311,8 @@ impl<'ctx, T: ?Sized> LeakBox<'ctx, T> { /// # Some(()) } /// ``` pub fn leak<'a>(this: Self) -> &'a mut T - where 'ctx: 'a + where + 'ctx: 'a, { let pointer = LeakBox::into_raw(this); // SAFETY: @@ -341,7 +338,7 @@ impl LeakBox<'static, T> { /// Consider this example: /// /// ```compile_fail - /// use static_alloc::{Bump, leaked::LeakBox}; + /// use static_alloc::{Bump, leaked::LeakBox}; /// /// async fn example(x: usize) -> usize { /// // Holding reference across yield point. @@ -365,7 +362,7 @@ impl LeakBox<'static, T> { /// use of a macro or unsafe on the caller's part. Now, with the correct usage of `into_pin`: /// /// ``` - /// use static_alloc::{Bump, leaked::LeakBox}; + /// use static_alloc::{Bump, leaked::LeakBox}; /// /// async fn example(x: usize) -> usize { /// // Holding reference across yield point. @@ -442,7 +439,7 @@ impl<'ctx, T> LeakBox<'ctx, T> { /// about any actual use case. pub fn from_mut(val: &'ctx mut T) -> Self where - T: Copy + T: Copy, { // SAFETY: // * Is valid instance diff --git a/static-alloc/src/lib.rs b/static-alloc/src/lib.rs index be681ac..d64f6a5 100644 --- a/static-alloc/src/lib.rs +++ b/static-alloc/src/lib.rs @@ -56,7 +56,7 @@ pub mod unsync; // Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of // the macro invocation. -// +// // The inspiration for the macro and implementation is from // // diff --git a/static-alloc/src/unsync/bump.rs b/static-alloc/src/unsync/bump.rs index 7ca1858..a1e1798 100644 --- a/static-alloc/src/unsync/bump.rs +++ b/static-alloc/src/unsync/bump.rs @@ -13,8 +13,8 @@ use crate::leaked::LeakBox; /// A bump allocator whose storage capacity and alignment is given by `T`. /// -/// This type dereferences to the generic `MemBump` that implements the allocation behavior. Note -/// that `MemBump` is an unsized type. In contrast this type is sized so it is possible to +/// This type dereferences to the generic `BumpSlice` that implements the allocation behavior. Note +/// that `BumpSlice` is an unsized type. In contrast this type is sized so it is possible to /// construct an instance on the stack or leak one from another bump allocator such as a global /// one. /// @@ -33,9 +33,9 @@ use crate::leaked::LeakBox; /// /// ``` /// use static_alloc::unsync::Bump; -/// # use static_alloc::unsync::MemBump; -/// # fn subroutine_one(_: &MemBump) {} -/// # fn subroutine_two(_: &MemBump) {} +/// # use static_alloc::unsync::BumpSlice; +/// # fn subroutine_one(_: &BumpSlice) {} +/// # fn subroutine_two(_: &BumpSlice) {} /// /// let mut stack_buffer: Bump<[usize; 64]> = Bump::uninit(); /// subroutine_one(&stack_buffer); @@ -51,9 +51,9 @@ use crate::leaked::LeakBox; /// #[cfg_attr(feature = "alloc", doc = "```")] #[cfg_attr(not(feature = "alloc"), doc = "```ignore")] -/// use static_alloc::unsync::{Bump, MemBump}; +/// use static_alloc::unsync::{Bump, BumpSlice}; /// # struct Request; -/// # fn handle_request(_: &MemBump, _: Request) {} +/// # fn handle_request(_: &BumpSlice, _: Request) {} /// # fn iterate_recv() -> Option { None } /// let mut local_page: Box> = Box::new(Bump::uninit()); /// @@ -63,9 +63,9 @@ use crate::leaked::LeakBox; /// } /// ``` /// -/// ## Coercion into [`MemBump`] +/// ## Coercion into [`BumpSlice`] /// -/// This allocator nominally implements [`Deref`](core::ops::Deref) into [`MemBump`]. However, the +/// This allocator nominally implements [`Deref`](core::ops::Deref) into [`BumpSlice`]. However, the /// layout of these two structs is equivalent only for types that have at most an alignment of /// [`usize`] (e.g. arrays of `u8`, `u16`, or more integers depending on the platform pointer size). /// @@ -77,7 +77,7 @@ use crate::leaked::LeakBox; /// For instance, this will *fail* to compile: /// /// ```compile_fail -/// use static_alloc::unsync::{Bump, MemBump}; +/// use static_alloc::unsync::{Bump, BumpSlice}; /// /// #[repr(align(32))] /// struct HighlyAligned([u8; 128]); @@ -92,7 +92,7 @@ pub struct Bump { _index: Cell, /// The backing storage for raw allocated data. _data: UnsafeCell>, - // Warning: when changing the data layout, you must change `MemBump` as well. + // Warning: when changing the data layout, you must change `BumpSlice` as well. } /// An error used when one could not re-use raw memory for a bump allocator. @@ -103,7 +103,7 @@ pub struct FromMemError { /// A dynamically sized allocation block in which any type can be allocated. #[repr(C)] -pub struct MemBump { +pub struct BumpSlice { header: Header, /// The data slice of a node. This slice @@ -140,7 +140,7 @@ impl Bump { } #[cfg(feature = "alloc")] -impl MemBump { +impl BumpSlice { /// Allocate some space to use for a bump allocator. pub fn new(capacity: usize) -> alloc::boxed::Box { let layout = Self::layout_from_size(capacity).expect("Bad layout"); @@ -153,21 +153,21 @@ impl MemBump { // Safety: `layout_from_size` ensures at least the header fits, and the allocation was // obviously successful as just seen. unsafe { ptr::write(ptr as *mut Header, Header::empty()) }; - unsafe { alloc::boxed::Box::from_raw(ptr as *mut MemBump) } + unsafe { alloc::boxed::Box::from_raw(ptr as *mut BumpSlice) } } } -impl MemBump { +impl BumpSlice { /// Initialize a bump allocator from existing memory. /// /// # Usage /// /// ``` /// use core::mem::MaybeUninit; - /// use static_alloc::unsync::MemBump; + /// use static_alloc::unsync::BumpSlice; /// /// let mut backing = [MaybeUninit::new(0); 128]; - /// let alloc = MemBump::from_mem(&mut backing)?; + /// let alloc = BumpSlice::from_mem(&mut backing)?; /// /// # Ok::<(), static_alloc::unsync::FromMemError>(()) /// ``` @@ -193,8 +193,8 @@ impl MemBump { /// /// # Safety /// - /// The memory must contain data that has been previously wrapped as a `MemBump`, exactly. The - /// only endorsed sound form of obtaining such memory is [`MemBump::into_mem`]. + /// The memory must contain data that has been previously wrapped as a `BumpSlice`, exactly. The + /// only endorsed sound form of obtaining such memory is [`BumpSlice::into_mem`]. /// /// Warning: Any _use_ of the memory will have invalidated all pointers to allocated objects, /// more specifically the provenance of these pointers is no longer valid! You _must_ derive @@ -223,10 +223,10 @@ impl MemBump { debug_assert!(Self::layout_from_size(datasize).is_ok_and(|l| l.size() <= mem.len())); let raw = mem.as_mut_ptr() as *mut u8; - // Turn it into a fat pointer with correct metadata for a `MemBump`. + // Turn it into a fat pointer with correct metadata for a `BumpSlice`. // Safety: // - The data is writable as we owned - unsafe { &mut *(ptr::slice_from_raw_parts_mut(raw, datasize) as *mut MemBump) } + unsafe { &mut *(ptr::slice_from_raw_parts_mut(raw, datasize) as *mut BumpSlice) } } /// Unwrap the memory owned by an unsized bump allocator. @@ -240,15 +240,15 @@ impl MemBump { /// /// ```rust /// use core::mem::MaybeUninit; - /// use static_alloc::unsync::MemBump; + /// use static_alloc::unsync::BumpSlice; /// /// # let mut backing = [MaybeUninit::new(0); 128]; - /// # let alloc = MemBump::from_mem(&mut backing)?; - /// let memory: &mut [_] = MemBump::into_mem(alloc); + /// # let alloc = BumpSlice::from_mem(&mut backing)?; + /// let memory: &mut [_] = BumpSlice::into_mem(alloc); /// assert!(memory.len() <= 128, "Not guaranteed to use all memory"); /// /// // Safety: We have not touched the memory itself. - /// unsafe { MemBump::from_mem_unchecked(memory) }; + /// unsafe { BumpSlice::from_mem_unchecked(memory) }; /// # Ok::<(), static_alloc::unsync::FromMemError>(()) /// ``` pub fn into_mem<'lt>(this: LeakBox<'lt, Self>) -> &'lt mut [MaybeUninit] { @@ -257,10 +257,10 @@ impl MemBump { unsafe { &mut *ptr::slice_from_raw_parts_mut(mem_pointer, layout.size()) } } - /// Returns the layout for the `header` of a `MemBump`. + /// Returns the layout for the `header` of a `BumpSlice`. /// The definition of `header` in this case is all the /// fields that come **before** the `data` field. - /// If any of the fields of a MemBump are modified, + /// If any of the fields of a BumpSlice are modified, /// this function likely has to be modified too. fn header_layout() -> Layout { Layout::new::>() @@ -271,7 +271,7 @@ impl MemBump { Layout::array::>>(size) } - /// Returns a layout for a MemBump where the length of the data field is `size`. + /// Returns a layout for a BumpSlice where the length of the data field is `size`. /// This relies on the two functions defined above. pub(crate) fn layout_from_size(size: usize) -> Result { let data_tail = Self::data_layout(size)?; @@ -279,7 +279,7 @@ impl MemBump { Ok(layout.pad_to_align()) } - /// Returns capacity of this `MemBump`. + /// Returns capacity of this `BumpSlice`. /// This is how many *bytes* can be allocated /// within this node. pub const fn capacity(&self) -> usize { @@ -290,9 +290,9 @@ impl MemBump { /// /// Note that *any* use of the pointer must be done with extreme care as it may invalidate /// existing references into the allocated region. Furthermore, bytes may not be initialized. - /// The length of the valid region is [`MemBump::capacity`]. + /// The length of the valid region is [`BumpSlice::capacity`]. /// - /// Prefer [`MemBump::get_unchecked`] for reconstructing a prior allocation. + /// Prefer [`BumpSlice::get_unchecked`] for reconstructing a prior allocation. pub fn data_ptr(&self) -> NonNull { NonNull::new(self.data.get() as *mut u8).expect("from a reference") } @@ -386,9 +386,9 @@ impl MemBump { /// /// ``` /// # use core::mem::MaybeUninit; - /// # use static_alloc::unsync::MemBump; + /// # use static_alloc::unsync::BumpSlice; /// # let mut backing = [MaybeUninit::new(0); 128]; - /// # let alloc = MemBump::from_mem(&mut backing).unwrap(); + /// # let alloc = BumpSlice::from_mem(&mut backing).unwrap(); /// // Create an initial allocation. /// let level = alloc.level(); /// let allocation = alloc.get_at::(level)?; @@ -408,9 +408,9 @@ impl MemBump { /// /// ``` /// # use core::mem::MaybeUninit; - /// # use static_alloc::{leaked::LeakBox, unsync::MemBump}; + /// # use static_alloc::{leaked::LeakBox, unsync::BumpSlice}; /// # let mut backing = [MaybeUninit::new(0); 128]; - /// # let alloc = MemBump::from_mem(&mut backing).unwrap(); + /// # let alloc = BumpSlice::from_mem(&mut backing).unwrap(); /// let level = alloc.level(); /// alloc.get_at::(level)?; /// @@ -612,15 +612,15 @@ impl EnsureDerefIsApplicable { if mem::offset_of!(Bump, _data) != mem::size_of::
() { panic!( // `data` follows header directly, using the macro requires a value for unsized types. - "This `unsync::Bump` can not be used as a `MemBump` since the reinterpretation changes the data layout. (Hint: its alignment must be at most `usize`).", + "This `unsync::Bump` can not be used as a `BumpSlice` since the reinterpretation changes the data layout. (Hint: its alignment must be at most `usize`).", ); } }; } impl ops::Deref for Bump { - type Target = MemBump; - fn deref(&self) -> &MemBump { + type Target = BumpSlice; + fn deref(&self) -> &BumpSlice { // This provokes post-mono error! let _: () = EnsureDerefIsApplicable::::ASSERT; @@ -630,15 +630,15 @@ impl ops::Deref for Bump { // struct instead. This meta data is later copied to the meta data of `bump` when cast. let ptr = (self as *const Self).cast::>(); let mem: *const [MaybeUninit] = ptr::slice_from_raw_parts(ptr, data_layout.size()); - // Now we have a pointer to MemBump with length meta data of the data slice. - let bump = unsafe { &*(mem as *const MemBump) }; + // Now we have a pointer to BumpSlice with length meta data of the data slice. + let bump = unsafe { &*(mem as *const BumpSlice) }; debug_assert_eq!(from_layout, Layout::for_value(bump)); bump } } impl ops::DerefMut for Bump { - fn deref_mut(&mut self) -> &mut MemBump { + fn deref_mut(&mut self) -> &mut BumpSlice { // This provokes post-mono error! let _: () = EnsureDerefIsApplicable::::ASSERT; @@ -648,8 +648,8 @@ impl ops::DerefMut for Bump { // struct instead. This meta data is later copied to the meta data of `bump` when cast. let ptr = (self as *mut Self).cast::>(); let mem: *mut [MaybeUninit] = ptr::slice_from_raw_parts_mut(ptr, data_layout.size()); - // Now we have a pointer to MemBump with length meta data of the data slice. - let bump = unsafe { &mut *(mem as *mut MemBump) }; + // Now we have a pointer to BumpSlice with length meta data of the data slice. + let bump = unsafe { &mut *(mem as *mut BumpSlice) }; debug_assert_eq!(from_layout, Layout::for_value(bump)); bump } @@ -676,6 +676,6 @@ impl Header { #[test] fn mem_bump_derefs_correctly() { let bump = Bump::::zeroed(); - let mem: &MemBump = ≎ + let mem: &BumpSlice = ≎ assert_eq!(mem::size_of_val(&bump), mem::size_of_val(mem)); } diff --git a/static-alloc/src/unsync/chain.rs b/static-alloc/src/unsync/chain.rs index ec9c2a0..0c7d46d 100644 --- a/static-alloc/src/unsync/chain.rs +++ b/static-alloc/src/unsync/chain.rs @@ -1,20 +1,17 @@ //! This module defines a simple bump allocator. //! The allocator is not thread safe. use core::{ - alloc::{Layout, LayoutErr}, + alloc::{Layout, LayoutError}, cell::Cell, mem::MaybeUninit, ptr::{self, NonNull}, }; -use alloc::{ - alloc::alloc_zeroed, - boxed::Box, -}; +use alloc::{alloc::alloc_zeroed, boxed::Box}; use crate::bump::Failure; -use crate::unsync::bump::MemBump; use crate::leaked::LeakBox; +use crate::unsync::bump::BumpSlice; /// An error representing an error while construction /// a [`Chain`]. @@ -39,7 +36,7 @@ struct Link { /// this field with just an &self reference. next: Cell, /// The bump allocator of this link. - bump: MemBump, + bump: BumpSlice, } /// A `Chain` is a simple bump allocator, that draws @@ -62,9 +59,9 @@ impl Chain { } /// Attempts to allocate `elem` within the allocator. - pub fn bump_box<'bump, T: 'bump>(&'bump self) - -> Result>, Failure> - { + pub fn bump_box<'bump, T: 'bump>( + &'bump self, + ) -> Result>, Failure> { let root = self.root().ok_or(Failure::Exhausted)?; root.as_bump().bump_box() } @@ -79,9 +76,7 @@ impl Chain { let self_bump = self.root.take(); match new.root() { - None => { - self.root.set(self_bump) - } + None => self.root.set(self_bump), Some(root) => { unsafe { root.set_next(self_bump) }; self.root.set(new.root.take()) @@ -118,7 +113,7 @@ impl Chain { } /// A type representing a failure while allocating -/// a `MemBump`. +/// a `BumpSlice`. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub(crate) struct RawAllocError { allocation_size: usize, @@ -138,41 +133,38 @@ impl Link { /// It must point to a valid link. Furthermore, the old link is dropped! pub(crate) unsafe fn set_next(&self, next: LinkPtr) { if let Some(next) = self.next.replace(next) { - let _ = Box::from_raw(next.as_ptr()); + // Safety: any value we stored into `next` is from `Box::leak` + let _ = unsafe { Box::from_raw(next.as_ptr()) }; } } /// Take over the control over the tail. pub(crate) fn take_next(&self) -> Option> { let ptr = self.next.take()?; - Some(unsafe { - Box::from_raw(ptr.as_ptr()) - }) + // Safety: any value we stored into `next` is from `Box::leak` + Some(unsafe { Box::from_raw(ptr.as_ptr()) }) } - pub(crate) fn as_bump(&self) -> &MemBump { + pub(crate) fn as_bump(&self) -> &BumpSlice { &self.bump } - pub(crate) fn layout_from_size(size: usize) -> Result { + pub(crate) fn layout_from_size(size: usize) -> Result { Layout::new::>() - .extend(MemBump::layout_from_size(size)?) + .extend(BumpSlice::layout_from_size(size)?) .map(|layout| layout.0) } unsafe fn alloc_raw(layout: Layout) -> Result, RawAllocError> { let ptr = alloc_zeroed(layout); - NonNull::new(ptr).ok_or_else(|| { - RawAllocError::new(layout.size(), RawAllocFailure::Exhausted) - }) + NonNull::new(ptr) + .ok_or_else(|| RawAllocError::new(layout.size(), RawAllocFailure::Exhausted)) } - /// Allocates a MemBump and returns it. + /// Allocates a BumpSlice and returns it. pub(crate) fn alloc(capacity: usize) -> Result, RawAllocError> { let layout = Self::layout_from_size(capacity) - .map_err(|_| { - RawAllocError::new(capacity, RawAllocFailure::Layout) - })?; + .map_err(|_| RawAllocError::new(capacity, RawAllocFailure::Layout))?; unsafe { let raw = Link::alloc_raw(layout)?; diff --git a/static-alloc/src/unsync/mod.rs b/static-alloc/src/unsync/mod.rs index e1216bc..f094c7c 100644 --- a/static-alloc/src/unsync/mod.rs +++ b/static-alloc/src/unsync/mod.rs @@ -1,7 +1,7 @@ mod bump; -#[cfg(all(feature = "alloc", feature="nightly_chain"))] +#[cfg(all(feature = "alloc", feature = "nightly_chain"))] mod chain; -pub use bump::{Bump, FromMemError, MemBump}; -#[cfg(all(feature="alloc", feature="nightly_chain"))] -pub use chain::{Chain}; +pub use bump::{Bump, BumpSlice, FromMemError}; +#[cfg(all(feature = "alloc", feature = "nightly_chain"))] +pub use chain::Chain; diff --git a/static-alloc/tests/alloca.rs b/static-alloc/tests/alloca.rs index e8af39e..76654e7 100644 --- a/static-alloc/tests/alloca.rs +++ b/static-alloc/tests/alloca.rs @@ -2,8 +2,7 @@ use static_alloc::leaked::Alloca; #[test] fn alloca_small() { - let alloc = Alloca::::new(16) - .unwrap(); + let alloc = Alloca::::new(16).unwrap(); alloc.run(|slice| { assert_eq!(slice.len(), 16); }); diff --git a/static-alloc/tests/threaded.rs b/static-alloc/tests/threaded.rs index 10ae703..31e1f79 100644 --- a/static-alloc/tests/threaded.rs +++ b/static-alloc/tests/threaded.rs @@ -7,9 +7,13 @@ fn each_thread_one() { // Static but not the global allocator. static BUMP: Bump<[u64; COUNT]> = Bump::uninit(); - let threads = (0..COUNT).map(|i| thread::spawn(move || { - BUMP.leak(i).unwrap(); - })).collect::>(); + let threads = (0..COUNT) + .map(|i| { + thread::spawn(move || { + BUMP.leak(i).unwrap(); + }) + }) + .collect::>(); threads .into_iter() diff --git a/static-alloc/tests/unsync.rs b/static-alloc/tests/unsync.rs index 0dcc3e4..2920785 100644 --- a/static-alloc/tests/unsync.rs +++ b/static-alloc/tests/unsync.rs @@ -1,12 +1,11 @@ use core::mem::MaybeUninit; use static_alloc::leaked::LeakBox; -use static_alloc::unsync::MemBump; +use static_alloc::unsync::BumpSlice; #[test] fn raw_from_mem() { let mut memory = [MaybeUninit::new(0); 128]; - let bump = MemBump::from_mem(&mut memory) - .expect("Enough memory for its metadata"); + let bump = BumpSlice::from_mem(&mut memory).expect("Enough memory for its metadata"); let n1 = bump.bump_box::().unwrap(); let n2 = bump.bump_box::().unwrap(); @@ -29,11 +28,9 @@ fn raw_from_mem() { #[cfg(feature = "alloc")] fn allocate_with_fixed_capacity() { const CAPACITY: usize = 16; - let bump = MemBump::new(CAPACITY); + let bump = BumpSlice::new(CAPACITY); for i in 0..CAPACITY { - bump.get::().unwrap_or_else(|| { - panic!("works {}", i) - }); + bump.get::().unwrap_or_else(|| panic!("works {}", i)); } assert!(bump.get::().is_none()); } diff --git a/static-alloc/tests/vec.rs b/static-alloc/tests/vec.rs index 8aa6bd1..40e7306 100644 --- a/static-alloc/tests/vec.rs +++ b/static-alloc/tests/vec.rs @@ -7,8 +7,7 @@ static A: Bump<[u8; 1 << 20]> = Bump::uninit(); fn ok_vec() { let v = vec![0xdeadbeef_u32; 128]; println!("{:x?}", v); - v.into_iter() - .for_each(|x| assert_eq!(x, 0xdeadbeef_u32)); + v.into_iter().for_each(|x| assert_eq!(x, 0xdeadbeef_u32)); } #[test]