Skip to content

Commit b67c5af

Browse files
fee1-deadonestacked
authored andcommitted
Allow const iterator implementations
1 parent b7b7f27 commit b67c5af

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1130
-408
lines changed

library/core/src/array/mod.rs

Lines changed: 82 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::error::Error;
1111
use crate::fmt;
1212
use crate::hash::{self, Hash};
1313
use crate::iter::TrustedLen;
14+
use crate::marker::Destruct;
1415
use crate::mem::{self, MaybeUninit};
1516
use crate::ops::{
1617
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
@@ -841,6 +842,54 @@ where
841842
}
842843
}
843844

845+
/// Panic guard for incremental initialization of arrays.
846+
///
847+
/// Disarm the guard with `mem::forget` once the array has been initialized.
848+
///
849+
/// # Safety
850+
///
851+
/// All write accesses to this structure are unsafe and must maintain a correct
852+
/// count of `initialized` elements.
853+
///
854+
/// To minimize indirection fields are still pub but callers should at least use
855+
/// `push_unchecked` to signal that something unsafe is going on.
856+
pub(crate) struct Guard<'a, T: Destruct, const N: usize> {
857+
/// The array to be initialized.
858+
pub array_mut: &'a mut [MaybeUninit<T>; N],
859+
/// The number of items that have been initialized so far.
860+
pub initialized: usize,
861+
}
862+
863+
impl<T, const N: usize> Guard<'_, T, N> {
864+
/// Adds an item to the array and updates the initialized item counter.
865+
///
866+
/// # Safety
867+
///
868+
/// No more than N elements must be initialized.
869+
#[inline]
870+
pub unsafe fn push_unchecked(&mut self, item: T) {
871+
// SAFETY: If `initialized` was correct before and the caller does not
872+
// invoke this method more than N times then writes will be in-bounds
873+
// and slots will not be initialized more than once.
874+
unsafe {
875+
self.array_mut.get_unchecked_mut(self.initialized).write(item);
876+
self.initialized = self.initialized.unchecked_add(1);
877+
}
878+
}
879+
}
880+
881+
impl<T: ~const Destruct, const N: usize> const Drop for Guard<'_, T, N> {
882+
fn drop(&mut self) {
883+
debug_assert!(self.initialized <= N);
884+
885+
// SAFETY: this slice will contain only initialized objects.
886+
unsafe {
887+
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
888+
&mut self.array_mut.get_unchecked_mut(..self.initialized),
889+
));
890+
}
891+
}
892+
}
844893
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
845894
/// yields fewer than `N` items, `Err` is returned containing an iterator over
846895
/// the already yielded items.
@@ -852,23 +901,27 @@ where
852901
/// If `iter.next()` panicks, all items already yielded by the iterator are
853902
/// dropped.
854903
#[inline]
855-
fn try_collect_into_array<I, T, R, const N: usize>(
904+
const fn try_collect_into_array<I, T, R, const N: usize>(
856905
iter: &mut I,
857906
) -> Result<R::TryType, IntoIter<T, N>>
858907
where
859-
I: Iterator,
860-
I::Item: Try<Output = T, Residual = R>,
861-
R: Residual<[T; N]>,
908+
I: ~const Iterator,
909+
I::Item: ~const Try<Output = T, Residual = R>,
910+
R: ~const Residual<[T; N]>,
911+
T: ~const Destruct,
912+
R::TryType: ~const Try, // #[cfg(bootstrap)]
862913
{
863914
if N == 0 {
864915
// SAFETY: An empty array is always inhabited and has no validity invariants.
865-
return Ok(Try::from_output(unsafe { mem::zeroed() }));
916+
return Ok(Try::from_output(unsafe { MaybeUninit::zeroed().assume_init() }));
866917
}
867918

868919
let mut array = MaybeUninit::uninit_array::<N>();
869920
let mut guard = Guard { array_mut: &mut array, initialized: 0 };
870921

871-
for _ in 0..N {
922+
let mut i = 0;
923+
// FIXME(const_trait_impl): replace with `for` loop
924+
while i < N {
872925
match iter.next() {
873926
Some(item_rslt) => {
874927
let item = match item_rslt.branch() {
@@ -878,11 +931,13 @@ where
878931
ControlFlow::Continue(elem) => elem,
879932
};
880933

881-
// SAFETY: `guard.initialized` starts at 0, which means push can be called
882-
// at most N times, which this loop does.
934+
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
935+
// loop and the loop is aborted once it reaches N (which is
936+
// `array.len()`).
883937
unsafe {
884-
guard.push_unchecked(item);
938+
guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
885939
}
940+
guard.initialized += 1;
886941
}
887942
None => {
888943
let alive = 0..guard.initialized;
@@ -892,66 +947,35 @@ where
892947
return Err(unsafe { IntoIter::new_unchecked(array, alive) });
893948
}
894949
}
950+
i += 1;
895951
}
896952

897953
mem::forget(guard);
898954
// SAFETY: All elements of the array were populated in the loop above.
899-
let output = unsafe { array.transpose().assume_init() };
955+
let output = unsafe { MaybeUninit::array_assume_init(array) };
900956
Ok(Try::from_output(output))
901957
}
902958

903-
/// Panic guard for incremental initialization of arrays.
904-
///
905-
/// Disarm the guard with `mem::forget` once the array has been initialized.
906-
///
907-
/// # Safety
908-
///
909-
/// All write accesses to this structure are unsafe and must maintain a correct
910-
/// count of `initialized` elements.
911-
///
912-
/// To minimize indirection fields are still pub but callers should at least use
913-
/// `push_unchecked` to signal that something unsafe is going on.
914-
pub(crate) struct Guard<'a, T, const N: usize> {
915-
/// The array to be initialized.
916-
pub array_mut: &'a mut [MaybeUninit<T>; N],
917-
/// The number of items that have been initialized so far.
918-
pub initialized: usize,
919-
}
920-
921-
impl<T, const N: usize> Guard<'_, T, N> {
922-
/// Adds an item to the array and updates the initialized item counter.
923-
///
924-
/// # Safety
925-
///
926-
/// No more than N elements must be initialized.
927-
#[inline]
928-
pub unsafe fn push_unchecked(&mut self, item: T) {
929-
// SAFETY: If `initialized` was correct before and the caller does not
930-
// invoke this method more than N times then writes will be in-bounds
931-
// and slots will not be initialized more than once.
932-
unsafe {
933-
self.array_mut.get_unchecked_mut(self.initialized).write(item);
934-
self.initialized = self.initialized.unchecked_add(1);
935-
}
936-
}
937-
}
938-
939-
impl<T, const N: usize> Drop for Guard<'_, T, N> {
940-
fn drop(&mut self) {
941-
debug_assert!(self.initialized <= N);
959+
/// Returns the next chunk of `N` items from the iterator or errors with an
960+
/// iterator over the remainder. Used for `Iterator::next_chunk`.
961+
#[inline]
962+
#[cfg(not(bootstrap))]
963+
pub(crate) const fn iter_next_chunk<I, const N: usize>(
964+
iter: &mut I,
965+
) -> Result<[I::Item; N], IntoIter<I::Item, N>>
966+
where
967+
I: ~const Iterator,
968+
I::Item: ~const Destruct,
969+
{
970+
let mut map = iter.map(NeverShortCircuit);
942971

943-
// SAFETY: this slice will contain only initialized objects.
944-
unsafe {
945-
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
946-
&mut self.array_mut.get_unchecked_mut(..self.initialized),
947-
));
948-
}
972+
match try_collect_into_array(&mut map) {
973+
Ok(NeverShortCircuit(x)) => Ok(x),
974+
Err(e) => Err(e),
949975
}
950976
}
951977

