@@ -65,3 +65,111 @@ fn tuple_struct_multi_pinned_fields_projection() {
6565 assert_eq ! ( * tuple. as_ref( ) . get_ref( ) . 1 . lock( ) , 20 ) ;
6666 assert_eq ! ( tuple. as_ref( ) . get_ref( ) . 2 , 30 ) ;
6767}
68+
69+ #[ pin_data]
70+ struct GenericTuple < ' a , T , const N : usize > ( #[ pin] CMutex < ( & ' a T , [ u8 ; N ] ) > , usize ) ;
71+
72+ #[ pin_data]
73+ #[ allow( dead_code) ]
74+ struct UnpinnedMutexTuple < T > ( CMutex < T > , usize ) ;
75+
76+ #[ pin_data]
77+ struct TupleConst < T , const N : usize > ( #[ pin] CMutex < [ T ; N ] > , usize ) ;
78+
79+ fn assert_unpin < T : Unpin > ( ) { }
80+
81+ #[ test]
82+ fn tuple_struct_generics_are_supported ( ) {
83+ let value = 77u16 ;
84+ let payload = ( & value, [ 1 , 2 , 3 , 4 ] ) ;
85+ stack_pin_init ! (
86+ let tuple = pin_init!( GenericTuple { 0 <- CMutex :: new( payload) , 1 : 12 } )
87+ ) ;
88+
89+ let projected = tuple. as_mut ( ) . project ( ) ;
90+ assert_pinned_mutex ( & projected. 0 ) ;
91+ let locked = projected. 0 . as_ref ( ) . get_ref ( ) . lock ( ) ;
92+ assert_eq ! ( * locked. 0 , 77u16 ) ;
93+ assert_eq ! ( locked. 1 , [ 1 , 2 , 3 , 4 ] ) ;
94+ assert_eq ! ( * projected. 1 , 12 ) ;
95+ }
96+
97+ #[ test]
98+ fn tuple_struct_unpin_ignores_unpinned_non_unpin_field ( ) {
99+ assert_unpin :: < UnpinnedMutexTuple < usize > > ( ) ;
100+ }
101+
102+ #[ test]
103+ fn tuple_struct_const_generics_support_explicit_arguments ( ) {
104+ stack_pin_init ! ( let tuple = pin_init!( TupleConst :: <u8 , 3 > { 0 <- CMutex :: new( [ 1 , 2 , 3 ] ) , 1 : 9 } ) ) ;
105+
106+ let projected = tuple. as_mut ( ) . project ( ) ;
107+ assert_pinned_mutex ( & projected. 0 ) ;
108+ assert_eq ! ( * projected. 0 . as_ref( ) . get_ref( ) . lock( ) , [ 1 , 2 , 3 ] ) ;
109+ assert_eq ! ( * projected. 1 , 9 ) ;
110+ }
111+
112+ #[ pin_data( PinnedDrop ) ]
113+ struct DropTuple ( #[ pin] CMutex < usize > , usize ) ;
114+
115+ static PINNED_DROP_TUPLE_DROPS : core:: sync:: atomic:: AtomicUsize =
116+ core:: sync:: atomic:: AtomicUsize :: new ( 0 ) ;
117+
118+ struct DropCounter ;
119+
120+ static FALLIBLE_TUPLE_DROPS : core:: sync:: atomic:: AtomicUsize =
121+ core:: sync:: atomic:: AtomicUsize :: new ( 0 ) ;
122+
123+ impl Drop for DropCounter {
124+ fn drop ( & mut self ) {
125+ FALLIBLE_TUPLE_DROPS . fetch_add ( 1 , core:: sync:: atomic:: Ordering :: SeqCst ) ;
126+ }
127+ }
128+
129+ fn tuple_failing_init ( ) -> impl PinInit < TupleStruct < DropCounter > , ( ) > {
130+ // SAFETY: The closure initializes field 0, explicitly rolls it back before returning `Err`,
131+ // and leaves the slot otherwise untouched.
132+ unsafe {
133+ pin_init_from_closure ( |slot : * mut TupleStruct < DropCounter > | {
134+ let field0 = core:: ptr:: addr_of_mut!( ( * slot) . 0 ) ;
135+ let init0 = CMutex :: new ( DropCounter ) ;
136+ match init0. __pinned_init ( field0) {
137+ Ok ( ( ) ) => { }
138+ Err ( infallible) => match infallible { } ,
139+ }
140+ core:: ptr:: drop_in_place ( field0) ;
141+ Err ( ( ) )
142+ } )
143+ }
144+ }
145+
146+ #[ pinned_drop]
147+ impl PinnedDrop for DropTuple {
148+ fn drop ( self : Pin < & mut Self > ) {
149+ let _ = self ;
150+ PINNED_DROP_TUPLE_DROPS . fetch_add ( 1 , core:: sync:: atomic:: Ordering :: SeqCst ) ;
151+ }
152+ }
153+
154+ #[ test]
155+ fn tuple_struct_pinned_drop_delegates_from_drop ( ) {
156+ PINNED_DROP_TUPLE_DROPS . store ( 0 , core:: sync:: atomic:: Ordering :: SeqCst ) ;
157+ {
158+ stack_pin_init ! ( let _tuple = pin_init!( DropTuple { 0 <- CMutex :: new( 5usize ) , 1 : 1 } ) ) ;
159+ }
160+ assert_eq ! (
161+ PINNED_DROP_TUPLE_DROPS . load( core:: sync:: atomic:: Ordering :: SeqCst ) ,
162+ 1
163+ ) ;
164+ }
165+
166+ #[ test]
167+ fn tuple_struct_fallible_init_drops_initialized_fields ( ) {
168+ FALLIBLE_TUPLE_DROPS . store ( 0 , core:: sync:: atomic:: Ordering :: SeqCst ) ;
169+ stack_try_pin_init ! ( let tuple: TupleStruct <DropCounter > = tuple_failing_init( ) ) ;
170+ assert ! ( matches!( tuple, Err ( ( ) ) ) ) ;
171+ assert_eq ! (
172+ FALLIBLE_TUPLE_DROPS . load( core:: sync:: atomic:: Ordering :: SeqCst ) ,
173+ 1
174+ ) ;
175+ }
0 commit comments