Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow const iterator implementations #102225

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 43 additions & 15 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::error::Error;
use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
use crate::marker::Destruct;
use crate::mem::{self, MaybeUninit};
use crate::ops::{
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
Expand Down Expand Up @@ -852,23 +853,26 @@ where
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
#[inline]
fn try_collect_into_array<I, T, R, const N: usize>(
const fn try_collect_into_array<I, T, R, const N: usize>(
iter: &mut I,
) -> Result<R::TryType, IntoIter<T, N>>
where
I: Iterator,
I::Item: Try<Output = T, Residual = R>,
R: Residual<[T; N]>,
I: ~const Iterator,
I::Item: ~const Try<Output = T, Residual = R>,
R: ~const Residual<[T; N]>,
T: ~const Destruct,
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
return Ok(Try::from_output(unsafe { mem::zeroed() }));
return Ok(Try::from_output(unsafe { MaybeUninit::zeroed().assume_init() }));
}

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

for _ in 0..N {
let mut i = 0;
// FIXME(const_trait_impl): replace with `for` loop
while i < N {
match iter.next() {
Some(item_rslt) => {
let item = match item_rslt.branch() {
Expand All @@ -892,6 +896,7 @@ where
return Err(unsafe { IntoIter::new_unchecked(array, alive) });
}
}
i += 1;
}

mem::forget(guard);
Expand All @@ -911,7 +916,7 @@ where
///
/// To minimize indirection fields are still pub but callers should at least use
/// `push_unchecked` to signal that something unsafe is going on.
pub(crate) struct Guard<'a, T, const N: usize> {
pub(crate) struct Guard<'a, T: ~const Destruct, const N: usize> {
/// The array to be initialized.
pub array_mut: &'a mut [MaybeUninit<T>; N],
/// The number of items that have been initialized so far.
Expand All @@ -925,7 +930,7 @@ impl<T, const N: usize> Guard<'_, T, N> {
///
/// No more than N elements must be initialized.
#[inline]
pub unsafe fn push_unchecked(&mut self, item: T) {
pub const unsafe fn push_unchecked(&mut self, item: T) {
// SAFETY: If `initialized` was correct before and the caller does not
// invoke this method more than N times then writes will be in-bounds
// and slots will not be initialized more than once.
Expand All @@ -936,28 +941,51 @@ impl<T, const N: usize> Guard<'_, T, N> {
}
}

impl<T, const N: usize> Drop for Guard<'_, T, N> {
impl<T: ~const Destruct, const N: usize> const Drop for Guard<'_, T, N> {
fn drop(&mut self) {
debug_assert!(self.initialized <= N);

#[inline]
const fn drop_ct<T: ~const Destruct>(x: &mut [T]) {
let mut i = 0;
while i < x.len() {
// SAFETY: dropping the value, contains initialized objects
unsafe {
crate::ptr::read(&mut x[i]);
}
i += 1;
}
}
fee1-dead marked this conversation as resolved.
Show resolved Hide resolved
#[inline]
fn drop_rt<T>(x: &mut [T]) {
// SAFETY: slice contains initialized objects
unsafe { crate::ptr::drop_in_place(x) }
}

// SAFETY: this slice will contain only initialized objects.
unsafe {
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
&mut self.array_mut.get_unchecked_mut(..self.initialized),
));
let to_drop = MaybeUninit::slice_assume_init_mut(
self.array_mut.get_unchecked_mut(..self.initialized),
);
crate::intrinsics::const_eval_select((to_drop,), drop_ct, drop_rt);
}
}
}

