Skip to content

Make it possible to have const impls for Iterator #92433

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

Closed
wants to merge 5 commits into from
Closed
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
16 changes: 14 additions & 2 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
@@ -1192,7 +1192,13 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
pub const fn min_by<T, F>(v1: T, v2: T, compare: F) -> T
where
F: ~const FnOnce(&T, &T) -> Ordering,
F: ~const Drop,
T: ~const Drop,
{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v1,
Ordering::Greater => v2,
@@ -1255,7 +1261,13 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
pub const fn max_by<T, F>(v1: T, v2: T, compare: F) -> T
where
F: ~const FnOnce(&T, &T) -> Ordering,
F: ~const Drop,
T: ~const Drop,
{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v2,
Ordering::Greater => v1,
49 changes: 49 additions & 0 deletions library/core/src/internal_macros.rs
Original file line number Diff line number Diff line change
@@ -187,3 +187,52 @@ macro_rules! impl_fn_for_zst {
)+
}
}

macro_rules! impl_const_closure {
(
impl$(<$( $tt : tt ),*>)?
const FnOnce for $Name: path $(where $($WhereTy:ty : $(~ $const:ident)? $Trait:path),+ $(,)?)? =
$(#[$meta:meta])*
|$mutorself:ident $($self:ident)?, $( $arg: tt: $ArgTy: ty ),*| $(-> $ReturnTy: ty)?
$body: block;
) => {
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl $( < $( $tt ),* > )? const FnOnce<($( $ArgTy, )*)> for $Name
$(where $($WhereTy: $(~$const)? $Trait),+)?
{
#[allow(unused_parens)]
type Output = ( $( $ReturnTy )? );

#[allow(unused_mut)]
$(#[$meta])*
extern "rust-call" fn call_once($mutorself $($self)?, ($( $arg, )*): ($( $ArgTy, )*)) -> Self::Output {
$body
}
}
};
(
impl$(< $( $tt: tt ),* >)?
const FnMut for $Name: path $(where $($WhereTy:ty : $(~ $const:ident)? $Trait:path),+ $(,)?)? =
$(#[$meta:meta])*
|&mut $self:ident, $( $arg: tt: $ArgTy: ty ),*| $(-> $ReturnTy: ty)?
$body: block;
) => {
impl_const_closure! {
impl$(< $( $tt ),* >)?
const FnOnce for $Name $(where $($WhereTy: $(~$const)? $Trait),+)? =
$(#[$meta])*
|mut $self, $( $arg: $ArgTy),*| $(-> $ReturnTy)?
$body;
}
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl $( < $( $tt ),* > )? const FnMut<($( $ArgTy, )*)> for $Name
$(where $($WhereTy: $(~$const)? $Trait),+)?
{
$(#[$meta])*
#[allow(unused_parens)]
extern "rust-call" fn call_mut(&mut $self, ($( $arg, )*): ($( $ArgTy, )*)) -> ( $($ReturnTy)? ) {
$body
}
}
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/chain.rs
Original file line number Diff line number Diff line change
@@ -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) }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/cloned.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/copied.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,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 }
}
}
8 changes: 6 additions & 2 deletions library/core/src/iter/adapters/cycle.rs
Original file line number Diff line number Diff line change
@@ -15,8 +15,12 @@ pub struct Cycle<I> {
iter: I,
}

impl<I: Clone> Cycle<I> {
pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
impl<I> Cycle<I> {
#[rustc_const_unstable(feature = "iter_internals", issue = "none")]
pub(in crate::iter) const fn new(iter: I) -> Cycle<I>
where
I: ~const Clone,
{
Cycle { orig: iter.clone(), iter }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/enumerate.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/filter.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/filter_map.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
}
17 changes: 8 additions & 9 deletions library/core/src/iter/adapters/flatten.rs
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ pub struct FlatMap<I, U: IntoIterator, F> {
}

impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
FlatMap { inner: FlattenCompat::new(iter.map(f)) }
#[rustc_const_unstable(feature = "iter_internals", issue = "none")]
pub(in crate::iter) const fn new(iter: I, f: F) -> FlatMap<I, U, F> {
FlatMap { inner: FlattenCompat::new(Map::new(iter, f)) }
}
}

@@ -152,7 +153,8 @@ pub struct Flatten<I: Iterator<Item: IntoIterator>> {
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
pub(in super::super) fn new(iter: I) -> Flatten<I> {
#[rustc_const_unstable(feature = "iter_internals", issue = "none")]
pub(in super::super) const fn new(iter: I) -> Flatten<I> {
Flatten { inner: FlattenCompat::new(iter) }
}
}
@@ -270,13 +272,10 @@ struct FlattenCompat<I, U> {
frontiter: Option<U>,
backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U>
where
I: Iterator,
{
impl<I, U> FlattenCompat<I, U> {
/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
fn new(iter: I) -> FlattenCompat<I, U> {
FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None }
const fn new(iter: I) -> FlattenCompat<I, U> {
FlattenCompat { iter: super::Fuse::new(iter), frontiter: None, backiter: None }
}
}

2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/fuse.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ pub struct Fuse<I> {
iter: Option<I>,
}
impl<I> Fuse<I> {
pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
pub(in crate::iter) const fn new(iter: I) -> Fuse<I> {
Fuse { iter: Some(iter) }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/inspect.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ pub struct Inspect<I, F> {
f: F,
}
impl<I, F> Inspect<I, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> Inspect<I, F> {
pub(in crate::iter) const fn new(iter: I, f: F) -> Inspect<I, F> {
Inspect { iter, f }
}
}
10 changes: 6 additions & 4 deletions library/core/src/iter/adapters/intersperse.rs
Original file line number Diff line number Diff line change
@@ -19,8 +19,9 @@ impl<I: Iterator> Intersperse<I>
where
I::Item: Clone,
{
pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
Self { iter: iter.peekable(), separator, needs_sep: false }
#[rustc_const_unstable(feature = "iter_internals", issue = "none")]
pub(in crate::iter) const fn new(iter: I, separator: I::Item) -> Self {
Self { iter: Peekable::new(iter), separator, needs_sep: false }
}
}

@@ -108,8 +109,9 @@ where
I: Iterator,
G: FnMut() -> I::Item,
{
pub(in crate::iter) fn new(iter: I, separator: G) -> Self {
Self { iter: iter.peekable(), separator, needs_sep: false }
#[rustc_const_unstable(feature = "iter_internals", issue = "none")]
pub(in crate::iter) const fn new(iter: I, separator: G) -> Self {
Self { iter: Peekable::new(iter), separator, needs_sep: false }
}
}

50 changes: 41 additions & 9 deletions library/core/src/iter/adapters/map.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ use crate::iter::adapters::{
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;
use crate::ops::{FromResidual, Try};

/// An iterator that maps the values of `iter` with `f`.
///
@@ -65,7 +65,7 @@ pub struct Map<I, F> {
}

impl<I, F> Map<I, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> Map<I, F> {
pub(in crate::iter) const fn new(iter: I, f: F) -> Map<I, F> {
Map { iter, f }
}
}
@@ -77,6 +77,33 @@ impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
}
}

struct MapFold<F, G>(F, G);
struct MapTryFold<F, G>(F, G);

impl_const_closure! {
impl<F, T, B, G, Acc> const FnMut for MapFold<F, G>
where
F: ~const FnMut(T) -> B,
F: ~const Drop,
G: ~const FnMut(Acc, B) -> Acc,
G: ~const Drop,
= |&mut self, acc: Acc, elt: T| -> Acc {
self.1(acc, self.0(elt))
};
}

impl_const_closure! {
impl<F, T, B, G, R, Acc> const FnMut for MapTryFold<F, G>
where
F: ~const FnMut(T) -> B,
F: ~const Drop,
G: ~const FnMut(Acc, B) -> R,
G: ~const Drop,
= |&mut self, acc: Acc, elt: T| -> R {
self.1(acc, self.0(elt))
};
}

fn map_fold<T, B, Acc>(
mut f: impl FnMut(T) -> B,
mut g: impl FnMut(Acc, B) -> Acc,
@@ -92,9 +119,10 @@ fn map_try_fold<'a, T, B, Acc, R>(
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: Iterator, F> Iterator for Map<I, F>
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
impl<B, I: ~const Iterator, F> const Iterator for Map<I, F>
where
F: FnMut(I::Item) -> B,
F: ~const FnMut(I::Item) -> B + ~const Drop,
{
type Item = B;

@@ -111,17 +139,21 @@ where
fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
where
Self: Sized,
G: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>,
G: ~const FnMut(Acc, B) -> R,
G: ~const Drop,
R: ~const Try<Output = Acc>,
R: ~const FromResidual,
{
self.iter.try_fold(init, map_try_fold(&mut self.f, g))
self.iter.try_fold(init, MapTryFold(&mut self.f, g))
}

fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
where
G: FnMut(Acc, Self::Item) -> Acc,
I: ~const Drop,
G: ~const FnMut(Acc, B) -> Acc,
G: ~const Drop,
{
self.iter.fold(init, map_fold(self.f, g))
self.iter.fold(init, MapFold(self.f, g))
}

#[doc(hidden)]
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/map_while.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ pub struct MapWhile<I, P> {
}

impl<I, P> MapWhile<I, P> {
pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
pub(in crate::iter) const fn new(iter: I, predicate: P) -> MapWhile<I, P> {
MapWhile { iter, predicate }
}
}
3 changes: 2 additions & 1 deletion library/core/src/iter/adapters/peekable.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,8 @@ pub struct Peekable<I: Iterator> {
}

impl<I: Iterator> Peekable<I> {
pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
#[rustc_allow_const_fn_unstable(const_fn_trait_bound)]
pub(in crate::iter) const fn new(iter: I) -> Peekable<I> {
Peekable { iter, peeked: None }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/rev.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ pub struct Rev<T> {
}

impl<T> Rev<T> {
pub(in crate::iter) fn new(iter: T) -> Rev<T> {
pub(in crate::iter) const fn new(iter: T) -> Rev<T> {
Rev { iter }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/scan.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ pub struct Scan<I, St, F> {
}

impl<I, St, F> Scan<I, St, F> {
pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
pub(in crate::iter) const fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
Scan { iter, state, f }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/skip.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ pub struct Skip<I> {
}

impl<I> Skip<I> {
pub(in crate::iter) fn new(iter: I, n: usize) -> Skip<I> {
pub(in crate::iter) const fn new(iter: I, n: usize) -> Skip<I> {
Skip { iter, n }
}
}
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/skip_while.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ pub struct SkipWhile<I, P> {
}

impl<I, P> SkipWhile<I, P> {
pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
pub(in crate::iter) const fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
SkipWhile { iter, flag: false, predicate }
}
}
5 changes: 3 additions & 2 deletions library/core/src/iter/adapters/step_by.rs
Original file line number Diff line number Diff line change
@@ -17,8 +17,9 @@ pub struct StepBy<I> {
}

impl<I> StepBy<I> {
pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> {
assert!(step != 0);
#[rustc_const_unstable(feature = "iter_internals", issue = "none")]
pub(in crate::iter) const fn new(iter: I, step: usize) -> StepBy<I> {
assert!(step != 0, "Step must be non-zero");
StepBy { iter, step: step - 1, first_take: true }
}
}
Loading