@@ -11,7 +11,7 @@ use crate::{
11
11
convert:: { IntoPyException , ToPyObject , ToPyResult , TryFromObject } ,
12
12
VirtualMachine ,
13
13
} ;
14
- use std:: { borrow:: Borrow , fmt, ops:: Deref } ;
14
+ use std:: { borrow:: Borrow , fmt, marker :: PhantomData , ops:: Deref , ptr :: null_mut } ;
15
15
16
16
/* Python objects and references.
17
17
@@ -214,27 +214,43 @@ impl<T: PyPayload> ToPyObject for PyRefExact<T> {
214
214
}
215
215
}
216
216
217
- pub struct PyAtomicRef < T : PyObjectPayload > ( PyAtomic < * mut Py < T > > ) ;
217
+ pub struct PyAtomicRef < T > {
218
+ inner : PyAtomic < * mut u8 > ,
219
+ _phantom : PhantomData < T > ,
220
+ }
218
221
219
222
cfg_if:: cfg_if! {
220
223
if #[ cfg( feature = "threading" ) ] {
221
224
unsafe impl <T : Send + PyObjectPayload > Send for PyAtomicRef <T > { }
222
225
unsafe impl <T : Sync + PyObjectPayload > Sync for PyAtomicRef <T > { }
226
+ unsafe impl <T : Send + PyObjectPayload > Send for PyAtomicRef <Option <T >> { }
227
+ unsafe impl <T : Sync + PyObjectPayload > Sync for PyAtomicRef <Option <T >> { }
228
+ unsafe impl Send for PyAtomicRef <PyObject > { }
229
+ unsafe impl Sync for PyAtomicRef <PyObject > { }
223
230
}
224
231
}
225
232
226
233
impl < T : PyObjectPayload > From < PyRef < T > > for PyAtomicRef < T > {
227
234
fn from ( pyref : PyRef < T > ) -> Self {
228
235
let py = PyRef :: leak ( pyref) ;
229
- Self ( Radium :: new ( py as * const _ as * mut _ ) )
236
+ Self {
237
+ inner : Radium :: new ( py as * const _ as * mut _ ) ,
238
+ _phantom : Default :: default ( ) ,
239
+ }
230
240
}
231
241
}
232
242
233
243
impl < T : PyObjectPayload > Deref for PyAtomicRef < T > {
234
244
type Target = Py < T > ;
235
245
236
246
fn deref ( & self ) -> & Self :: Target {
237
- unsafe { & * self . 0 . load ( Ordering :: Relaxed ) }
247
+ unsafe {
248
+ self . inner
249
+ . load ( Ordering :: Relaxed )
250
+ . cast :: < Py < T > > ( )
251
+ . as_ref ( )
252
+ . unwrap_unchecked ( )
253
+ }
238
254
}
239
255
}
240
256
@@ -244,9 +260,9 @@ impl<T: PyObjectPayload> PyAtomicRef<T> {
244
260
/// until no more reference can be used via PyAtomicRef::deref()
245
261
#[ must_use]
246
262
pub unsafe fn swap ( & self , pyref : PyRef < T > ) -> PyRef < T > {
247
- let py = PyRef :: leak ( pyref) ;
248
- let old = Radium :: swap ( & self . 0 , py as * const _ as * mut _ , Ordering :: AcqRel ) ;
249
- PyRef :: from_raw ( old)
263
+ let py = PyRef :: leak ( pyref) as * const Py < T > as * mut _ ;
264
+ let old = Radium :: swap ( & self . inner , py, Ordering :: AcqRel ) ;
265
+ PyRef :: from_raw ( old. cast ( ) )
250
266
}
251
267
252
268
pub fn swap_to_temporary_refs ( & self , pyref : PyRef < T > , vm : & VirtualMachine ) {
@@ -257,6 +273,88 @@ impl<T: PyObjectPayload> PyAtomicRef<T> {
257
273
}
258
274
}
259
275
276
+ impl < T : PyObjectPayload > From < Option < PyRef < T > > > for PyAtomicRef < Option < T > > {
277
+ fn from ( opt_ref : Option < PyRef < T > > ) -> Self {
278
+ let val = opt_ref
279
+ . map ( |x| PyRef :: leak ( x) as * const Py < T > as * mut _ )
280
+ . unwrap_or ( null_mut ( ) ) ;
281
+ Self {
282
+ inner : Radium :: new ( val) ,
283
+ _phantom : Default :: default ( ) ,
284
+ }
285
+ }
286
+ }
287
+
288
+ impl < T : PyObjectPayload > PyAtomicRef < Option < T > > {
289
+ pub fn deref ( & self ) -> Option < & Py < T > > {
290
+ unsafe { self . inner . load ( Ordering :: Relaxed ) . cast :: < Py < T > > ( ) . as_ref ( ) }
291
+ }
292
+
293
+ /// # Safety
294
+ /// The caller is responsible to keep the returned PyRef alive
295
+ /// until no more reference can be used via PyAtomicRef::deref()
296
+ #[ must_use]
297
+ pub unsafe fn swap ( & self , opt_ref : Option < PyRef < T > > ) -> Option < PyRef < T > > {
298
+ let val = opt_ref
299
+ . map ( |x| PyRef :: leak ( x) as * const Py < T > as * mut _ )
300
+ . unwrap_or ( null_mut ( ) ) ;
301
+ let old = Radium :: swap ( & self . inner , val, Ordering :: AcqRel ) ;
302
+ unsafe { old. cast :: < Py < T > > ( ) . as_ref ( ) . map ( |x| PyRef :: from_raw ( x) ) }
303
+ }
304
+
305
+ pub fn swap_to_temporary_refs ( & self , opt_ref : Option < PyRef < T > > , vm : & VirtualMachine ) {
306
+ let Some ( old) = ( unsafe { self . swap ( opt_ref) } ) else {
307
+ return ;
308
+ } ;
309
+ if let Some ( frame) = vm. current_frame ( ) {
310
+ frame. temporary_refs . lock ( ) . push ( old. into ( ) ) ;
311
+ }
312
+ }
313
+ }
314
+
315
+ impl From < PyObjectRef > for PyAtomicRef < PyObject > {
316
+ fn from ( obj : PyObjectRef ) -> Self {
317
+ let obj = obj. into_raw ( ) ;
318
+ Self {
319
+ inner : Radium :: new ( obj as * mut _ ) ,
320
+ _phantom : Default :: default ( ) ,
321
+ }
322
+ }
323
+ }
324
+
325
+ impl Deref for PyAtomicRef < PyObject > {
326
+ type Target = PyObject ;
327
+
328
+ fn deref ( & self ) -> & Self :: Target {
329
+ unsafe {
330
+ self . inner
331
+ . load ( Ordering :: Relaxed )
332
+ . cast :: < PyObject > ( )
333
+ . as_ref ( )
334
+ . unwrap_unchecked ( )
335
+ }
336
+ }
337
+ }
338
+
339
+ impl PyAtomicRef < PyObject > {
340
+ /// # Safety
341
+ /// The caller is responsible to keep the returned PyRef alive
342
+ /// until no more reference can be used via PyAtomicRef::deref()
343
+ #[ must_use]
344
+ pub unsafe fn swap ( & self , obj : PyObjectRef ) -> PyObjectRef {
345
+ let obj = obj. into_raw ( ) as * mut _ ;
346
+ let old = Radium :: swap ( & self . inner , obj, Ordering :: AcqRel ) ;
347
+ PyObjectRef :: from_raw ( old. cast ( ) )
348
+ }
349
+
350
+ pub fn swap_to_temporary_refs ( & self , obj : PyObjectRef , vm : & VirtualMachine ) {
351
+ let old = unsafe { self . swap ( obj) } ;
352
+ if let Some ( frame) = vm. current_frame ( ) {
353
+ frame. temporary_refs . lock ( ) . push ( old) ;
354
+ }
355
+ }
356
+ }
357
+
260
358
pub trait AsObject
261
359
where
262
360
Self : Borrow < PyObject > ,
0 commit comments