@@ -47,7 +47,73 @@ use core::{
47
47
/// The current implementation uses a `struct Erased` with size 0 and align 1.
48
48
/// If you want to offset the pointer, make sure to cast to a `u8` or other known type pointer first.
49
49
/// When `Erased` becomes an extern type, it will properly have unknown size and align.
50
- pub type ErasedPtr = ptr:: NonNull < Erased > ;
50
+ #[ derive( Debug , Copy , Clone , PartialEq ) ]
51
+ #[ repr( transparent) ]
52
+ pub struct ErasedPtr ( ptr:: NonNull < Erased > ) ;
53
+
54
+ impl ErasedPtr {
55
+ /// Gets the raw pointer as '*const ()' unit type. This keeps the internal representation
56
+ /// hidden and is not very useful but for diagnostics like logging memory addresses and
57
+ /// comparing pointers for partial equality.
58
+ pub fn as_unit_ptr ( & self ) -> * const ( ) {
59
+ self . 0 . as_ptr ( ) as * const _
60
+ }
61
+
62
+ /// Run a closure on a borrow of the real pointer. Unlike the `Thin<T>` wrapper this does
63
+ /// not carry the original type around. Thus it is required to specify the original impl
64
+ /// type as closure parameter.
65
+ ///
66
+ /// ```
67
+ /// # use {erasable::*, std::rc::Rc};
68
+ /// let rc: Rc<i32> = Rc::new(123);
69
+ ///
70
+ /// let erased: ErasedPtr = ErasablePtr::erase(rc);
71
+ ///
72
+ /// let cloned = unsafe {
73
+ /// // must specify a reference to the original type here
74
+ /// erased.with(|rc: &Rc<i32>| rc.clone())
75
+ /// };
76
+ ///
77
+ /// assert_eq!(*cloned, 123);
78
+ /// # unsafe {<Rc<i32> as ErasablePtr>::unerase(erased)}; // drop it
79
+ /// ```
80
+ ///
81
+ /// # Safety
82
+ ///
83
+ /// * The erased pointer must have been created by `erase`.
84
+ /// * The specified impl type must be the original type.
85
+ pub unsafe fn with < E , F , T > ( & self , f : F ) -> T
86
+ where
87
+ E : ErasablePtr ,
88
+ F : FnOnce ( & E ) -> T ,
89
+ {
90
+ f ( & ManuallyDrop :: new ( <E as ErasablePtr >:: unerase ( * self ) ) )
91
+ }
92
+
93
+ /// Run a closure on a mutable borrow of the real pointer. Unlike the `Thin<T>` wrapper
94
+ /// this does not carry the original type around. Thus it is required to specify the
95
+ /// original impl type as closure parameter.
96
+ ///
97
+ /// # Safety
98
+ ///
99
+ /// * The erased pointer must have been created by `erase`.
100
+ /// * The specified impl type must be the original type.
101
+ pub unsafe fn with_mut < E , F , T > ( & mut self , f : F ) -> T
102
+ where
103
+ E : ErasablePtr ,
104
+ F : FnOnce ( & mut E ) -> T ,
105
+ {
106
+ // SAFETY: guard is required to write potentially changed pointer value, even on unwind
107
+ let mut this = scopeguard:: guard (
108
+ ManuallyDrop :: new ( <E as ErasablePtr >:: unerase ( * self ) ) ,
109
+ |unerased| {
110
+ ptr:: write ( self , ErasablePtr :: erase ( ManuallyDrop :: into_inner ( unerased) ) ) ;
111
+ } ,
112
+ ) ;
113
+
114
+ f ( & mut this)
115
+ }
116
+ }
51
117
52
118
#[ cfg( not( has_extern_type) ) ]
53
119
pub ( crate ) use priv_in_pub:: Erased ;
@@ -185,60 +251,6 @@ pub unsafe trait ErasablePtr {
185
251
///
186
252
/// The erased pointer must have been created by `erase`.
187
253
unsafe fn unerase ( this : ErasedPtr ) -> Self ;
188
-
189
- /// Run a closure on a borrow of the real pointer. Unlike the `Thin<T>` wrapper this does
190
- /// not carry the original type around. Thus it is required to specify the original impl
191
- /// type when calling this function.
192
- ///
193
- /// ```
194
- /// # use {erasable::*, std::rc::Rc};
195
- /// let rc: Rc<i32> = Rc::new(123);
196
- ///
197
- /// let erased: ErasedPtr = ErasablePtr::erase(rc);
198
- ///
199
- /// let cloned = unsafe {
200
- /// <Rc<i32> as ErasablePtr>::with(&erased, |rc| rc.clone())
201
- /// };
202
- ///
203
- /// assert_eq!(*cloned, 123);
204
- /// # unsafe {<Rc<i32> as ErasablePtr>::unerase(erased)}; // drop it
205
- /// ```
206
- ///
207
- /// The main purpose of this function is to be able implement recursive types that would
208
- /// be otherwise not representable in rust.
209
- ///
210
- /// # Safety
211
- ///
212
- /// * The erased pointer must have been created by `erase`.
213
- /// * The specified impl type must be the original type.
214
- unsafe fn with < F , T > ( this : & ErasedPtr , f : F ) -> T
215
- where
216
- Self : Sized ,
217
- F : FnOnce ( & Self ) -> T ,
218
- {
219
- f ( & ManuallyDrop :: new ( Self :: unerase ( * this) ) )
220
- }
221
-
222
- /// Run a closure on a mutable borrow of the real pointer. Unlike the `Thin<T>` wrapper
223
- /// this does not carry the original type around. Thus it is required to specify the
224
- /// original impl type when calling this function.
225
- ///
226
- /// # Safety
227
- ///
228
- /// * The erased pointer must have been created by `erase`.
229
- /// * The specified impl type must be the original type.
230
- unsafe fn with_mut < F , T > ( this : & mut ErasedPtr , f : F ) -> T
231
- where
232
- Self : Sized ,
233
- F : FnOnce ( & mut Self ) -> T ,
234
- {
235
- // SAFETY: guard is required to write potentially changed pointer value, even on unwind
236
- let mut that = scopeguard:: guard ( ManuallyDrop :: new ( Self :: unerase ( * this) ) , |unerased| {
237
- ptr:: write ( this, ErasablePtr :: erase ( ManuallyDrop :: into_inner ( unerased) ) ) ;
238
- } ) ;
239
-
240
- f ( & mut that)
241
- }
242
254
}
243
255
244
256
/// A pointee type that supports type-erased pointers (thin pointers).
@@ -327,7 +339,7 @@ pub unsafe trait Erasable {
327
339
/// Erase a pointer.
328
340
#[ inline( always) ]
329
341
pub fn erase < T : ?Sized > ( ptr : ptr:: NonNull < T > ) -> ErasedPtr {
330
- unsafe { ptr:: NonNull :: new_unchecked ( ptr. as_ptr ( ) as * mut Erased ) }
342
+ unsafe { ErasedPtr ( ptr:: NonNull :: new_unchecked ( ptr. as_ptr ( ) as * mut Erased ) ) }
331
343
}
332
344
333
345
/// Wrapper struct to create thin pointer types.
@@ -670,7 +682,7 @@ where
670
682
unsafe impl < T : Sized > Erasable for T {
671
683
unsafe fn unerase ( this : ErasedPtr ) -> ptr:: NonNull < T > {
672
684
// SAFETY: must not read the pointer for the safety of the impl directly below.
673
- this. cast ( )
685
+ this. 0 . cast ( )
674
686
}
675
687
676
688
const ACK_1_1_0 : bool = true ;
0 commit comments