@@ -3,7 +3,6 @@ use crate::common::{
33 hash:: { PyHash , PyUHash } ,
44 lock:: PyMutex ,
55} ;
6- use crate :: object:: { MaybeTraverse , Traverse , TraverseFn } ;
76use crate :: {
87 AsObject , Context , Py , PyObject , PyObjectRef , PyPayload , PyRef , PyResult , TryFromObject ,
98 atomic_func,
@@ -22,14 +21,14 @@ use crate::{
2221 utils:: collection_repr,
2322 vm:: VirtualMachine ,
2423} ;
25- use std:: { fmt, marker :: PhantomData , sync:: LazyLock } ;
24+ use std:: { fmt, sync:: LazyLock } ;
2625
2726#[ pyclass( module = false , name = "tuple" , traverse) ]
28- pub struct PyTuple {
29- elements : Box < [ PyObjectRef ] > ,
27+ pub struct PyTuple < R = PyObjectRef > {
28+ elements : Box < [ R ] > ,
3029}
3130
32- impl fmt:: Debug for PyTuple {
31+ impl < R > fmt:: Debug for PyTuple < R > {
3332 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3433 // TODO: implement more informational, non-recursive Debug formatter
3534 f. write_str ( "tuple" )
@@ -140,39 +139,60 @@ impl Constructor for PyTuple {
140139 }
141140}
142141
143- impl AsRef < [ PyObjectRef ] > for PyTuple {
144- fn as_ref ( & self ) -> & [ PyObjectRef ] {
145- self . as_slice ( )
142+ impl < R > AsRef < [ R ] > for PyTuple < R > {
143+ fn as_ref ( & self ) -> & [ R ] {
144+ & self . elements
146145 }
147146}
148147
149- impl std:: ops:: Deref for PyTuple {
150- type Target = [ PyObjectRef ] ;
148+ impl < R > std:: ops:: Deref for PyTuple < R > {
149+ type Target = [ R ] ;
151150
152- fn deref ( & self ) -> & [ PyObjectRef ] {
153- self . as_slice ( )
151+ fn deref ( & self ) -> & [ R ] {
152+ & self . elements
154153 }
155154}
156155
157- impl < ' a > std:: iter:: IntoIterator for & ' a PyTuple {
158- type Item = & ' a PyObjectRef ;
159- type IntoIter = std:: slice:: Iter < ' a , PyObjectRef > ;
156+ impl < ' a , R > std:: iter:: IntoIterator for & ' a PyTuple < R > {
157+ type Item = & ' a R ;
158+ type IntoIter = std:: slice:: Iter < ' a , R > ;
160159
161160 fn into_iter ( self ) -> Self :: IntoIter {
162161 self . iter ( )
163162 }
164163}
165164
166- impl < ' a > std:: iter:: IntoIterator for & ' a Py < PyTuple > {
167- type Item = & ' a PyObjectRef ;
168- type IntoIter = std:: slice:: Iter < ' a , PyObjectRef > ;
165+ impl < ' a , R > std:: iter:: IntoIterator for & ' a Py < PyTuple < R > > {
166+ type Item = & ' a R ;
167+ type IntoIter = std:: slice:: Iter < ' a , R > ;
169168
170169 fn into_iter ( self ) -> Self :: IntoIter {
171170 self . iter ( )
172171 }
173172}
174173
175- impl PyTuple {
174+ impl < R > PyTuple < R > {
175+ pub const fn as_slice ( & self ) -> & [ R ] {
176+ & self . elements
177+ }
178+
179+ #[ inline]
180+ pub fn len ( & self ) -> usize {
181+ self . elements . len ( )
182+ }
183+
184+ #[ inline]
185+ pub fn is_empty ( & self ) -> bool {
186+ self . elements . is_empty ( )
187+ }
188+
189+ #[ inline]
190+ pub fn iter ( & self ) -> std:: slice:: Iter < ' _ , R > {
191+ self . elements . iter ( )
192+ }
193+ }
194+
195+ impl PyTuple < PyObjectRef > {
176196 pub fn new_ref ( elements : Vec < PyObjectRef > , ctx : & Context ) -> PyRef < Self > {
177197 if elements. is_empty ( ) {
178198 ctx. empty_tuple . clone ( )
@@ -189,10 +209,6 @@ impl PyTuple {
189209 Self { elements }
190210 }
191211
192- pub const fn as_slice ( & self ) -> & [ PyObjectRef ] {
193- & self . elements
194- }
195-
196212 fn repeat ( zelf : PyRef < Self > , value : isize , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
197213 Ok ( if zelf. elements . is_empty ( ) || value == 0 {
198214 vm. ctx . empty_tuple . clone ( )
@@ -214,6 +230,18 @@ impl PyTuple {
214230 }
215231}
216232
233+ impl < T > PyTuple < PyRef < T > > {
234+ pub fn new_ref_typed ( elements : Vec < PyRef < T > > , ctx : & Context ) -> PyRef < PyTuple < PyRef < T > > > {
235+ // SAFETY: PyRef<T> has the same layout as PyObjectRef
236+ unsafe {
237+ let elements: Vec < PyObjectRef > =
238+ std:: mem:: transmute :: < Vec < PyRef < T > > , Vec < PyObjectRef > > ( elements) ;
239+ let tuple = PyTuple :: < PyObjectRef > :: new_ref ( elements, ctx) ;
240+ std:: mem:: transmute :: < PyRef < PyTuple > , PyRef < PyTuple < PyRef < T > > > > ( tuple)
241+ }
242+ }
243+ }
244+
217245#[ pyclass(
218246 flags( BASETYPE ) ,
219247 with(
@@ -272,11 +300,6 @@ impl PyTuple {
272300 self . elements . len ( )
273301 }
274302
275- #[ inline]
276- pub const fn is_empty ( & self ) -> bool {
277- self . elements . is_empty ( )
278- }
279-
280303 #[ pymethod( name = "__rmul__" ) ]
281304 #[ pymethod]
282305 fn __mul__ ( zelf : PyRef < Self > , value : ArgSize , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
@@ -449,21 +472,38 @@ impl Representable for PyTuple {
449472 }
450473}
451474
452- impl PyRef < PyTuple > {
475+ impl PyRef < PyTuple < PyObjectRef > > {
453476 pub fn try_into_typed < T : PyPayload > (
454477 self ,
455478 vm : & VirtualMachine ,
456- ) -> PyResult < PyRef < PyTupleTyped < PyRef < T > > > > {
457- PyRef :: < PyTupleTyped < PyRef < T > > > :: try_from_untyped ( self , vm)
479+ ) -> PyResult < PyRef < PyTuple < PyRef < T > > > > {
480+ // Check that all elements are of the correct type
481+ for elem in self . as_slice ( ) {
482+ <PyRef < T > as TransmuteFromObject >:: check ( vm, elem) ?;
483+ }
484+ // SAFETY: We just verified all elements are of type T
485+ Ok ( unsafe { std:: mem:: transmute :: < PyRef < PyTuple > , PyRef < PyTuple < PyRef < T > > > > ( self ) } )
486+ }
487+ }
488+
489+ impl < T : PyPayload > PyRef < PyTuple < PyRef < T > > > {
490+ pub fn into_untyped ( self ) -> PyRef < PyTuple > {
491+ // SAFETY: PyTuple<PyRef<T>> has the same layout as PyTuple
492+ unsafe { std:: mem:: transmute :: < PyRef < PyTuple < PyRef < T > > > , PyRef < PyTuple > > ( self ) }
458493 }
459- /// # Safety
460- ///
461- /// The caller must ensure that all elements in the tuple are valid instances
462- /// of type `T` before calling this method. This is typically verified by
463- /// calling `try_into_typed` first.
464- unsafe fn into_typed_unchecked < T : PyPayload > ( self ) -> PyRef < PyTupleTyped < PyRef < T > > > {
465- let obj: PyObjectRef = self . into ( ) ;
466- unsafe { obj. downcast_unchecked :: < PyTupleTyped < PyRef < T > > > ( ) }
494+ }
495+
496+ impl < T : PyPayload > Py < PyTuple < PyRef < T > > > {
497+ pub fn as_untyped ( & self ) -> & Py < PyTuple > {
498+ // SAFETY: PyTuple<PyRef<T>> has the same layout as PyTuple
499+ unsafe { std:: mem:: transmute :: < & Py < PyTuple < PyRef < T > > > , & Py < PyTuple > > ( self ) }
500+ }
501+ }
502+
503+ impl < T : PyPayload > From < PyRef < PyTuple < PyRef < T > > > > for PyTupleRef {
504+ #[ inline]
505+ fn from ( tup : PyRef < PyTuple < PyRef < T > > > ) -> Self {
506+ tup. into_untyped ( )
467507 }
468508}
469509
@@ -518,101 +558,6 @@ pub(crate) fn init(context: &Context) {
518558 PyTupleIterator :: extend_class ( context, context. types . tuple_iterator_type ) ;
519559}
520560
521- #[ repr( transparent) ]
522- pub struct PyTupleTyped < R > {
523- // SAFETY INVARIANT: T must be repr(transparent) over PyObjectRef, and the
524- // elements must be logically valid when transmuted to T
525- tuple : PyTuple ,
526- _marker : PhantomData < R > ,
527- }
528-
529- unsafe impl < R > Traverse for PyTupleTyped < R >
530- where
531- R : TransmuteFromObject ,
532- {
533- fn traverse ( & self , tracer_fn : & mut TraverseFn < ' _ > ) {
534- self . tuple . traverse ( tracer_fn) ;
535- }
536- }
537-
538- impl < R : TransmuteFromObject + Traverse > MaybeTraverse for PyTupleTyped < R > {
539- const IS_TRACE : bool = true ;
540- fn try_traverse ( & self , tracer_fn : & mut TraverseFn < ' _ > ) {
541- self . traverse ( tracer_fn) ;
542- }
543- }
544-
545- impl < T : PyPayload > PyTupleTyped < PyRef < T > > {
546- pub fn new_ref ( elements : Vec < PyRef < T > > , ctx : & Context ) -> PyRef < Self > {
547- // SAFETY: PyRef<T> has the same layout as PyObjectRef
548- unsafe {
549- let elements: Vec < PyObjectRef > =
550- std:: mem:: transmute :: < Vec < PyRef < T > > , Vec < PyObjectRef > > ( elements) ;
551- let tuple = PyTuple :: new_ref ( elements, ctx) ;
552- tuple. into_typed_unchecked :: < T > ( )
553- }
554- }
555- }
556-
557- impl < T : PyPayload > PyRef < PyTupleTyped < PyRef < T > > > {
558- pub fn into_untyped ( self ) -> PyRef < PyTuple > {
559- // SAFETY: PyTupleTyped is transparent over PyTuple
560- unsafe { std:: mem:: transmute :: < PyRef < PyTupleTyped < PyRef < T > > > , PyRef < PyTuple > > ( self ) }
561- }
562-
563- pub fn try_from_untyped ( tuple : PyTupleRef , vm : & VirtualMachine ) -> PyResult < Self > {
564- // Check that all elements are of the correct type
565- for elem in tuple. as_slice ( ) {
566- <PyRef < T > as TransmuteFromObject >:: check ( vm, elem) ?;
567- }
568- // SAFETY: We just verified all elements are of type T, and PyTupleTyped has the same layout as PyTuple
569- Ok ( unsafe { std:: mem:: transmute :: < PyRef < PyTuple > , PyRef < PyTupleTyped < PyRef < T > > > > ( tuple) } )
570- }
571- }
572-
573- impl < T : PyPayload > Py < PyTupleTyped < PyRef < T > > > {
574- pub fn as_untyped ( & self ) -> & Py < PyTuple > {
575- // SAFETY: PyTupleTyped is transparent over PyTuple
576- unsafe { std:: mem:: transmute :: < & Py < PyTupleTyped < PyRef < T > > > , & Py < PyTuple > > ( self ) }
577- }
578- }
579-
580- impl < T : PyPayload > AsRef < [ PyRef < T > ] > for PyTupleTyped < PyRef < T > > {
581- fn as_ref ( & self ) -> & [ PyRef < T > ] {
582- self . as_slice ( )
583- }
584- }
585-
586- impl < T : PyPayload > PyTupleTyped < PyRef < T > > {
587- #[ inline]
588- pub fn as_slice ( & self ) -> & [ PyRef < T > ] {
589- unsafe { & * ( self . tuple . as_slice ( ) as * const [ PyObjectRef ] as * const [ PyRef < T > ] ) }
590- }
591-
592- #[ inline]
593- pub fn len ( & self ) -> usize {
594- self . tuple . len ( )
595- }
596-
597- #[ inline]
598- pub fn is_empty ( & self ) -> bool {
599- self . tuple . is_empty ( )
600- }
601- }
602-
603- impl < R : fmt:: Debug > fmt:: Debug for PyTupleTyped < R > {
604- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
605- self . tuple . as_slice ( ) . fmt ( f)
606- }
607- }
608-
609- impl < T : PyPayload > From < PyRef < PyTupleTyped < PyRef < T > > > > for PyTupleRef {
610- #[ inline]
611- fn from ( tup : PyRef < PyTupleTyped < PyRef < T > > > ) -> Self {
612- tup. into_untyped ( )
613- }
614- }
615-
616561pub ( super ) fn tuple_hash ( elements : & [ PyObjectRef ] , vm : & VirtualMachine ) -> PyResult < PyHash > {
617562 #[ cfg( target_pointer_width = "64" ) ]
618563 const PRIME1 : PyUHash = 11400714785074694791 ;
0 commit comments