952-
/// Returns the next chunk of `N` items from the iterator or errors with an
953-
/// iterator over the remainder. Used for `Iterator::next_chunk`.
954-
#[inline]
978+
#[cfg(bootstrap)]
955979
pub(crate) fn iter_next_chunk<I, const N: usize>(
956980
iter: &mut I,
957981
) -> Result<[I::Item; N], IntoIter<I::Item, N>>

library/core/src/cmp.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
use crate::const_closure::ConstFnMutClosure;
2626
use crate::marker::Destruct;
27+
use crate::marker::StructuralEq;
2728
use crate::marker::StructuralPartialEq;
2829

2930
use self::Ordering::*;
@@ -280,7 +281,8 @@ pub macro PartialEq($item:item) {
280281
#[doc(alias = "!=")]
281282
#[stable(feature = "rust1", since = "1.0.0")]
282283
#[rustc_diagnostic_item = "Eq"]
283-
pub trait Eq: PartialEq<Self> {
284+
#[const_trait]
285+
pub trait Eq: ~const PartialEq<Self> {
284286
// this method is used solely by #[deriving] to assert
285287
// that every component of a type implements #[deriving]
286288
// itself, the current deriving infrastructure means doing this
@@ -330,7 +332,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
330332
/// let result = 2.cmp(&1);
331333
/// assert_eq!(Ordering::Greater, result);
332334
/// ```
333-
#[derive(Clone, Copy, Eq, Debug, Hash)]
335+
#[derive(Clone, Copy, Debug, Hash)]
334336
#[stable(feature = "rust1", since = "1.0.0")]
335337
#[repr(i8)]
336338
pub enum Ordering {
@@ -578,6 +580,9 @@ impl Ordering {
578580
}
579581
}
580582

583+
#[stable(feature = "rust1", since = "1.0.0")]
584+
impl StructuralEq for Ordering {}
585+
581586
/// A helper struct for reverse ordering.
582587
///
583588
/// This struct is a helper to be used with functions like [`Vec::sort_by_key`] and
@@ -760,7 +765,7 @@ impl<T: Clone> Clone for Reverse<T> {
760765
#[stable(feature = "rust1", since = "1.0.0")]
761766
#[rustc_diagnostic_item = "Ord"]
762767
#[const_trait]
763-
pub trait Ord: Eq + PartialOrd<Self> {
768+
pub trait Ord: ~const Eq + ~const PartialOrd<Self> {
764769
/// This method returns an [`Ordering`] between `self` and `other`.
765770
///
766771
/// By convention, `self.cmp(&other)` returns the ordering matching the expression
@@ -888,6 +893,10 @@ impl const PartialEq for Ordering {
888893
}
889894
}
890895

896+
#[stable(feature = "rust1", since = "1.0.0")]
897+
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
898+
impl const Eq for Ordering {}
899+
891900
#[stable(feature = "rust1", since = "1.0.0")]
892901
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
893902
impl const Ord for Ordering {
@@ -1227,7 +1236,6 @@ pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
12271236
pub const fn min_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
12281237
where
12291238
T: ~const Destruct,
1230-
F: ~const Destruct,
12311239
{
12321240
match compare(&v1, &v2) {
12331241
Ordering::Less | Ordering::Equal => v1,
@@ -1312,7 +1320,6 @@ pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
13121320
pub const fn max_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
13131321
where
13141322
T: ~const Destruct,
1315-
F: ~const Destruct,
13161323
{
13171324
match compare(&v1, &v2) {
13181325
Ordering::Less | Ordering::Equal => v2,
@@ -1393,7 +1400,8 @@ mod impls {
13931400
macro_rules! eq_impl {
13941401
($($t:ty)*) => ($(
13951402
#[stable(feature = "rust1", since = "1.0.0")]
1396-
impl Eq for $t {}
1403+
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
1404+
impl const Eq for $t {}
13971405
)*)
13981406
}
13991407

@@ -1517,7 +1525,8 @@ mod impls {
15171525
}
15181526

15191527
#[unstable(feature = "never_type", issue = "35121")]
1520-
impl Eq for ! {}
1528+
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
1529+
impl const Eq for ! {}
15211530

15221531
#[unstable(feature = "never_type", issue = "35121")]
15231532
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]

library/core/src/iter/adapters/array_chunks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ where
2424
I: Iterator,
2525
{
2626
#[track_caller]
27-
pub(in crate::iter) fn new(iter: I) -> Self {
27+
pub(in crate::iter) const fn new(iter: I) -> Self {
2828
assert!(N != 0, "chunk size must be non-zero");
2929
Self { iter, remainder: None }
3030
}

library/core/src/iter/adapters/by_ref_sized.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::{
2-
const_closure::ConstFnMutClosure,
3-
ops::{NeverShortCircuit, Try},
4-
};
1+
use crate::const_closure::ConstFnMutClosure;
2+
use crate::marker::Destruct;
3+
use crate::ops::{NeverShortCircuit, Try};
54

65
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
76
///
@@ -15,7 +14,7 @@ pub struct ByRefSized<'a, I>(pub &'a mut I);
1514
// to avoid accidentally calling the `&mut Iterator` implementations.
1615

1716
#[unstable(feature = "std_internals", issue = "none")]
18-
impl<I: Iterator> Iterator for ByRefSized<'_, I> {
17+
impl<I: ~const Iterator> const Iterator for ByRefSized<'_, I> {
1918
type Item = I::Item;
2019

2120
#[inline]
@@ -29,19 +28,25 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
2928
}
3029

3130
#[inline]
32-
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
31+
fn advance_by(&mut self, n: usize) -> Result<(), usize>
32+
where
33+
I::Item: ~const Destruct,
34+
{
3335
I::advance_by(self.0, n)
3436
}
3537

3638
#[inline]
37-
fn nth(&mut self, n: usize) -> Option<Self::Item> {
39+
fn nth(&mut self, n: usize) -> Option<Self::Item>
40+
where
41+
I::Item: ~const Destruct,
42+
{
3843
I::nth(self.0, n)
3944
}
4045

4146
#[inline]
4247
fn fold<B, F>(self, init: B, mut f: F) -> B
4348
where
44-
F: FnMut(B, Self::Item) -> B,
49+
F: ~const FnMut(B, Self::Item) -> B + ~const Destruct,
4550
{
4651
// `fold` needs ownership, so this can't forward directly.
4752
I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
@@ -51,8 +56,8 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
5156
#[inline]
5257
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
5358
where
54-
F: FnMut(B, Self::Item) -> R,
55-
R: Try<Output = B>,
59+
F: ~const FnMut(B, Self::Item) -> R + ~const Destruct,
60+
R: ~const Try<Output = B>,
5661
{
5762
I::try_fold(self.0, init, f)
5863
}

library/core/src/iter/adapters/chain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub struct Chain<A, B> {
3232
b: Option<B>,
3333
}
3434
impl<A, B> Chain<A, B> {
35-
pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
35+
pub(in super::super) const fn new(a: A, b: B) -> Chain<A, B> {
3636
Chain { a: Some(a), b: Some(b) }
3737
}
3838
}

library/core/src/iter/adapters/cloned.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct Cloned<I> {
1919
}
2020

2121
impl<I> Cloned<I> {
22-
pub(in crate::iter) fn new(it: I) -> Cloned<I> {
22+
pub(in crate::iter) const fn new(it: I) -> Cloned<I> {
2323
Cloned { it }
2424
}
2525
}

library/core/src/iter/adapters/copied.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub struct Copied<I> {
2222
}
2323

2424
impl<I> Copied<I> {
25-
pub(in crate::iter) fn new(it: I) -> Copied<I> {
25+
pub(in crate::iter) const fn new(it: I) -> Copied<I> {
2626
Copied { it }
2727
}
2828
}

library/core/src/iter/adapters/cycle.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ pub struct Cycle<I> {
1616
}
1717

1818
impl<I: Clone> Cycle<I> {
19-
pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
19+
pub(in crate::iter) const fn new(iter: I) -> Cycle<I>
20+
where
21+
I: ~const Clone,
22+
{
2023
Cycle { orig: iter.clone(), iter }
2124
}
2225
}

0 commit comments

Comments
 (0)