@@ -463,6 +463,64 @@ impl PyAtomicRef<Option<PyObject>> {
463463 }
464464}
465465
466+ /// Atomic borrowed (non-ref-counted) optional reference to a Python object.
467+ /// Unlike `PyAtomicRef`, this does NOT own the reference.
468+ /// The pointed-to object must outlive this reference.
469+ pub struct PyAtomicBorrow {
470+ inner : PyAtomic < * mut u8 > ,
471+ }
472+
473+ // Safety: Access patterns ensure the pointed-to object outlives this reference.
474+ // The owner (generator/coroutine) clears this in its Drop impl before deallocation.
475+ unsafe impl Send for PyAtomicBorrow { }
476+ unsafe impl Sync for PyAtomicBorrow { }
477+
478+ impl PyAtomicBorrow {
479+ pub fn new ( ) -> Self {
480+ Self {
481+ inner : Radium :: new ( null_mut ( ) ) ,
482+ }
483+ }
484+
485+ pub fn store ( & self , obj : & PyObject ) {
486+ let ptr = obj as * const PyObject as * mut u8 ;
487+ Radium :: store ( & self . inner , ptr, Ordering :: Relaxed ) ;
488+ }
489+
490+ pub fn load ( & self ) -> Option < & PyObject > {
491+ let ptr = Radium :: load ( & self . inner , Ordering :: Relaxed ) ;
492+ if ptr. is_null ( ) {
493+ None
494+ } else {
495+ Some ( unsafe { & * ( ptr as * const PyObject ) } )
496+ }
497+ }
498+
499+ pub fn clear ( & self ) {
500+ Radium :: store ( & self . inner , null_mut ( ) , Ordering :: Relaxed ) ;
501+ }
502+
503+ pub fn to_owned ( & self ) -> Option < PyObjectRef > {
504+ self . load ( ) . map ( |obj| obj. to_owned ( ) )
505+ }
506+ }
507+
508+ impl Default for PyAtomicBorrow {
509+ fn default ( ) -> Self {
510+ Self :: new ( )
511+ }
512+ }
513+
514+ impl fmt:: Debug for PyAtomicBorrow {
515+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
516+ write ! (
517+ f,
518+ "PyAtomicBorrow({:?})" ,
519+ Radium :: load( & self . inner, Ordering :: Relaxed )
520+ )
521+ }
522+ }
523+
466524pub trait AsObject
467525where
468526 Self : Borrow < PyObject > ,
0 commit comments