18
18
use crate :: { bindings, Result } ;
19
19
use alloc:: boxed:: Box ;
20
20
use core:: {
21
+ alloc:: Layout ,
21
22
cell:: UnsafeCell ,
22
23
convert:: AsRef ,
23
24
marker:: { PhantomData , Unsize } ,
24
25
mem:: ManuallyDrop ,
25
26
ops:: Deref ,
26
27
pin:: Pin ,
27
- ptr:: NonNull ,
28
+ ptr:: { self , NonNull } ,
28
29
} ;
29
30
30
31
extern "C" {
@@ -47,6 +48,7 @@ pub struct Ref<T: ?Sized> {
47
48
_p : PhantomData < RefInner < T > > ,
48
49
}
49
50
51
+ #[ repr( C ) ]
50
52
struct RefInner < T : ?Sized > {
51
53
refcount : UnsafeCell < bindings:: refcount_t > ,
52
54
data : T ,
@@ -97,10 +99,9 @@ impl<T> Ref<T> {
97
99
// pinned, and in `drop`. Both are compatible with the pin requirements.
98
100
init ( pinned) ;
99
101
100
- Ok ( Ref {
101
- ptr : NonNull :: from ( Box :: leak ( inner) ) ,
102
- _p : PhantomData ,
103
- } )
102
+ // SAFETY: We just created `inner` with a reference count of 1 and we're leaking it. So the
103
+ // new `Ref` object owns the reference.
104
+ Ok ( unsafe { Self :: from_inner ( NonNull :: from ( Box :: leak ( inner) ) ) } )
104
105
}
105
106
106
107
/// Deconstructs a [`Ref`] object into a `usize`.
@@ -134,24 +135,73 @@ impl<T> Ref<T> {
134
135
/// `encoded` must have been returned by a previous call to [`Ref::into_usize`]. Additionally,
135
136
/// it can only be called once for each previous call to [``Ref::into_usize`].
136
137
pub unsafe fn from_usize ( encoded : usize ) -> Self {
138
+ // SAFETY: By the safety invariants we know that `encoded` came from `Ref::into_usize`, so
139
+ // the reference count held then will be owned by the new `Ref` object.
140
+ unsafe { Self :: from_inner ( NonNull :: new ( encoded as _ ) . unwrap ( ) ) }
141
+ }
142
+ }
143
+
144
+ impl < T : ?Sized > Ref < T > {
145
+ /// Constructs a new [`Ref`] from an existing [`RefInner`].
146
+ ///
147
+ /// # Safety
148
+ ///
149
+ /// The caller must ensure that `inner` points to a valid location and has a non-zero reference
150
+ /// count, one of which will be owned by the new [`Ref`] instance.
151
+ unsafe fn from_inner ( inner : NonNull < RefInner < T > > ) -> Self {
152
+ // INVARIANT: By the safety requirements, the invariants hold.
137
153
Ref {
138
- ptr : NonNull :: new ( encoded as _ ) . unwrap ( ) ,
154
+ ptr : inner ,
139
155
_p : PhantomData ,
140
156
}
141
157
}
142
- }
143
158
144
- impl < T : ?Sized > Ref < T > {
145
159
/// Determines if two reference-counted pointers point to the same underlying instance of `T`.
146
160
pub fn ptr_eq ( a : & Self , b : & Self ) -> bool {
147
- core :: ptr:: eq ( a. ptr . as_ptr ( ) , b. ptr . as_ptr ( ) )
161
+ ptr:: eq ( a. ptr . as_ptr ( ) , b. ptr . as_ptr ( ) )
148
162
}
149
163
150
164
/// Returns a pinned version of a given `Ref` instance.
151
165
pub fn pinned ( obj : Self ) -> Pin < Self > {
152
166
// SAFETY: The type invariants guarantee that the value is pinned.
153
167
unsafe { Pin :: new_unchecked ( obj) }
154
168
}
169
+
170
+ /// Deconstructs a [`Ref`] object into a raw pointer.
171
+ ///
172
+ /// It can be reconstructed once via [`Ref::from_raw`].
173
+ pub fn into_raw ( obj : Self ) -> * const T {
174
+ let ret = & * obj as * const T ;
175
+ core:: mem:: forget ( obj) ;
176
+ ret
177
+ }
178
+
179
+ /// Recreates a [`Ref`] instance previously deconstructed via [`Ref::into_raw`].
180
+ ///
181
+ /// This code relies on the `repr(C)` layout of structs as described in
182
+ /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.
183
+ ///
184
+ /// # Safety
185
+ ///
186
+ /// `ptr` must have been returned by a previous call to [`Ref::into_raw`]. Additionally, it
187
+ /// can only be called once for each previous call to [``Ref::into_raw`].
188
+ pub unsafe fn from_raw ( ptr : * const T ) -> Self {
189
+ // SAFETY: The safety requirement ensures that the pointer is valid.
190
+ let align = core:: mem:: align_of_val ( unsafe { & * ptr } ) ;
191
+ let offset = Layout :: new :: < RefInner < ( ) > > ( )
192
+ . align_to ( align)
193
+ . unwrap ( )
194
+ . pad_to_align ( )
195
+ . size ( ) ;
196
+ // SAFETY: The pointer is in bounds because by the safety requirements `ptr` came from
197
+ // `Ref::into_raw`, so it is a pointer `offset` bytes from the beginning of the allocation.
198
+ let data = unsafe { ( ptr as * const u8 ) . sub ( offset) } ;
199
+ let metadata = ptr:: metadata ( ptr as * const RefInner < T > ) ;
200
+ let ptr = ptr:: from_raw_parts_mut ( data as _ , metadata) ;
201
+ // SAFETY: By the safety requirements we know that `ptr` came from `Ref::into_raw`, so the
202
+ // reference count held then will be owned by the new `Ref` object.
203
+ unsafe { Self :: from_inner ( NonNull :: new ( ptr) . unwrap ( ) ) }
204
+ }
155
205
}
156
206
157
207
impl < T : ?Sized > Deref for Ref < T > {
0 commit comments