11use std:: {
22 alloc:: { self , GlobalAlloc , Layout , System } ,
3- mem:: ManuallyDrop ,
4- ops:: Deref ,
3+ mem:: { self , ManuallyDrop } ,
54 ptr:: NonNull ,
65 sync:: {
76 Mutex ,
@@ -16,6 +15,8 @@ use crate::{
1615 generated:: fixed_size_constants:: { BLOCK_ALIGN , BLOCK_SIZE , RAW_METADATA_SIZE } ,
1716} ;
1817
18+ use super :: AllocatorGuard ;
19+
1920const TWO_GIB : usize = 1 << 31 ;
2021const FOUR_GIB : usize = 1 << 32 ;
2122
@@ -46,12 +47,12 @@ impl AllocatorPool {
4647 ///
4748 /// Panics if the underlying mutex is poisoned.
4849 pub fn get ( & self ) -> AllocatorGuard < ' _ > {
49- let allocator = {
50+ let fixed_size_allocator = {
5051 let mut allocators = self . allocators . lock ( ) . unwrap ( ) ;
5152 allocators. pop ( )
5253 } ;
5354
54- let allocator = allocator . unwrap_or_else ( || {
55+ let fixed_size_allocator = fixed_size_allocator . unwrap_or_else ( || {
5556 // Each allocator needs to have a unique ID, but the order those IDs are assigned in
5657 // doesn't matter, so `Ordering::Relaxed` is fine
5758 let id = self . next_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
@@ -61,45 +62,31 @@ impl AllocatorPool {
6162 FixedSizeAllocator :: new ( id)
6263 } ) ;
6364
64- AllocatorGuard { allocator : ManuallyDrop :: new ( allocator) , pool : self }
65+ // Unwrap `FixedSizeAllocator`.
66+ // `add` method will wrap it again, before returning it to pool, ensuring it gets dropped properly.
67+ // SAFETY: `FixedSizeAllocator` is just a wrapper around `ManuallyDrop<Allocator>`,
68+ // and is `#[repr(transparent)]`, so the 2 are equivalent.
69+ let allocator = unsafe {
70+ mem:: transmute :: < FixedSizeAllocator , ManuallyDrop < Allocator > > ( fixed_size_allocator)
71+ } ;
72+
73+ AllocatorGuard { allocator, pool : self }
6574 }
6675
67- /// Add a [`FixedSizeAllocator `] to the pool.
76+ /// Add an [`Allocator `] to the pool.
6877 ///
6978 /// The `Allocator` is reset by this method, so it's ready to be re-used.
7079 ///
7180 /// # Panics
7281 ///
7382 /// Panics if the underlying mutex is poisoned.
74- fn add ( & self , mut allocator : FixedSizeAllocator ) {
75- allocator. reset ( ) ;
76- let mut allocators = self . allocators . lock ( ) . unwrap ( ) ;
77- allocators. push ( allocator) ;
78- }
79- }
83+ pub ( super ) fn add ( & self , allocator : Allocator ) {
84+ let mut fixed_size_allocator =
85+ FixedSizeAllocator { allocator : ManuallyDrop :: new ( allocator) } ;
86+ fixed_size_allocator. reset ( ) ;
8087
81- /// A guard object representing exclusive access to an [`Allocator`] from the pool.
82- ///
83- /// On drop, the `Allocator` is reset and returned to the pool.
84- pub struct AllocatorGuard < ' alloc_pool > {
85- allocator : ManuallyDrop < FixedSizeAllocator > ,
86- pool : & ' alloc_pool AllocatorPool ,
87- }
88-
89- impl Deref for AllocatorGuard < ' _ > {
90- type Target = Allocator ;
91-
92- fn deref ( & self ) -> & Self :: Target {
93- & self . allocator . allocator
94- }
95- }
96-
97- impl Drop for AllocatorGuard < ' _ > {
98- /// Return [`Allocator`] back to the pool.
99- fn drop ( & mut self ) {
100- // SAFETY: After taking ownership of the `FixedSizeAllocator`, we do not touch the `ManuallyDrop` again
101- let allocator = unsafe { ManuallyDrop :: take ( & mut self . allocator ) } ;
102- self . pool . add ( allocator) ;
88+ let mut allocators = self . allocators . lock ( ) . unwrap ( ) ;
89+ allocators. push ( fixed_size_allocator) ;
10390 }
10491}
10592
@@ -198,6 +185,7 @@ const ALLOC_LAYOUT: Layout = match Layout::from_size_align(ALLOC_SIZE, ALLOC_ALI
198185/// * `BLOCK_SIZE` is a multiple of 16.
199186/// * `RawTransferMetadata` is 16 bytes.
200187/// * Size of `FixedSizeAllocatorMetadata` is rounded up to a multiple of 16.
188+ #[ repr( transparent) ]
201189struct FixedSizeAllocator {
202190 /// `Allocator` which utilizes part of the original allocation
203191 allocator : ManuallyDrop < Allocator > ,
0 commit comments