@@ -10,80 +10,107 @@ use std::{
1010
1111#[ repr( align( 128 ) ) ]
1212struct Chonk < const N : usize > {
13- data : [ MaybeUninit < u8 > ; N ] ,
13+ data : MaybeUninit < [ u8 ; N ] > ,
1414}
1515
1616impl < const N : usize > Chonk < N > {
17- pub fn new ( ) -> Self {
18- Self {
19- data : [ MaybeUninit :: uninit ( ) ; N ] ,
20- }
17+ /// Returns (almost certainly aliasing) pointers to the Chonk
18+ /// as well as the data payload.
19+ ///
20+ /// MUST be freed with a matching call to `Chonk::unleak`
21+ pub fn new ( ) -> ( * mut Chonk < N > , * mut u8 ) {
22+ let heap_space_ptr: * mut Chonk < N > = {
23+ let owned_box = Box :: new ( Self {
24+ data : MaybeUninit :: uninit ( ) ,
25+ } ) ;
26+ let mutref = Box :: leak ( owned_box) ;
27+ mutref
28+ } ;
29+ let data_ptr: * mut u8 = unsafe { core:: ptr:: addr_of_mut!( ( * heap_space_ptr) . data) . cast ( ) } ;
30+ ( heap_space_ptr, data_ptr)
31+ }
32+
33+ pub unsafe fn unleak ( putter : * mut Chonk < N > ) {
34+ drop ( Box :: from_raw ( putter) )
2135 }
2236}
2337
24- pub struct OwnedHeap < F > {
38+ pub struct Dropper < const N : usize > {
39+ putter : * mut Chonk < N > ,
40+ }
41+
42+ impl < const N : usize > Dropper < N > {
43+ fn new ( putter : * mut Chonk < N > ) -> Self {
44+ Self { putter }
45+ }
46+ }
47+
48+ impl < const N : usize > Drop for Dropper < N > {
49+ fn drop ( & mut self ) {
50+ unsafe { Chonk :: unleak ( self . putter ) }
51+ }
52+ }
53+
54+ pub struct OwnedHeap < const N : usize > {
2555 heap : Heap ,
26- _drop : F ,
56+ // /!\ SAFETY /!\: Load bearing drop order! `_drop` MUST be dropped AFTER
57+ // `heap` is dropped. This is enforced by rust's built-in drop ordering, as
58+ // long as `_drop` is declared after `heap`.
59+ _drop : Dropper < N > ,
2760}
2861
29- impl < F > Deref for OwnedHeap < F > {
62+ impl < const N : usize > Deref for OwnedHeap < N > {
3063 type Target = Heap ;
3164
3265 fn deref ( & self ) -> & Self :: Target {
3366 & self . heap
3467 }
3568}
3669
37- impl < F > DerefMut for OwnedHeap < F > {
70+ impl < const N : usize > DerefMut for OwnedHeap < N > {
3871 fn deref_mut ( & mut self ) -> & mut Self :: Target {
3972 & mut self . heap
4073 }
4174}
4275
43- pub fn new_heap ( ) -> OwnedHeap < impl Sized > {
76+ pub fn new_heap ( ) -> OwnedHeap < 1000 > {
4477 const HEAP_SIZE : usize = 1000 ;
45- let mut heap_space = Box :: new ( Chonk :: < HEAP_SIZE > :: new ( ) ) ;
46- let data = & mut heap_space. data ;
47- let assumed_location = data. as_mut_ptr ( ) . cast ( ) ;
78+ let ( heap_space_ptr, data_ptr) = Chonk :: < HEAP_SIZE > :: new ( ) ;
4879
49- let heap = unsafe { Heap :: new ( data . as_mut_ptr ( ) . cast ( ) , data . len ( ) ) } ;
50- assert_eq ! ( heap. bottom( ) , assumed_location ) ;
80+ let heap = unsafe { Heap :: new ( data_ptr , HEAP_SIZE ) } ;
81+ assert_eq ! ( heap. bottom( ) , data_ptr ) ;
5182 assert_eq ! ( heap. size( ) , align_down_size( HEAP_SIZE , size_of:: <usize >( ) ) ) ;
52-
53- let drop = move || {
54- let _ = heap_space;
55- } ;
56- OwnedHeap { heap, _drop : drop }
83+ OwnedHeap {
84+ heap,
85+ _drop : Dropper :: new ( heap_space_ptr) ,
86+ }
5787}
5888
59- fn new_max_heap ( ) -> OwnedHeap < impl Sized > {
89+ fn new_max_heap ( ) -> OwnedHeap < 2048 > {
6090 const HEAP_SIZE : usize = 1024 ;
6191 const HEAP_SIZE_MAX : usize = 2048 ;
62- let mut heap_space = Box :: new ( Chonk :: < HEAP_SIZE_MAX > :: new ( ) ) ;
63- let data = & mut heap_space. data ;
64- let start_ptr = data. as_mut_ptr ( ) . cast ( ) ;
92+ let ( heap_space_ptr, data_ptr) = Chonk :: < HEAP_SIZE_MAX > :: new ( ) ;
6593
6694 // Unsafe so that we have provenance over the whole allocation.
67- let heap = unsafe { Heap :: new ( start_ptr , HEAP_SIZE ) } ;
68- assert_eq ! ( heap. bottom( ) , start_ptr ) ;
95+ let heap = unsafe { Heap :: new ( data_ptr , HEAP_SIZE ) } ;
96+ assert_eq ! ( heap. bottom( ) , data_ptr ) ;
6997 assert_eq ! ( heap. size( ) , HEAP_SIZE ) ;
7098
71- let drop = move || {
72- let _ = heap_space ;
73- } ;
74- OwnedHeap { heap , _drop : drop }
99+ OwnedHeap {
100+ heap ,
101+ _drop : Dropper :: new ( heap_space_ptr ) ,
102+ }
75103}
76104
77- fn new_heap_skip ( ct : usize ) -> OwnedHeap < impl Sized > {
105+ fn new_heap_skip ( ct : usize ) -> OwnedHeap < 1000 > {
78106 const HEAP_SIZE : usize = 1000 ;
79- let mut heap_space = Box :: new ( Chonk :: < HEAP_SIZE > :: new ( ) ) ;
80- let data = & mut heap_space. data [ ct..] ;
81- let heap = unsafe { Heap :: new ( data. as_mut_ptr ( ) . cast ( ) , data. len ( ) ) } ;
82-
83- let drop = move || {
84- let _ = heap_space;
85- } ;
86- OwnedHeap { heap, _drop : drop }
107+ let ( heap_space_ptr, data_ptr) = Chonk :: < HEAP_SIZE > :: new ( ) ;
108+
109+ let heap = unsafe { Heap :: new ( data_ptr. add ( ct) , HEAP_SIZE - ct) } ;
110+ OwnedHeap {
111+ heap,
112+ _drop : Dropper :: new ( heap_space_ptr) ,
113+ }
87114}
88115
89116#[ test]
@@ -96,17 +123,18 @@ fn empty() {
96123#[ test]
97124fn oom ( ) {
98125 const HEAP_SIZE : usize = 1000 ;
99- let mut heap_space = Box :: new ( Chonk :: < HEAP_SIZE > :: new ( ) ) ;
100- let data = & mut heap_space. data ;
101- let assumed_location = data. as_mut_ptr ( ) . cast ( ) ;
126+ let ( heap_space_ptr, data_ptr) = Chonk :: < HEAP_SIZE > :: new ( ) ;
102127
103- let mut heap = unsafe { Heap :: new ( data . as_mut_ptr ( ) . cast ( ) , data . len ( ) ) } ;
104- assert_eq ! ( heap. bottom( ) , assumed_location ) ;
128+ let mut heap = unsafe { Heap :: new ( data_ptr , HEAP_SIZE ) } ;
129+ assert_eq ! ( heap. bottom( ) , data_ptr ) ;
105130 assert_eq ! ( heap. size( ) , align_down_size( HEAP_SIZE , size_of:: <usize >( ) ) ) ;
106131
107132 let layout = Layout :: from_size_align ( heap. size ( ) + 1 , align_of :: < usize > ( ) ) ;
108133 let addr = heap. allocate_first_fit ( layout. unwrap ( ) ) ;
109134 assert ! ( addr. is_err( ) ) ;
135+
136+ // Explicitly unleak the heap allocation
137+ unsafe { Chonk :: unleak ( heap_space_ptr) } ;
110138}
111139
112140#[ test]
0 commit comments