-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Add std/core::iter::repeat_with #48156
Changes from all commits
0f789aa
c4099ca
1af9ee1
f025eff
55c669c
efa3320
9cee79a
91a4b90
db13296
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,12 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {} | |
/// | ||
/// [`take`]: trait.Iterator.html#method.take | ||
/// | ||
/// If the element type of the iterator you need does not implement `Clone`, | ||
/// or if you do not want to keep the repeated element in memory, you can | ||
/// instead use the [`repeat_with`] function. | ||
/// | ||
/// [`repeat_with`]: fn.repeat_with.html | ||
/// | ||
/// # Examples | ||
/// | ||
/// Basic usage: | ||
|
@@ -99,6 +105,115 @@ pub fn repeat<T: Clone>(elt: T) -> Repeat<T> { | |
Repeat{element: elt} | ||
} | ||
|
||
/// An iterator that repeats elements of type `A` endlessly by | ||
/// applying the provided closure `F: FnMut() -> A`. | ||
/// | ||
/// This `struct` is created by the [`repeat_with`] function. | ||
/// See its documentation for more. | ||
/// | ||
/// [`repeat_with`]: fn.repeat_with.html | ||
#[derive(Copy, Clone, Debug)] | ||
#[unstable(feature = "iterator_repeat_with", issue = "48169")] | ||
pub struct RepeatWith<F> { | ||
repeater: F | ||
} | ||
|
||
#[unstable(feature = "iterator_repeat_with", issue = "48169")] | ||
impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> { | ||
type Item = A; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<A> { Some((self.repeater)()) } | ||
|
||
#[inline] | ||
fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) } | ||
} | ||
|
||
#[unstable(feature = "iterator_repeat_with", issue = "48169")] | ||
impl<A, F: FnMut() -> A> DoubleEndedIterator for RepeatWith<F> { | ||
#[inline] | ||
fn next_back(&mut self) -> Option<A> { self.next() } | ||
} | ||
|
||
#[unstable(feature = "fused", issue = "35602")] | ||
impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {} | ||
|
||
#[unstable(feature = "trusted_len", issue = "37572")] | ||
unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {} | ||
|
||
/// Creates a new iterator that repeats elements of type `A` endlessly by | ||
/// applying the provided closure, the repeater, `F: FnMut() -> A`. | ||
/// | ||
/// The `repeat_with()` function calls the repeater over and over and over and | ||
/// over and over and 🔁. | ||
/// | ||
/// Infinite iterators like `repeat_with()` are often used with adapters like | ||
/// [`take`], in order to make them finite. | ||
/// | ||
/// [`take`]: trait.Iterator.html#method.take | ||
/// | ||
/// If the element type of the iterator you need implements `Clone`, and | ||
/// it is OK to keep the source element in memory, you should instead use | ||
/// the [`repeat`] function. | ||
/// | ||
/// [`repeat`]: fn.repeat.html | ||
/// | ||
/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. | ||
/// It is important to not that reversing `repeat_with(f)` will produce | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that not should be a note instead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in #48282. |
||
/// the exact same sequence as the non-reversed iterator. In other words, | ||
/// `repeat_with(f).rev().collect::<Vec<_>>()` is equivalent to | ||
/// `repeat_with(f).collect::<Vec<_>>()`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// Basic usage: | ||
/// | ||
/// ``` | ||
/// #![feature(iterator_repeat_with)] | ||
/// | ||
/// use std::iter; | ||
/// | ||
/// // let's assume we have some value of a type that is not `Clone` | ||
/// // or which don't want to have in memory just yet because it is expensive: | ||
/// #[derive(PartialEq, Debug)] | ||
/// struct Expensive; | ||
/// | ||
/// // a particular value forever: | ||
/// let mut things = iter::repeat_with(|| Expensive); | ||
/// | ||
/// assert_eq!(Some(Expensive), things.next()); | ||
/// assert_eq!(Some(Expensive), things.next()); | ||
/// assert_eq!(Some(Expensive), things.next()); | ||
/// assert_eq!(Some(Expensive), things.next()); | ||
/// assert_eq!(Some(Expensive), things.next()); | ||
/// ``` | ||
/// | ||
/// Using mutation and going finite: | ||
/// | ||
/// ```rust | ||
/// #![feature(iterator_repeat_with)] | ||
/// | ||
/// use std::iter; | ||
/// | ||
/// // From the zeroth to the third power of two: | ||
/// let mut curr = 1; | ||
/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) | ||
/// .take(4); | ||
/// | ||
/// assert_eq!(Some(1), pow2.next()); | ||
/// assert_eq!(Some(2), pow2.next()); | ||
/// assert_eq!(Some(4), pow2.next()); | ||
/// assert_eq!(Some(8), pow2.next()); | ||
/// | ||
/// // ... and now we're done | ||
/// assert_eq!(None, pow2.next()); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "iterator_repeat_with", issue = "48169")] | ||
pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> { | ||
RepeatWith { repeater } | ||
} | ||
|
||
/// An iterator that yields nothing. | ||
/// | ||
/// This `struct` is created by the [`empty`] function. See its documentation for more. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1549,6 +1549,51 @@ fn test_repeat_take_collect() { | |
assert_eq!(v, vec![42, 42, 42]); | ||
} | ||
|
||
#[test] | ||
fn test_repeat_with() { | ||
#[derive(PartialEq, Debug)] | ||
struct NotClone(usize); | ||
let mut it = repeat_with(|| NotClone(42)); | ||
assert_eq!(it.next(), Some(NotClone(42))); | ||
assert_eq!(it.next(), Some(NotClone(42))); | ||
assert_eq!(it.next(), Some(NotClone(42))); | ||
assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); | ||
} | ||
|
||
#[test] | ||
fn test_repeat_with_rev() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This behaviour is surprising to me, since it produces the same sequence of different things with or without the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I agree. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's consistent with map this way... No big opinion but I'd vote to keep it double ended with FnMut There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bluss I guess that works too if we document it well... I don't have a big opinion either. |
||
let mut curr = 1; | ||
let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) | ||
.rev().take(4); | ||
assert_eq!(pow2.next(), Some(1)); | ||
assert_eq!(pow2.next(), Some(2)); | ||
assert_eq!(pow2.next(), Some(4)); | ||
assert_eq!(pow2.next(), Some(8)); | ||
assert_eq!(pow2.next(), None); | ||
} | ||
|
||
#[test] | ||
fn test_repeat_with_take() { | ||
let mut it = repeat_with(|| 42).take(3); | ||
assert_eq!(it.next(), Some(42)); | ||
assert_eq!(it.next(), Some(42)); | ||
assert_eq!(it.next(), Some(42)); | ||
assert_eq!(it.next(), None); | ||
is_trusted_len(repeat_with(|| 42).take(3)); | ||
assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); | ||
assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); | ||
assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), | ||
(usize::MAX, Some(usize::MAX))); | ||
} | ||
|
||
#[test] | ||
fn test_repeat_with_take_collect() { | ||
let mut curr = 1; | ||
let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) | ||
.take(5).collect(); | ||
assert_eq!(v, vec![1, 2, 4, 8, 16]); | ||
} | ||
|
||
#[test] | ||
fn test_fuse() { | ||
let mut it = 0..3; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessary that we mention it, but another case is indeed to emit a different value each time the function is called, for example (stolen from itertools so it uses while_some() as well):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty neat example - let's have
.while_some()
in core?Edit: we could also have a
while_some(..)
source? so that you can write:I think
while_some
is a pretty descriptive name as source as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully there's a
Try
version that can go well with Option and Result and friends, or perhaps a more fundamental adapter too. Possibly-related: #45594 (comment)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scottmcm Perhaps
Try<Ok = Elt, Error: Into<()>>
?