@@ -3,7 +3,6 @@ use crate::common::{
3
3
hash:: { PyHash , PyUHash } ,
4
4
lock:: PyMutex ,
5
5
} ;
6
- use crate :: object:: { MaybeTraverse , Traverse , TraverseFn } ;
7
6
use crate :: {
8
7
AsObject , Context , Py , PyObject , PyObjectRef , PyPayload , PyRef , PyResult , TryFromObject ,
9
8
atomic_func,
@@ -22,14 +21,14 @@ use crate::{
22
21
utils:: collection_repr,
23
22
vm:: VirtualMachine ,
24
23
} ;
25
- use std:: { fmt, marker :: PhantomData , sync:: LazyLock } ;
24
+ use std:: { fmt, sync:: LazyLock } ;
26
25
27
26
#[ pyclass( module = false , name = "tuple" , traverse) ]
28
- pub struct PyTuple {
29
- elements : Box < [ PyObjectRef ] > ,
27
+ pub struct PyTuple < R = PyObjectRef > {
28
+ elements : Box < [ R ] > ,
30
29
}
31
30
32
- impl fmt:: Debug for PyTuple {
31
+ impl < R > fmt:: Debug for PyTuple < R > {
33
32
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
34
33
// TODO: implement more informational, non-recursive Debug formatter
35
34
f. write_str ( "tuple" )
@@ -140,39 +139,60 @@ impl Constructor for PyTuple {
140
139
}
141
140
}
142
141
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
146
145
}
147
146
}
148
147
149
- impl std:: ops:: Deref for PyTuple {
150
- type Target = [ PyObjectRef ] ;
148
+ impl < R > std:: ops:: Deref for PyTuple < R > {
149
+ type Target = [ R ] ;
151
150
152
- fn deref ( & self ) -> & [ PyObjectRef ] {
153
- self . as_slice ( )
151
+ fn deref ( & self ) -> & [ R ] {
152
+ & self . elements
154
153
}
155
154
}
156
155
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 > ;
160
159
161
160
fn into_iter ( self ) -> Self :: IntoIter {
162
161
self . iter ( )
163
162
}
164
163
}
165
164
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 > ;
169
168
170
169
fn into_iter ( self ) -> Self :: IntoIter {
171
170
self . iter ( )
172
171
}
173
172
}
174
173
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 > {
176
196
pub fn new_ref ( elements : Vec < PyObjectRef > , ctx : & Context ) -> PyRef < Self > {
177
197
if elements. is_empty ( ) {
178
198
ctx. empty_tuple . clone ( )
@@ -189,10 +209,6 @@ impl PyTuple {
189
209
Self { elements }
190
210
}
191
211
192
- pub const fn as_slice ( & self ) -> & [ PyObjectRef ] {
193
- & self . elements
194
- }
195
-
196
212
fn repeat ( zelf : PyRef < Self > , value : isize , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
197
213
Ok ( if zelf. elements . is_empty ( ) || value == 0 {
198
214
vm. ctx . empty_tuple . clone ( )
@@ -214,6 +230,18 @@ impl PyTuple {
214
230
}
215
231
}
216
232
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
+
217
245
#[ pyclass(
218
246
flags( BASETYPE ) ,
219
247
with(
@@ -272,11 +300,6 @@ impl PyTuple {
272
300
self . elements . len ( )
273
301
}
274
302
275
- #[ inline]
276
- pub const fn is_empty ( & self ) -> bool {
277
- self . elements . is_empty ( )
278
- }
279
-
280
303
#[ pymethod( name = "__rmul__" ) ]
281
304
#[ pymethod]
282
305
fn __mul__ ( zelf : PyRef < Self > , value : ArgSize , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
@@ -449,21 +472,38 @@ impl Representable for PyTuple {
449
472
}
450
473
}
451
474
452
- impl PyRef < PyTuple > {
475
+ impl PyRef < PyTuple < PyObjectRef > > {
453
476
pub fn try_into_typed < T : PyPayload > (
454
477
self ,
455
478
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 ) }
458
493
}
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 ( )
467
507
}
468
508
}
469
509
@@ -518,101 +558,6 @@ pub(crate) fn init(context: &Context) {
518
558
PyTupleIterator :: extend_class ( context, context. types . tuple_iterator_type ) ;
519
559
}
520
560
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
-
616
561
pub ( super ) fn tuple_hash ( elements : & [ PyObjectRef ] , vm : & VirtualMachine ) -> PyResult < PyHash > {
617
562
#[ cfg( target_pointer_width = "64" ) ]
618
563
const PRIME1 : PyUHash = 11400714785074694791 ;
0 commit comments