@@ -29,7 +29,9 @@ use core::ptr::{self, NonNull};
29
29
/// ```
30
30
#[ unstable( feature = "thin_box" , issue = "92791" ) ]
31
31
pub struct ThinBox < T : ?Sized > {
32
- ptr : WithHeader < <T as Pointee >:: Metadata > ,
32
+ // This is essentially `WithHeader<<T as Pointee>::Metadata>`,
33
+ // but that would be invariant in `T`, and we want covariance.
34
+ ptr : WithOpaqueHeader ,
33
35
_marker : PhantomData < T > ,
34
36
}
35
37
@@ -49,7 +51,7 @@ impl<T> ThinBox<T> {
49
51
#[ cfg( not( no_global_oom_handling) ) ]
50
52
pub fn new ( value : T ) -> Self {
51
53
let meta = ptr:: metadata ( & value) ;
52
- let ptr = WithHeader :: new ( meta, value) ;
54
+ let ptr = WithOpaqueHeader :: new ( meta, value) ;
53
55
ThinBox { ptr, _marker : PhantomData }
54
56
}
55
57
}
@@ -73,7 +75,7 @@ impl<Dyn: ?Sized> ThinBox<Dyn> {
73
75
T : Unsize < Dyn > ,
74
76
{
75
77
let meta = ptr:: metadata ( & value as & Dyn ) ;
76
- let ptr = WithHeader :: new ( meta, value) ;
78
+ let ptr = WithOpaqueHeader :: new ( meta, value) ;
77
79
ThinBox { ptr, _marker : PhantomData }
78
80
}
79
81
}
@@ -120,7 +122,7 @@ impl<T: ?Sized> Drop for ThinBox<T> {
120
122
unsafe {
121
123
let value = self . deref_mut ( ) ;
122
124
let value = value as * mut T ;
123
- self . ptr . drop :: < T > ( value) ;
125
+ self . with_header ( ) . drop :: < T > ( value) ;
124
126
}
125
127
}
126
128
}
@@ -130,11 +132,16 @@ impl<T: ?Sized> ThinBox<T> {
130
132
fn meta ( & self ) -> <T as Pointee >:: Metadata {
131
133
// Safety:
132
134
// - NonNull and valid.
133
- unsafe { * self . ptr . header ( ) }
135
+ unsafe { * self . with_header ( ) . header ( ) }
134
136
}
135
137
136
138
fn data ( & self ) -> * mut u8 {
137
- self . ptr . value ( )
139
+ self . with_header ( ) . value ( )
140
+ }
141
+
142
+ fn with_header ( & self ) -> & WithHeader < <T as Pointee >:: Metadata > {
143
+ // SAFETY: both types are transparent to `NonNull<u8>`
144
+ unsafe { & * ( ( & self . ptr ) as * const WithOpaqueHeader as * const WithHeader < _ > ) }
138
145
}
139
146
}
140
147
@@ -143,8 +150,22 @@ impl<T: ?Sized> ThinBox<T> {
143
150
/// metadata (`H`) are ZSTs.
144
151
/// 2. A pointer to a valid `T` that has a header `H` directly before the
145
152
/// pointed-to location.
153
+ #[ repr( transparent) ]
146
154
struct WithHeader < H > ( NonNull < u8 > , PhantomData < H > ) ;
147
155
156
+ /// An opaque representation of `WithHeader<H>` to avoid the
157
+ /// projection invariance of `<T as Pointee>::Metadata`.
158
+ #[ repr( transparent) ]
159
+ struct WithOpaqueHeader ( NonNull < u8 > ) ;
160
+
161
+ impl WithOpaqueHeader {
162
+ #[ cfg( not( no_global_oom_handling) ) ]
163
+ fn new < H , T > ( header : H , value : T ) -> Self {
164
+ let ptr = WithHeader :: new ( header, value) ;
165
+ Self ( ptr. 0 )
166
+ }
167
+ }
168
+
148
169
impl < H > WithHeader < H > {
149
170
#[ cfg( not( no_global_oom_handling) ) ]
150
171
fn new < T > ( header : H , value : T ) -> WithHeader < H > {
0 commit comments