11use crossbeam_utils:: atomic:: AtomicCell ;
22use std:: fmt;
3+ use std:: marker:: PhantomData ;
34
45use super :: pytype:: PyTypeRef ;
56use crate :: common:: hash:: PyHash ;
67use crate :: function:: OptionalArg ;
78use crate :: pyobject:: {
89 self , BorrowValue , Either , IdProtocol , IntoPyObject , PyArithmaticValue , PyClassImpl ,
9- PyComparisonValue , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
10+ PyComparisonValue , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TransmuteFromObject ,
11+ TryFromObject , TypeProtocol ,
1012} ;
1113use crate :: sequence:: { self , SimpleSeq } ;
1214use crate :: sliceable:: PySliceableSequence ;
@@ -262,7 +264,7 @@ impl Iterable for PyTuple {
262264
263265#[ pyclass( module = false , name = "tuple_iterator" ) ]
264266#[ derive( Debug ) ]
265- pub struct PyTupleIterator {
267+ pub ( crate ) struct PyTupleIterator {
266268 position : AtomicCell < usize > ,
267269 tuple : PyTupleRef ,
268270}
@@ -287,9 +289,35 @@ impl PyIter for PyTupleIterator {
287289 }
288290}
289291
290- pub fn init ( context : & PyContext ) {
291- let tuple_type = & context. types . tuple_type ;
292- PyTuple :: extend_class ( context, tuple_type) ;
293-
292+ pub ( crate ) fn init ( context : & PyContext ) {
293+ PyTuple :: extend_class ( context, & context. types . tuple_type ) ;
294294 PyTupleIterator :: extend_class ( context, & context. types . tuple_iterator_type ) ;
295295}
296+
297+ pub struct PyTupleTyped < T > {
298+ // SAFETY INVARIANT: T must be repr(transparent) over PyObjectRef, and the
299+ // elements must be logically valid when transmuted to T
300+ tuple : PyTupleRef ,
301+ _marker : PhantomData < Vec < T > > ,
302+ }
303+
304+ impl < T : TransmuteFromObject > TryFromObject for PyTupleTyped < T > {
305+ fn try_from_object ( vm : & VirtualMachine , obj : PyObjectRef ) -> PyResult < Self > {
306+ let tuple = PyTupleRef :: try_from_object ( vm, obj) ?;
307+ for elem in tuple. borrow_value ( ) {
308+ T :: check ( vm, elem) ?
309+ }
310+ // SAFETY: the contract of TransmuteFromObject upholds the variant on `tuple`
311+ Ok ( Self {
312+ tuple,
313+ _marker : PhantomData ,
314+ } )
315+ }
316+ }
317+
318+ impl < ' a , T : ' a > BorrowValue < ' a > for PyTupleTyped < T > {
319+ type Borrowed = & ' a [ T ] ;
320+ fn borrow_value ( & ' a self ) -> Self :: Borrowed {
321+ unsafe { & * ( self . tuple . borrow_value ( ) as * const [ PyObjectRef ] as * const [ T ] ) }
322+ }
323+ }
0 commit comments