@@ -10,80 +10,107 @@ use std::{
10
10
11
11
#[ repr( align( 128 ) ) ]
12
12
struct Chonk < const N : usize > {
13
- data : [ MaybeUninit < u8 > ; N ] ,
13
+ data : MaybeUninit < [ u8 ; N ] > ,
14
14
}
15
15
16
16
impl < 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) )
21
35
}
22
36
}
23
37
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 > {
25
55
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 > ,
27
60
}
28
61
29
- impl < F > Deref for OwnedHeap < F > {
62
+ impl < const N : usize > Deref for OwnedHeap < N > {
30
63
type Target = Heap ;
31
64
32
65
fn deref ( & self ) -> & Self :: Target {
33
66
& self . heap
34
67
}
35
68
}
36
69
37
- impl < F > DerefMut for OwnedHeap < F > {
70
+ impl < const N : usize > DerefMut for OwnedHeap < N > {
38
71
fn deref_mut ( & mut self ) -> & mut Self :: Target {
39
72
& mut self . heap
40
73
}
41
74
}
42
75
43
- pub fn new_heap ( ) -> OwnedHeap < impl Sized > {
76
+ pub fn new_heap ( ) -> OwnedHeap < 1000 > {
44
77
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 ( ) ;
48
79
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 ) ;
51
82
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
+ }
57
87
}
58
88
59
- fn new_max_heap ( ) -> OwnedHeap < impl Sized > {
89
+ fn new_max_heap ( ) -> OwnedHeap < 2048 > {
60
90
const HEAP_SIZE : usize = 1024 ;
61
91
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 ( ) ;
65
93
66
94
// 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 ) ;
69
97
assert_eq ! ( heap. size( ) , HEAP_SIZE ) ;
70
98
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
+ }
75
103
}
76
104
77
- fn new_heap_skip ( ct : usize ) -> OwnedHeap < impl Sized > {
105
+ fn new_heap_skip ( ct : usize ) -> OwnedHeap < 1000 > {
78
106
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
+ }
87
114
}
88
115
89
116
#[ test]
@@ -96,17 +123,18 @@ fn empty() {
96
123
#[ test]
97
124
fn oom ( ) {
98
125
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 ( ) ;
102
127
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 ) ;
105
130
assert_eq ! ( heap. size( ) , align_down_size( HEAP_SIZE , size_of:: <usize >( ) ) ) ;
106
131
107
132
let layout = Layout :: from_size_align ( heap. size ( ) + 1 , align_of :: < usize > ( ) ) ;
108
133
let addr = heap. allocate_first_fit ( layout. unwrap ( ) ) ;
109
134
assert ! ( addr. is_err( ) ) ;
135
+
136
+ // Explicitly unleak the heap allocation
137
+ unsafe { Chonk :: unleak ( heap_space_ptr) } ;
110
138
}
111
139
112
140
#[ test]
0 commit comments