@@ -3,7 +3,7 @@ use crate::common::{
33 hash:: { PyHash , PyUHash } ,
44 lock:: PyMutex ,
55} ;
6- use crate :: object:: { Traverse , TraverseFn } ;
6+ use crate :: object:: { MaybeTraverse , Traverse , TraverseFn } ;
77use crate :: {
88 AsObject , Context , Py , PyObject , PyObjectRef , PyPayload , PyRef , PyResult , TryFromObject ,
99 atomic_func,
@@ -500,53 +500,81 @@ pub(crate) fn init(context: &Context) {
500500 PyTupleIterator :: extend_class ( context, context. types . tuple_iterator_type ) ;
501501}
502502
503- pub struct PyTupleTyped < T : TransmuteFromObject > {
503+ pub struct PyTupleTyped < R > {
504504 // SAFETY INVARIANT: T must be repr(transparent) over PyObjectRef, and the
505505 // elements must be logically valid when transmuted to T
506- tuple : PyTupleRef ,
507- _marker : PhantomData < Vec < T > > ,
506+ tuple : PyTuple ,
507+ _marker : PhantomData < R > ,
508508}
509509
510- unsafe impl < T > Traverse for PyTupleTyped < T >
510+ impl < T : PyPayload > PyPayload for PyTupleTyped < PyRef < T > >
511511where
512- T : TransmuteFromObject + Traverse ,
512+ PyRef < T > : TransmuteFromObject ,
513+ {
514+ #[ inline]
515+ fn payload_type_id ( ) -> std:: any:: TypeId {
516+ std:: any:: TypeId :: of :: < PyTuple > ( )
517+ }
518+ #[ inline]
519+ fn class ( ctx : & Context ) -> & ' static Py < PyType > {
520+ ctx. types . tuple_type
521+ }
522+ }
523+
524+ unsafe impl < R > Traverse for PyTupleTyped < R >
525+ where
526+ R : TransmuteFromObject ,
513527{
514528 fn traverse ( & self , tracer_fn : & mut TraverseFn < ' _ > ) {
515529 self . tuple . traverse ( tracer_fn) ;
516530 }
517531}
518532
519- impl < T : TransmuteFromObject > TryFromObject for PyTupleTyped < T > {
520- fn try_from_object ( vm : & VirtualMachine , obj : PyObjectRef ) -> PyResult < Self > {
521- let tuple = PyTupleRef :: try_from_object ( vm , obj ) ? ;
522- for elem in & * tuple {
523- T :: check ( vm , elem ) ?
524- }
525- // SAFETY: the contract of TransmuteFromObject upholds the variant on `tuple`
526- Ok ( Self {
527- tuple ,
528- _marker : PhantomData ,
529- } )
533+ impl < R : TransmuteFromObject + Traverse > MaybeTraverse for PyTupleTyped < R > {
534+ const IS_TRACE : bool = true ;
535+ fn try_traverse ( & self , tracer_fn : & mut TraverseFn < ' _ > ) {
536+ self . traverse ( tracer_fn ) ;
537+ }
538+ }
539+
540+ impl < T : PyPayload > PyRef < PyTupleTyped < PyRef < T > > > {
541+ pub fn into_untyped ( self ) -> PyRef < PyTuple > {
542+ // SAFETY: PyTupleTyped is transparent over PyTuple
543+ unsafe { std :: mem :: transmute ( self ) }
530544 }
531545}
532546
533- impl < T : TransmuteFromObject > AsRef < [ T ] > for PyTupleTyped < T > {
534- fn as_ref ( & self ) -> & [ T ] {
547+ impl < T : PyPayload > Py < PyTupleTyped < PyRef < T > > > {
548+ pub fn as_untyped ( & self ) -> & Py < PyTuple > {
549+ // SAFETY: PyTupleTyped is transparent over PyTuple
550+ unsafe { std:: mem:: transmute ( self ) }
551+ }
552+ }
553+
554+ impl < T : PyPayload > AsRef < [ PyRef < T > ] > for PyTupleTyped < PyRef < T > > {
555+ fn as_ref ( & self ) -> & [ PyRef < T > ] {
535556 self . as_slice ( )
536557 }
537558}
538559
539- impl < T : TransmuteFromObject > PyTupleTyped < T > {
540- pub fn empty ( vm : & VirtualMachine ) -> Self {
541- Self {
542- tuple : vm. ctx . empty_tuple . clone ( ) ,
543- _marker : PhantomData ,
560+ impl < T : PyPayload > PyTupleTyped < PyRef < T > > {
561+ /// Returns a reference to the empty tuple
562+ pub fn empty ( ctx : & Context ) -> & Py < Self >
563+ where
564+ T : fmt:: Debug + Send + Sync + ' static ,
565+ {
566+ // SAFETY: empty_tuple is always a valid tuple with 0 elements,
567+ // and 0 elements trivially satisfy any T::check
568+ unsafe {
569+ ctx. empty_tuple
570+ . as_object ( )
571+ . downcast_unchecked_ref :: < PyTupleTyped < PyRef < T > > > ( )
544572 }
545573 }
546574
547575 #[ inline]
548- pub fn as_slice ( & self ) -> & [ T ] {
549- unsafe { & * ( self . tuple . as_slice ( ) as * const [ PyObjectRef ] as * const [ T ] ) }
576+ pub fn as_slice ( & self ) -> & [ PyRef < T > ] {
577+ unsafe { & * ( self . tuple . as_slice ( ) as * const [ PyObjectRef ] as * const [ PyRef < T > ] ) }
550578 }
551579
552580 #[ inline]
@@ -560,32 +588,16 @@ impl<T: TransmuteFromObject> PyTupleTyped<T> {
560588 }
561589}
562590
563- impl < T : TransmuteFromObject > Clone for PyTupleTyped < T > {
564- fn clone ( & self ) -> Self {
565- Self {
566- tuple : self . tuple . clone ( ) ,
567- _marker : PhantomData ,
568- }
569- }
570- }
571-
572- impl < T : TransmuteFromObject + fmt:: Debug > fmt:: Debug for PyTupleTyped < T > {
591+ impl < R : fmt:: Debug > fmt:: Debug for PyTupleTyped < R > {
573592 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
574- self . as_slice ( ) . fmt ( f)
575- }
576- }
577-
578- impl < T : TransmuteFromObject > From < PyTupleTyped < T > > for PyTupleRef {
579- #[ inline]
580- fn from ( tup : PyTupleTyped < T > ) -> Self {
581- tup. tuple
593+ self . tuple . as_slice ( ) . fmt ( f)
582594 }
583595}
584596
585- impl < T : TransmuteFromObject > ToPyObject for PyTupleTyped < T > {
597+ impl < T : PyPayload > From < PyRef < PyTupleTyped < PyRef < T > > > > for PyTupleRef {
586598 #[ inline]
587- fn to_pyobject ( self , _vm : & VirtualMachine ) -> PyObjectRef {
588- self . tuple . into ( )
599+ fn from ( tup : PyRef < PyTupleTyped < PyRef < T > > > ) -> Self {
600+ tup . into_untyped ( )
589601 }
590602}
591603
0 commit comments