11use crate :: marker:: { Destruct , PhantomData } ;
2- use crate :: mem:: { ManuallyDrop , SizedTypeProperties , conjure_zst} ;
3- use crate :: ptr:: { NonNull , drop_in_place, from_raw_parts_mut, null_mut } ;
2+ use crate :: mem:: { ManuallyDrop , SizedTypeProperties , conjure_zst, transmute } ;
3+ use crate :: ptr:: { NonNull , drop_in_place, from_raw_parts_mut, without_provenance_mut } ;
44
5- impl < ' l , ' f , T , U , const N : usize , F : FnMut ( T ) -> U > Drain < ' l , ' f , T , N , F > {
5+ impl < ' l , ' f , T , U , F : FnMut ( T ) -> U > Drain < ' l , ' f , T , F > {
66 /// This function returns a function that lets you index the given array in const.
77 /// As implemented it can optimize better than iterators, and can be constified.
88 /// It acts like a sort of guard (owns the array) and iterator combined, which can be implemented
@@ -14,44 +14,47 @@ impl<'l, 'f, T, U, const N: usize, F: FnMut(T) -> U> Drain<'l, 'f, T, N, F> {
1414 /// This will also not actually store the array.
1515 ///
1616 /// SAFETY: must only be called `N` times. Thou shalt not drop the array either.
17- // FIXME(const-hack): this is a hack for `let guard = Guard(array); |i| f(guard[i])`.
1817 #[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
19- pub ( super ) const unsafe fn new ( array : & ' l mut ManuallyDrop < [ T ; N ] > , f : & ' f mut F ) -> Self {
18+ pub ( super ) const unsafe fn new < const N : usize > (
19+ array : & ' l mut ManuallyDrop < [ T ; N ] > ,
20+ f : & ' f mut F ,
21+ ) -> Self {
2022 // dont drop the array, transfers "ownership" to Self
2123 let ptr: NonNull < T > = NonNull :: from_mut ( array) . cast ( ) ;
2224 // SAFETY:
2325 // Adding `slice.len()` to the starting pointer gives a pointer
2426 // at the end of `slice`. `end` will never be dereferenced, only checked
2527 // for direct pointer equality with `ptr` to check if the drainer is done.
2628 unsafe {
27- let end = if T :: IS_ZST { null_mut ( ) } else { ptr. as_ptr ( ) . add ( N ) } ;
28- Self { ptr, end, f, l : PhantomData }
29+ let end_or_len =
30+ if T :: IS_ZST { without_provenance_mut ( N ) } else { ptr. as_ptr ( ) . add ( N ) } ;
31+ Self { ptr, end_or_len, f, l : PhantomData }
2932 }
3033 }
3134}
3235
3336/// See [`Drain::new`]; this is our fake iterator.
3437#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
3538#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
36- pub ( super ) struct Drain < ' l , ' f , T , const N : usize , F > {
37- // FIXME(const-hack): This is essentially a slice::IterMut<'static >, replace when possible.
39+ pub ( super ) struct Drain < ' l , ' f , T , F > {
40+ // FIXME(const-hack): This is a slice::IterMut<'l >, replace when possible.
3841 /// The pointer to the next element to return, or the past-the-end location
3942 /// if the drainer is empty.
4043 ///
4144 /// This address will be used for all ZST elements, never changed.
4245 /// As we "own" this array, we dont need to store any lifetime.
4346 ptr : NonNull < T > ,
4447 /// For non-ZSTs, the non-null pointer to the past-the-end element.
45- /// For ZSTs, this is null .
46- end : * mut T ,
48+ /// For ZSTs, this is the number of unprocessed items .
49+ end_or_len : * mut T ,
4750
4851 f : & ' f mut F ,
49- l : PhantomData < & ' l mut [ T ; N ] > ,
52+ l : PhantomData < & ' l mut [ T ] > ,
5053}
5154
5255#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
5356#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
54- impl < T , U , const N : usize , F > const FnOnce < ( usize , ) > for & mut Drain < ' _ , ' _ , T , N , F >
57+ impl < T , U , F > const FnOnce < ( usize , ) > for & mut Drain < ' _ , ' _ , T , F >
5558where
5659 F : [ const ] FnMut ( T ) -> U ,
5760{
6467}
6568#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
6669#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
67- impl < T , U , const N : usize , F > const FnMut < ( usize , ) > for & mut Drain < ' _ , ' _ , T , N , F >
70+ impl < T , U , F > const FnMut < ( usize , ) > for & mut Drain < ' _ , ' _ , T , F >
6871where
6972 F : [ const ] FnMut ( T ) -> U ,
7073{
7477 ( _ /* ignore argument */ , ) : ( usize , ) ,
7578 ) -> Self :: Output {
7679 if T :: IS_ZST {
80+ #[ expect( ptr_to_integer_transmute_in_consts) ]
81+ // SAFETY:
82+ // This is equivalent to `self.end_or_len.addr`, but that's not
83+ // available in `const`. `self.end_or_len` doesn't have provenance,
84+ // so transmuting is fine.
85+ let len = unsafe { transmute :: < * mut T , usize > ( self . end_or_len ) } ;
86+ // SAFETY:
87+ // The caller guarantees that this is never called more than N times
88+ // (see `Drain::new`), hence this cannot underflow.
89+ self . end_or_len = without_provenance_mut ( unsafe { len. unchecked_sub ( 1 ) } ) ;
7790 // its UB to call this more than N times, so returning more ZSTs is valid.
7891 // SAFETY: its a ZST? we conjur.
7992 ( self . f ) ( unsafe { conjure_zst :: < T > ( ) } )
@@ -89,20 +102,32 @@ where
89102}
90103#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
91104#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
92- impl < T : [ const ] Destruct , const N : usize , F > const Drop for Drain < ' _ , ' _ , T , N , F > {
105+ impl < T : [ const ] Destruct , F > const Drop for Drain < ' _ , ' _ , T , F > {
93106 fn drop ( & mut self ) {
94- if !T :: IS_ZST {
107+ let slice = if T :: IS_ZST {
108+ from_raw_parts_mut :: < [ T ] > (
109+ self . ptr . as_ptr ( ) ,
110+ #[ expect( ptr_to_integer_transmute_in_consts) ]
111+ // SAFETY:
112+ // This is equivalent to `self.end_or_len.addr`, but that's not
113+ // available in `const`. `self.end_or_len` doesn't have provenance,
114+ // so transmuting is fine.
115+ unsafe {
116+ transmute :: < * mut T , usize > ( self . end_or_len )
117+ } ,
118+ )
119+ } else {
95120 // SAFETY: we cant read more than N elements
96- let slice = unsafe {
121+ unsafe {
97122 from_raw_parts_mut :: < [ T ] > (
98123 self . ptr . as_ptr ( ) ,
99124 // SAFETY: `start <= end`
100- self . end . offset_from_unsigned ( self . ptr . as_ptr ( ) ) ,
125+ self . end_or_len . offset_from_unsigned ( self . ptr . as_ptr ( ) ) ,
101126 )
102- } ;
127+ }
128+ } ;
103129
104- // SAFETY: By the type invariant, we're allowed to drop all these. (we own it, after all)
105- unsafe { drop_in_place ( slice) }
106- }
130+ // SAFETY: By the type invariant, we're allowed to drop all these. (we own it, after all)
131+ unsafe { drop_in_place ( slice) }
107132 }
108133}
0 commit comments