12
12
// Pierre Avital, <[email protected] >
13
13
//
14
14
15
- use crate as stabby;
15
+ use crate :: { self as stabby} ;
16
+ use core:: {
17
+ hash:: { Hash , Hasher } ,
18
+ marker:: PhantomData ,
19
+ ptr:: NonNull ,
20
+ } ;
16
21
17
22
#[ rustversion:: nightly]
18
23
/// Implementation detail for stabby's version of dyn traits.
19
24
/// Any type that implements a trait `ITrait` must implement `IConstConstructor<VtITrait>` for `stabby::dyn!(Ptr<ITrait>)::from(value)` to work.
20
25
pub trait IConstConstructor < ' a , Source > : ' a + Copy + core:: marker:: Freeze {
21
26
/// The vtable.
22
- const VTABLE : & ' a Self ;
27
+ const VTABLE : Self ;
28
+ /// A reference to the vtable
29
+ const VTABLE_REF : & ' a Self = & Self :: VTABLE ;
30
+ /// Returns the reference to the vtable
31
+ fn vtable ( ) -> & ' a Self {
32
+ Self :: VTABLE_REF
33
+ }
23
34
}
24
- #[ rustversion:: not( nightly) ]
35
+
36
+ #[ rustversion:: before( 1.78 . 0 ) ]
25
37
/// Implementation detail for stabby's version of dyn traits.
26
38
/// Any type that implements a trait `ITrait` must implement `IConstConstructor<VtITrait>` for `stabby::dyn!(Ptr<ITrait>)::from(value)` to work.
27
39
pub trait IConstConstructor < ' a , Source > : ' a + Copy {
28
40
/// The vtable.
29
- const VTABLE : & ' a Self ;
41
+ const VTABLE : Self ;
42
+ /// A reference to the vtable
43
+ const VTABLE_REF : & ' a Self = & Self :: VTABLE ;
44
+ /// Returns the reference to the vtable
45
+ fn vtable ( ) -> & ' a Self {
46
+ Self :: VTABLE_REF
47
+ }
48
+ }
49
+
50
+ #[ cfg( feature = "libc" ) ]
51
+ #[ rustversion:: all( since( 1.78 . 0 ) , not( nightly) ) ]
52
+ static VTABLES : core:: sync:: atomic:: AtomicPtr <
53
+ crate :: alloc:: vec:: Vec < (
54
+ u64 ,
55
+ crate :: alloc:: AllocPtr < * const ( ) , crate :: alloc:: DefaultAllocator > ,
56
+ ) > ,
57
+ > = core:: sync:: atomic:: AtomicPtr :: new ( core:: ptr:: null_mut ( ) ) ;
58
+ #[ cfg( feature = "libc" ) ]
59
+ #[ rustversion:: all( since( 1.78 . 0 ) , not( nightly) ) ]
60
+ /// Implementation detail for stabby's version of dyn traits.
61
+ /// Any type that implements a trait `ITrait` must implement `IConstConstructor<VtITrait>` for `stabby::dyn!(Ptr<ITrait>)::from(value)` to work.
62
+ pub trait IConstConstructor < ' a , Source > : ' a + Copy + core:: hash:: Hash + core:: fmt:: Debug {
63
+ /// The vtable.
64
+ const VTABLE : Self ;
65
+ /// Returns the reference to the vtable
66
+ fn vtable ( ) -> & ' a Self {
67
+ use crate :: alloc:: { boxed:: Box , vec:: Vec , AllocPtr , DefaultAllocator } ;
68
+ let vtable = Self :: VTABLE ;
69
+ #[ allow( deprecated) ]
70
+ let hash = {
71
+ let mut hasher = core:: hash:: SipHasher :: new ( ) ;
72
+ vtable. hash ( & mut hasher) ;
73
+ hasher. finish ( )
74
+ } ;
75
+ fn insert_vtable ( hash : u64 , vtable : & [ * const ( ) ] ) -> AllocPtr < * const ( ) , DefaultAllocator > {
76
+ let mut search_start = 0 ;
77
+ let mut allocated_vt = None ;
78
+ let mut vtables = VTABLES . load ( core:: sync:: atomic:: Ordering :: SeqCst ) ;
79
+ loop {
80
+ let vts = match unsafe { vtables. as_ref ( ) } {
81
+ None => [ ] . as_slice ( ) ,
82
+ Some ( vts) => match vts[ search_start..]
83
+ . iter ( )
84
+ . find_map ( |e| ( e. 0 == hash) . then_some ( e. 1 ) )
85
+ {
86
+ Some ( vt) => return vt,
87
+ None => vts,
88
+ } ,
89
+ } ;
90
+ let vt = allocated_vt. unwrap_or_else ( || {
91
+ let mut ptr =
92
+ AllocPtr :: alloc_array ( & mut DefaultAllocator :: new ( ) , vtable. len ( ) ) . unwrap ( ) ;
93
+ unsafe {
94
+ core:: ptr:: copy_nonoverlapping ( vtable. as_ptr ( ) , ptr. as_mut ( ) , vtable. len ( ) )
95
+ } ;
96
+ ptr
97
+ } ) ;
98
+ allocated_vt = Some ( vt) ;
99
+ let updated = VTABLES . load ( core:: sync:: atomic:: Ordering :: SeqCst ) ;
100
+ if !core:: ptr:: eq ( vtables, updated) {
101
+ vtables = updated;
102
+ continue ;
103
+ }
104
+ let mut vec = Vec :: with_capacity ( vts. len ( ) + 1 ) ;
105
+ vec. copy_extend ( vts) ;
106
+ vec. push ( ( hash, vt) ) ;
107
+ let mut vec = Box :: into_raw ( Box :: new ( vec) ) ;
108
+ match VTABLES . compare_exchange (
109
+ updated,
110
+ unsafe { vec. as_mut ( ) } ,
111
+ core:: sync:: atomic:: Ordering :: SeqCst ,
112
+ core:: sync:: atomic:: Ordering :: SeqCst ,
113
+ ) {
114
+ Ok ( updated) => {
115
+ if let Some ( updated) = NonNull :: new ( updated) {
116
+ unsafe {
117
+ Box :: from_raw ( AllocPtr {
118
+ ptr : updated,
119
+ marker : PhantomData :: < DefaultAllocator > ,
120
+ } )
121
+ } ;
122
+ }
123
+ return vt;
124
+ }
125
+ Err ( new_vtables) => {
126
+ search_start = vts. len ( ) ;
127
+ vtables = new_vtables;
128
+ unsafe { Box :: from_raw ( vec) } ;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ unsafe {
134
+ let vtable = core:: slice:: from_raw_parts (
135
+ ( & vtable as * const Self ) . cast ( ) ,
136
+ core:: mem:: size_of :: < Self > ( ) / core:: mem:: size_of :: < * const ( ) > ( ) ,
137
+ ) ;
138
+ let vt = insert_vtable ( hash, vtable) . cast ( ) . as_ref ( ) ;
139
+ debug_assert_eq ! (
140
+ core:: slice:: from_raw_parts(
141
+ ( vt as * const Self ) . cast:: <* const ( ) >( ) ,
142
+ core:: mem:: size_of:: <Self >( ) / core:: mem:: size_of:: <* const ( ) >( ) ,
143
+ ) ,
144
+ vtable
145
+ ) ;
146
+ vt
147
+ }
148
+ }
30
149
}
31
150
32
151
/// Implementation detail for stabby's version of dyn traits.
@@ -42,7 +161,7 @@ pub struct T<T>(T);
42
161
/// You should _always_ use `stabby::vtable!(Trait1 + Trait2 + ...)` to generate this type,
43
162
/// as this macro will ensure that traits are ordered consistently in the vtable.
44
163
#[ stabby:: stabby]
45
- #[ derive( Clone , Copy , PartialEq , Eq ) ]
164
+ #[ derive( Clone , Copy , PartialEq , Eq , Hash , Debug ) ]
46
165
pub struct VTable < Head , Tail = VtDrop > {
47
166
/// The rest of the vtable.
48
167
///
@@ -63,13 +182,13 @@ where
63
182
Head : IConstConstructor < ' a , T > ,
64
183
Tail : IConstConstructor < ' a , T > ,
65
184
{
66
- const VTABLE : & ' a VTable < Head , Tail > = & VTable {
67
- head : * Head :: VTABLE ,
68
- tail : * Tail :: VTABLE ,
185
+ const VTABLE : VTable < Head , Tail > = VTable {
186
+ head : Head :: VTABLE ,
187
+ tail : Tail :: VTABLE ,
69
188
} ;
70
189
}
71
190
impl < ' a , T > IConstConstructor < ' a , T > for ( ) {
72
- const VTABLE : & ' a ( ) = & ( ) ;
191
+ const VTABLE : ( ) = ( ) ;
73
192
}
74
193
impl < Head , Tail > TransitiveDeref < Head , H > for VTable < Head , Tail > {
75
194
fn tderef ( & self ) -> & Head {
@@ -122,11 +241,21 @@ impl<Head, Tail: HasSyncVt> HasSyncVt for VTable<Head, Tail> {}
122
241
// DROP
123
242
/// The vtable to drop a value in place
124
243
#[ stabby:: stabby]
125
- #[ derive( Clone , Copy ) ]
244
+ #[ derive( Clone , Copy , Eq ) ]
126
245
pub struct VtDrop {
127
246
/// The [`Drop::drop`] function, shimmed with the C calling convention.
128
247
pub drop : crate :: StableLike < unsafe extern "C" fn ( & mut ( ) ) , core:: num:: NonZeroUsize > ,
129
248
}
249
+ impl core:: fmt:: Debug for VtDrop {
250
+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
251
+ write ! ( f, "VtDrop({:p})" , unsafe { self . drop. as_ref_unchecked( ) } )
252
+ }
253
+ }
254
+ impl Hash for VtDrop {
255
+ fn hash < H : core:: hash:: Hasher > ( & self , state : & mut H ) {
256
+ self . drop . hash ( state)
257
+ }
258
+ }
130
259
impl PartialEq for VtDrop {
131
260
fn eq ( & self , other : & Self ) -> bool {
132
261
core:: ptr:: eq (
@@ -136,7 +265,7 @@ impl PartialEq for VtDrop {
136
265
}
137
266
}
138
267
impl < ' a , T > IConstConstructor < ' a , T > for VtDrop {
139
- const VTABLE : & ' a VtDrop = & VtDrop {
268
+ const VTABLE : VtDrop = VtDrop {
140
269
drop : unsafe {
141
270
core:: mem:: transmute ( {
142
271
unsafe extern "C" fn drop < T > ( this : & mut T ) {
@@ -150,7 +279,7 @@ impl<'a, T> IConstConstructor<'a, T> for VtDrop {
150
279
151
280
/// A marker for vtables for types that are `Send`
152
281
#[ stabby:: stabby]
153
- #[ derive( Clone , Copy , PartialEq , Eq ) ]
282
+ #[ derive( Clone , Copy , PartialEq , Eq , Hash , Debug ) ]
154
283
pub struct VtSend < T > ( pub T ) ;
155
284
impl CompoundVt for dyn Send {
156
285
type Vt < T > = VtSend < T > ;
@@ -166,18 +295,18 @@ impl<Head, Tail> From<crate::vtable::VtSend<VTable<Head, Tail>>> for VTable<Head
166
295
}
167
296
}
168
297
impl < ' a , T : Send , Vt : IConstConstructor < ' a , T > > IConstConstructor < ' a , T > for VtSend < Vt > {
169
- const VTABLE : & ' a VtSend < Vt > = & VtSend ( * Vt :: VTABLE ) ;
298
+ const VTABLE : VtSend < Vt > = VtSend ( Vt :: VTABLE ) ;
170
299
}
171
300
172
301
/// A marker for vtables for types that are `Sync`
173
302
#[ stabby:: stabby]
174
- #[ derive( Clone , Copy , PartialEq , Eq ) ]
303
+ #[ derive( Clone , Copy , PartialEq , Eq , Hash , Debug ) ]
175
304
pub struct VtSync < T > ( pub T ) ;
176
305
impl CompoundVt for dyn Sync {
177
306
type Vt < T > = VtSync < T > ;
178
307
}
179
308
impl < ' a , T : Sync , Vt : IConstConstructor < ' a , T > > IConstConstructor < ' a , T > for VtSync < Vt > {
180
- const VTABLE : & ' a VtSync < Vt > = & VtSync ( * Vt :: VTABLE ) ;
309
+ const VTABLE : VtSync < Vt > = VtSync ( Vt :: VTABLE ) ;
181
310
}
182
311
impl < Tail : TransitiveDeref < Vt , N > , Vt , N > TransitiveDeref < Vt , N > for VtSync < Tail > {
183
312
fn tderef ( & self ) -> & Vt {
0 commit comments