1
- use std:: { alloc, mem, ptr} ;
1
+ use std:: {
2
+ alloc, mem,
3
+ ptr:: { self , NonNull } ,
4
+ } ;
2
5
3
6
/// A typesafe helper that stores the allocated pointer without the data initialized.
4
- pub struct BoxAllocation < T > ( * mut T ) ;
7
+ pub struct BoxAllocation < T > (
8
+ // ptr cannot be null since it would mean the allocation failed.
9
+ // Note: covariance is acceptable since this eventually becomes a `Box<T>`,
10
+ // which is covariant too.
11
+ NonNull < T > ,
12
+ ) ;
5
13
6
14
impl < T > BoxAllocation < T > {
7
15
/// Consumes self and writes the given value into the allocation.
8
- pub fn init ( mut self , value : T ) -> Box < T > {
16
+ #[ inline( always) ] // if this does not get inlined then copying happens
17
+ pub fn init ( self , value : T ) -> Box < T > {
9
18
if mem:: size_of :: < T > ( ) == 0 {
10
19
return Box :: new ( value) ;
11
20
}
12
21
13
- let ptr = mem:: replace ( & mut self . 0 , ptr:: null_mut ( ) ) ;
14
22
unsafe {
23
+ let ptr = self . 0 . as_ptr ( ) ;
24
+ mem:: forget ( self ) ;
15
25
ptr:: write ( ptr, value) ;
16
26
Box :: from_raw ( ptr)
17
27
}
@@ -20,16 +30,17 @@ impl<T> BoxAllocation<T> {
20
30
21
31
impl < T > Drop for BoxAllocation < T > {
22
32
fn drop ( & mut self ) {
23
- if !self . 0 . is_null ( ) {
24
- let layout = alloc:: Layout :: new :: < T > ( ) ;
25
- unsafe {
26
- alloc:: dealloc ( self . 0 as * mut u8 , layout) ;
27
- }
33
+ if mem:: size_of :: < T > ( ) == 0 {
34
+ return ;
35
+ }
36
+
37
+ let layout = alloc:: Layout :: new :: < T > ( ) ;
38
+ unsafe {
39
+ alloc:: dealloc ( self . 0 . as_ptr ( ) as * mut u8 , layout) ;
28
40
}
29
41
}
30
42
}
31
43
32
-
33
44
/// Helper trait for a `Box` type that allocates up-front.
34
45
pub trait BoxHelper < T > {
35
46
/// Allocates the storage without providing any data.
@@ -39,12 +50,13 @@ pub trait BoxHelper<T> {
39
50
impl < T > BoxHelper < T > for Box < T > {
40
51
fn alloc ( ) -> BoxAllocation < T > {
41
52
if mem:: size_of :: < T > ( ) == 0 {
42
- return BoxAllocation ( ptr :: null_mut ( ) ) ;
53
+ return BoxAllocation ( NonNull :: dangling ( ) ) ;
43
54
}
44
55
45
56
let layout = alloc:: Layout :: new :: < T > ( ) ;
46
- BoxAllocation ( unsafe {
47
- alloc:: alloc ( layout) as * mut T
48
- } )
57
+ BoxAllocation (
58
+ NonNull :: new ( unsafe { alloc:: alloc ( layout) as * mut T } )
59
+ . unwrap_or_else ( || alloc:: handle_alloc_error ( layout) ) , // oom
60
+ )
49
61
}
50
62
}
0 commit comments