/// Returns the next chunk of `N` items from the iterator or errors with an
/// iterator over the remainder. Used for `Iterator::next_chunk`.
#[inline]
pub(crate) fn iter_next_chunk<I, const N: usize>(
pub(crate) const fn iter_next_chunk<I, const N: usize>(
iter: &mut I,
) -> Result<[I::Item; N], IntoIter<I::Item, N>>
where
I: Iterator,
I: ~const Iterator,
I::Item: ~const Destruct,
{
let mut map = iter.map(NeverShortCircuit);
try_collect_into_array(&mut map).map(|NeverShortCircuit(arr)| arr)

match try_collect_into_array(&mut map) {
Ok(NeverShortCircuit(x)) => Ok(x),
Err(e) => Err(e),
}
}
28 changes: 10 additions & 18 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ pub macro PartialEq($item:item) {
#[doc(alias = "!=")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Eq"]
pub trait Eq: PartialEq<Self> {
#[const_trait]
pub trait Eq: ~const PartialEq<Self> {
// this method is used solely by #[deriving] to assert
// that every component of a type implements #[deriving]
// itself, the current deriving infrastructure means doing this
Expand Down Expand Up @@ -331,8 +332,9 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
/// let result = 2.cmp(&1);
/// assert_eq!(Ordering::Greater, result);
/// ```
#[derive(Clone, Copy, Eq, Debug, Hash)]
#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq))]
#[derive(Clone, Copy, Debug, Hash)]
#[cfg_attr(bootstrap, derive(Ord, Eq))]
#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq, Eq))]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(i8)]
pub enum Ordering {
Expand Down Expand Up @@ -762,7 +764,7 @@ impl<T: Clone> Clone for Reverse<T> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Ord"]
#[const_trait]
pub trait Ord: Eq + PartialOrd<Self> {
pub trait Ord: ~const Eq + ~const PartialOrd<Self> {
/// This method returns an [`Ordering`] between `self` and `other`.
///
/// By convention, `self.cmp(&other)` returns the ordering matching the expression
Expand Down Expand Up @@ -892,16 +894,6 @@ impl const PartialEq for Ordering {
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
#[cfg(bootstrap)]
impl const Ord for Ordering {
#[inline]
fn cmp(&self, other: &Ordering) -> Ordering {
(*self as i32).cmp(&(*other as i32))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
#[cfg(bootstrap)]
Expand Down Expand Up @@ -1233,7 +1225,6 @@ pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
pub const fn min_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
where
T: ~const Destruct,
F: ~const Destruct,
{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v1,
Expand Down Expand Up @@ -1318,7 +1309,6 @@ pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
pub const fn max_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
where
T: ~const Destruct,
F: ~const Destruct,
{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v2,
Expand Down Expand Up @@ -1399,7 +1389,8 @@ mod impls {
macro_rules! eq_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for $t {}
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Eq for $t {}
)*)
}

Expand Down Expand Up @@ -1523,7 +1514,8 @@ mod impls {
}

#[unstable(feature = "never_type", issue = "35121")]
impl Eq for ! {}
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Eq for ! {}

#[unstable(feature = "never_type", issue = "35121")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
Expand Down
1 change: 1 addition & 0 deletions library/core/src/const_closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub(crate) struct ConstFnMutClosure<CapturedData, Function> {
/// The Function of the Closure, must be: Fn(CapturedData, ClosureArgs) -> ClosureReturn
pub func: Function,
}

impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData, Function> {
/// Function for creating a new closure.
///
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/array_chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ where
I: Iterator,
{
#[track_caller]
pub(in crate::iter) fn new(iter: I) -> Self {
pub(in crate::iter) const fn new(iter: I) -> Self {
assert!(N != 0, "chunk size must be non-zero");
Self { iter, remainder: None }
}
Expand Down
25 changes: 15 additions & 10 deletions library/core/src/iter/adapters/by_ref_sized.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{
const_closure::ConstFnMutClosure,
ops::{NeverShortCircuit, Try},
};
use crate::const_closure::ConstFnMutClosure;
use crate::marker::Destruct;
use crate::ops::{NeverShortCircuit, Try};

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

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

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

#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), usize>
where
I::Item: ~const Destruct,
{
I::advance_by(self.0, n)
}

#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
fn nth(&mut self, n: usize) -> Option<Self::Item>
where
I::Item: ~const Destruct,
{
I::nth(self.0, n)
}

#[inline]
fn fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
F: ~const FnMut(B, Self::Item) -> B + ~const Destruct,
{
// `fold` needs ownership, so this can't forward directly.
I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
Expand All @@ -51,8 +56,8 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
#[inline]
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
F: ~const FnMut(B, Self::Item) -> R + ~const Destruct,
R: ~const Try<Output = B>,
{
I::try_fold(self.0, init, f)
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub struct Chain<A, B> {
b: Option<B>,
}
impl<A, B> Chain<A, B> {
pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
pub(in super::super) const fn new(a: A, b: B) -> Chain<A, B> {
Chain { a: Some(a), b: Some(b) }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/cloned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Cloned<I> {
}

impl<I> Cloned<I> {
pub(in crate::iter) fn new(it: I) -> Cloned<I> {
pub(in crate::iter) const fn new(it: I) -> Cloned<I> {
Cloned { it }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/copied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Copied<I> {
}

impl<I> Copied<I> {
pub(in crate::iter) fn new(it: I) -> Copied<I> {
pub(in crate::iter) const fn new(it: I) -> Copied<I> {
Copied { it }
}
}
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/iter/adapters/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub struct Cycle<I> {
iter: I,
}

impl<I: Clone> Cycle<I> {
pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
impl<I: ~const Clone> Cycle<I> {
pub(in crate::iter) const fn new(iter: I) -> Cycle<I> {
Cycle { orig: iter.clone(), iter }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/enumerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Enumerate<I> {
count: usize,
}
impl<I> Enumerate<I> {
pub(in crate::iter) fn new(iter: I) -> Enumerate<I> {
pub(in crate::iter) const fn new(iter: I) -> Enumerate<I> {
Enumerate { iter, count: 0 }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct Filter<I, P> {
predicate: P,
}
impl<I, P> Filter<I, P> {
pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter<I, P> {
pub(in crate::iter) const fn new(iter: I, predicate: P) -> Filter<I, P> {
Filter { iter, predicate }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/filter_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct FilterMap<I, F> {
f: F,
}
impl<I, F> FilterMap<I, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap<I, F> {
pub(in crate::iter) const fn new(iter: I, f: F) -> FilterMap<I, F> {
FilterMap { iter, f }
}
}
Expand Down
Loading