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,43 +14,46 @@ 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#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
35- pub ( super ) struct Drain < ' l , ' f , T , const N : usize , F > {
36- // FIXME(const-hack): This is essentially a slice::IterMut<'static >, replace when possible.
38+ pub ( super ) struct Drain < ' l , ' f , T , F > {
39+ // FIXME(const-hack): This is a slice::IterMut<'l >, replace when possible.
3740 /// The pointer to the next element to return, or the past-the-end location
3841 /// if the drainer is empty.
3942 ///
4043 /// This address will be used for all ZST elements, never changed.
4144 /// As we "own" this array, we dont need to store any lifetime.
4245 ptr : NonNull < T > ,
4346 /// For non-ZSTs, the non-null pointer to the past-the-end element.
44- /// For ZSTs, this is null .
45- end : * mut T ,
47+ /// For ZSTs, this is the number of unprocessed items .
48+ end_or_len : * mut T ,
4649
4750 f : & ' f mut F ,
48- l : PhantomData < & ' l mut [ T ; N ] > ,
51+ l : PhantomData < & ' l mut [ T ] > ,
4952}
5053
5154#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
5255#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
53- impl < T , U , const N : usize , F > const FnOnce < ( usize , ) > for & mut Drain < ' _ , ' _ , T , N , F >
56+ impl < T , U , F > const FnOnce < ( usize , ) > for & mut Drain < ' _ , ' _ , T , F >
5457where
5558 F : [ const ] FnMut ( T ) -> U ,
5659{
6366}
6467#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
6568#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
66- impl < T , U , const N : usize , F > const FnMut < ( usize , ) > for & mut Drain < ' _ , ' _ , T , N , F >
69+ impl < T , U , F > const FnMut < ( usize , ) > for & mut Drain < ' _ , ' _ , T , F >
6770where
6871 F : [ const ] FnMut ( T ) -> U ,
6972{
7376 ( _ /* ignore argument */ , ) : ( usize , ) ,
7477 ) -> Self :: Output {
7578 if T :: IS_ZST {
79+ #[ expect( ptr_to_integer_transmute_in_consts) ]
80+ // SAFETY:
81+ // This is equivalent to `self.end_or_len.addr`, but that's not
82+ // available in `const`. `self.end_or_len` doesn't have provenance,
83+ // so transmuting is fine.
84+ let len = unsafe { transmute :: < * mut T , usize > ( self . end_or_len ) } ;
85+ // SAFETY:
86+ // The caller guarantees that this is never called more than N times
87+ // (see `Drain::new`), hence this cannot underflow.
88+ self . end_or_len = without_provenance_mut ( unsafe { len. unchecked_sub ( 1 ) } ) ;
7689 // its UB to call this more than N times, so returning more ZSTs is valid.
7790 // SAFETY: its a ZST? we conjur.
7891 ( self . f ) ( unsafe { conjure_zst :: < T > ( ) } )
@@ -88,20 +101,32 @@ where
88101}
89102#[ rustc_const_unstable( feature = "array_try_map" , issue = "79711" ) ]
90103#[ unstable( feature = "array_try_map" , issue = "79711" ) ]
91- impl < T : [ const ] Destruct , const N : usize , F > const Drop for Drain < ' _ , ' _ , T , N , F > {
104+ impl < T : [ const ] Destruct , F > const Drop for Drain < ' _ , ' _ , T , F > {
92105 fn drop ( & mut self ) {
93- if !T :: IS_ZST {
106+ let slice = if T :: IS_ZST {
107+ from_raw_parts_mut :: < [ T ] > (
108+ self . ptr . as_ptr ( ) ,
109+ #[ expect( ptr_to_integer_transmute_in_consts) ]
110+ // SAFETY:
111+ // This is equivalent to `self.end_or_len.addr`, but that's not
112+ // available in `const`. `self.end_or_len` doesn't have provenance,
113+ // so transmuting is fine.
114+ unsafe {
115+ transmute :: < * mut T , usize > ( self . end_or_len )
116+ } ,
117+ )
118+ } else {
94119 // SAFETY: we cant read more than N elements
95- let slice = unsafe {
120+ unsafe {
96121 from_raw_parts_mut :: < [ T ] > (
97122 self . ptr . as_ptr ( ) ,
98123 // SAFETY: `start <= end`
99- self . end . offset_from_unsigned ( self . ptr . as_ptr ( ) ) ,
124+ self . end_or_len . offset_from_unsigned ( self . ptr . as_ptr ( ) ) ,
100125 )
101- } ;
126+ }
127+ } ;
102128
103- // SAFETY: By the type invariant, we're allowed to drop all these. (we own it, after all)
104- unsafe { drop_in_place ( slice) }
105- }
129+ // SAFETY: By the type invariant, we're allowed to drop all these. (we own it, after all)
130+ unsafe { drop_in_place ( slice) }
106131 }
107132}
0 commit comments