Skip to content

Rollup of 10 pull requests #79319

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

Merged
merged 25 commits into from
Nov 23, 2020
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b813c72
Clean up `StructuralEq` docs
camelid Nov 6, 2020
0f005c2
BTreeMap: address namespace conflicts
ssomers Nov 5, 2020
773b73c
Split iterator adaptors into individual modules
WaffleLapkin Oct 7, 2020
66d6708
Split iterator sources into different modules
WaffleLapkin Oct 7, 2020
b82a76a
Merge `use`s in core::iter
WaffleLapkin Oct 7, 2020
0dc187c
Fix doc links in core::iter::sources
WaffleLapkin Oct 8, 2020
e0e906b
Fix UI tests
WaffleLapkin Oct 8, 2020
4612658
Remove multiline `use`s
WaffleLapkin Oct 8, 2020
b6f9705
Add test for eval order for a+=b
Havvy Nov 22, 2020
9186c07
BTreeMap: fix minor testing mistakes in #78903
ssomers Nov 22, 2020
b04abc4
BTreeMap: swap the names of NodeRef::new and Root::new_leaf
ssomers Nov 22, 2020
cf32afc
Stabilise `then`
varkor Nov 22, 2020
5c6689b
Stabilize refcell_take
ThinkChaos Oct 31, 2020
cf26f2f
Add f{32,64}::is_subnormal
clarfonthey Sep 19, 2020
9050d12
Stabilize `alloc::Layout const` functions
ChrisDenton Nov 22, 2020
9b98f1d
Rollup merge of #76941 - clarfonthey:is_subnormal, r=m-ou-se
m-ou-se Nov 22, 2020
4407049
Rollup merge of #77697 - WaffleLapkin:iter_split_adaptors, r=m-ou-se
m-ou-se Nov 22, 2020
186ec64
Rollup merge of #78305 - ChrisDenton:const-layout, r=oli-obk
m-ou-se Nov 22, 2020
b249844
Rollup merge of #78608 - ThinkChaos:stabilize_refcell_take, r=m-ou-se
m-ou-se Nov 22, 2020
8a623e6
Rollup merge of #78793 - camelid:fixup-structuraleq, r=jyn514
m-ou-se Nov 22, 2020
5793fa9
Rollup merge of #79267 - ssomers:btree_namespaces, r=Mark-Simulacrum
m-ou-se Nov 22, 2020
138845d
Rollup merge of #79293 - Havvy:test-eval-order-compound-assign, r=Mar…
m-ou-se Nov 22, 2020
b54838f
Rollup merge of #79295 - ssomers:btree_fix_78903, r=Mark-Simulacrum
m-ou-se Nov 22, 2020
d39e095
Rollup merge of #79297 - ssomers:btree_post_redux, r=Mark-Simulacrum
m-ou-se Nov 22, 2020
41c033b
Rollup merge of #79299 - varkor:stabilise-then, r=m-ou-se
m-ou-se Nov 22, 2020
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
1 change: 0 additions & 1 deletion compiler/rustc_index/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(allow_internal_unstable)]
#![feature(bool_to_option)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
1 change: 0 additions & 1 deletion compiler/rustc_metadata/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
1 change: 0 additions & 1 deletion compiler/rustc_parse/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! The main parser interface.

#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(bindings_after_at)]
#![feature(iter_order_by)]
2 changes: 1 addition & 1 deletion library/alloc/src/collections/btree/append.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ impl<K, V> Root<K, V> {

// Push key-value pair and new right subtree.
let tree_height = open_node.height() - 1;
let mut right_tree = Root::new_leaf();
let mut right_tree = Root::new();
for _ in 0..tree_height {
right_tree.push_internal_level();
}
16 changes: 8 additions & 8 deletions library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use core::ops::{Index, RangeBounds};
use core::ptr;

use super::borrow::DormantMutRef;
use super::node::{self, marker, ForceResult::*, Handle, NodeRef};
use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
use super::search::{self, SearchResult::*};
use super::unwrap_unchecked;

@@ -128,7 +128,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BTreeMap<K, V> {
root: Option<node::Root<K, V>>,
root: Option<Root<K, V>>,
length: usize,
}

@@ -145,15 +145,15 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap<K, V> {
impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
fn clone(&self) -> BTreeMap<K, V> {
fn clone_subtree<'a, K: Clone, V: Clone>(
node: node::NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>,
node: NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>,
) -> BTreeMap<K, V>
where
K: 'a,
V: 'a,
{
match node.force() {
Leaf(leaf) => {
let mut out_tree = BTreeMap { root: Some(node::Root::new_leaf()), length: 0 };
let mut out_tree = BTreeMap { root: Some(Root::new()), length: 0 };

{
let root = out_tree.root.as_mut().unwrap(); // unwrap succeeds because we just wrapped
@@ -198,7 +198,7 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
(root, length)
};

out_node.push(k, v, subroot.unwrap_or_else(node::Root::new_leaf));
out_node.push(k, v, subroot.unwrap_or_else(Root::new));
out_tree.length += 1 + sublength;
}
}
@@ -1558,7 +1558,7 @@ pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
length: &'a mut usize,
/// Burried reference to the root field in the borrowed map.
/// Wrapped in `Option` to allow drop handler to `take` it.
dormant_root: Option<DormantMutRef<'a, node::Root<K, V>>>,
dormant_root: Option<DormantMutRef<'a, Root<K, V>>>,
/// Contains a leaf edge preceding the next element to be returned, or the last leaf edge.
/// Empty if the map has no root, if iteration went beyond the last leaf edge,
/// or if a panic occurred in the predicate.
@@ -2160,8 +2160,8 @@ impl<K, V> BTreeMap<K, V> {

/// If the root node is the empty (non-allocated) root node, allocate our
/// own node. Is an associated function to avoid borrowing the entire BTreeMap.
fn ensure_is_owned(root: &mut Option<node::Root<K, V>>) -> &mut node::Root<K, V> {
root.get_or_insert_with(node::Root::new_leaf)
fn ensure_is_owned(root: &mut Option<Root<K, V>>) -> &mut Root<K, V> {
root.get_or_insert_with(Root::new)
}
}

71 changes: 32 additions & 39 deletions library/alloc/src/collections/btree/map/tests.rs
Original file line number Diff line number Diff line change
@@ -6,13 +6,14 @@ use crate::fmt::Debug;
use crate::rc::Rc;
use crate::string::{String, ToString};
use crate::vec::Vec;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::iter::{self, FromIterator};
use std::mem;
use std::ops::Bound::{self, Excluded, Included, Unbounded};
use std::ops::RangeBounds;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};

mod ord_chaos;
use ord_chaos::{Cyclic3, Governed, Governor};
@@ -56,24 +57,23 @@ impl<K, V> BTreeMap<K, V> {
assert!(root_node.ascend().is_err());
root_node.assert_back_pointers();

// Check consistenty of `length` and some of the navigation.
// Check consistency of `length` with what navigation code encounters.
assert_eq!(self.length, root_node.calc_length());
assert_eq!(self.length, self.keys().count());

// Lastly, check the invariant causing the least harm.
root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
} else {
// Check consistenty of `length` and some of the navigation.
assert_eq!(self.length, 0);
assert_eq!(self.length, self.keys().count());
}

// Check that `assert_strictly_ascending` will encounter all keys.
assert_eq!(self.length, self.keys().count());
}

// Panics if the map is corrupted or if the keys are not in strictly
// ascending order, in the current opinion of the `Ord` implementation.
// If the `Ord` implementation does not honor transitivity, this method
// does not guarantee that all the keys are unique, just that adjacent
// keys are unique.
// If the `Ord` implementation violates transitivity, this method does not
// guarantee that all keys are unique, just that adjacent keys are unique.
fn check(&self)
where
K: Debug + Ord,
@@ -879,6 +879,7 @@ mod test_drain_filter {
map.check();
}

// Explicitly consumes the iterator, where most test cases drop it instantly.
#[test]
fn consumed_keeping_all() {
let pairs = (0..3).map(|i| (i, i));
@@ -887,6 +888,7 @@ mod test_drain_filter {
map.check();
}

// Explicitly consumes the iterator, where most test cases drop it instantly.
#[test]
fn consumed_removing_all() {
let pairs = (0..3).map(|i| (i, i));
@@ -896,15 +898,7 @@ mod test_drain_filter {
map.check();
}

#[test]
fn dropped_removing_all() {
let pairs = (0..3).map(|i| (i, i));
let mut map: BTreeMap<_, _> = pairs.collect();
map.drain_filter(|_, _| true);
assert!(map.is_empty());
map.check();
}

// Explicitly consumes the iterator and modifies values through it.
#[test]
fn mutating_and_keeping() {
let pairs = (0..3).map(|i| (i, i));
@@ -921,6 +915,7 @@ mod test_drain_filter {
map.check();
}

// Explicitly consumes the iterator and modifies values through it.
#[test]
fn mutating_and_removing() {
let pairs = (0..3).map(|i| (i, i));
@@ -1094,7 +1089,7 @@ mod test_drain_filter {
struct D;
impl Drop for D {
fn drop(&mut self) {
if DROPS.fetch_add(1, Ordering::SeqCst) == 1 {
if DROPS.fetch_add(1, SeqCst) == 1 {
panic!("panic in `drop`");
}
}
@@ -1105,14 +1100,14 @@ mod test_drain_filter {

catch_unwind(move || {
drop(map.drain_filter(|i, _| {
PREDS.fetch_add(1usize << i, Ordering::SeqCst);
PREDS.fetch_add(1usize << i, SeqCst);
true
}))
})
.unwrap_err();

assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
assert_eq!(PREDS.load(SeqCst), 0x011);
assert_eq!(DROPS.load(SeqCst), 3);
}

#[test]
@@ -1123,7 +1118,7 @@ mod test_drain_filter {
struct D;
impl Drop for D {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::SeqCst);
DROPS.fetch_add(1, SeqCst);
}
}

@@ -1132,7 +1127,7 @@ mod test_drain_filter {

catch_unwind(AssertUnwindSafe(|| {
drop(map.drain_filter(|i, _| {
PREDS.fetch_add(1usize << i, Ordering::SeqCst);
PREDS.fetch_add(1usize << i, SeqCst);
match i {
0 => true,
_ => panic!(),
@@ -1141,8 +1136,8 @@ mod test_drain_filter {
}))
.unwrap_err();

assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
assert_eq!(PREDS.load(SeqCst), 0x011);
assert_eq!(DROPS.load(SeqCst), 1);
assert_eq!(map.len(), 2);
assert_eq!(map.first_entry().unwrap().key(), &4);
assert_eq!(map.last_entry().unwrap().key(), &8);
@@ -1158,7 +1153,7 @@ mod test_drain_filter {
struct D;
impl Drop for D {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::SeqCst);
DROPS.fetch_add(1, SeqCst);
}
}

@@ -1167,7 +1162,7 @@ mod test_drain_filter {

{
let mut it = map.drain_filter(|i, _| {
PREDS.fetch_add(1usize << i, Ordering::SeqCst);
PREDS.fetch_add(1usize << i, SeqCst);
match i {
0 => true,
_ => panic!(),
@@ -1180,8 +1175,8 @@ mod test_drain_filter {
assert!(matches!(result, Ok(None)));
}

assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
assert_eq!(PREDS.load(SeqCst), 0x011);
assert_eq!(DROPS.load(SeqCst), 1);
assert_eq!(map.len(), 2);
assert_eq!(map.first_entry().unwrap().key(), &4);
assert_eq!(map.last_entry().unwrap().key(), &8);
@@ -1315,8 +1310,6 @@ fn test_zst() {
// undefined.
#[test]
fn test_bad_zst() {
use std::cmp::Ordering;

#[derive(Clone, Copy, Debug)]
struct Bad;

@@ -1763,7 +1756,7 @@ fn test_append_drop_leak() {

impl Drop for D {
fn drop(&mut self) {
if DROPS.fetch_add(1, Ordering::SeqCst) == 0 {
if DROPS.fetch_add(1, SeqCst) == 0 {
panic!("panic in `drop`");
}
}
@@ -1779,7 +1772,7 @@ fn test_append_drop_leak() {

catch_unwind(move || left.append(&mut right)).unwrap_err();

assert_eq!(DROPS.load(Ordering::SeqCst), 4); // Rust issue #47949 ate one little piggy
assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy
}

#[test]
@@ -1894,7 +1887,7 @@ fn test_into_iter_drop_leak_height_0() {

impl Drop for D {
fn drop(&mut self) {
if DROPS.fetch_add(1, Ordering::SeqCst) == 3 {
if DROPS.fetch_add(1, SeqCst) == 3 {
panic!("panic in `drop`");
}
}
@@ -1909,7 +1902,7 @@ fn test_into_iter_drop_leak_height_0() {

catch_unwind(move || drop(map.into_iter())).unwrap_err();

assert_eq!(DROPS.load(Ordering::SeqCst), 5);
assert_eq!(DROPS.load(SeqCst), 5);
}

#[test]
@@ -1921,18 +1914,18 @@ fn test_into_iter_drop_leak_height_1() {
struct D;
impl Drop for D {
fn drop(&mut self) {
if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) {
if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) {
panic!("panic in `drop`");
}
}
}

for panic_point in vec![0, 1, size - 2, size - 1] {
DROPS.store(0, Ordering::SeqCst);
PANIC_POINT.store(panic_point, Ordering::SeqCst);
DROPS.store(0, SeqCst);
PANIC_POINT.store(panic_point, SeqCst);
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
catch_unwind(move || drop(map.into_iter())).unwrap_err();
assert_eq!(DROPS.load(Ordering::SeqCst), size);
assert_eq!(DROPS.load(SeqCst), size);
}
}

5 changes: 5 additions & 0 deletions library/alloc/src/collections/btree/map/tests/ord_chaos.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ use std::cell::Cell;
use std::cmp::Ordering::{self, *};
use std::ptr;

// Minimal type with an `Ord` implementation violating transitivity.
#[derive(Debug)]
pub enum Cyclic3 {
A,
@@ -34,6 +35,7 @@ impl PartialEq for Cyclic3 {

impl Eq for Cyclic3 {}

// Controls the ordering of values wrapped by `Governed`.
#[derive(Debug)]
pub struct Governor {
flipped: Cell<bool>,
@@ -49,6 +51,9 @@ impl Governor {
}
}

// Type with an `Ord` implementation that forms a total order at any moment
// (assuming that `T` respects total order), but can suddenly be made to invert
// that total order.
#[derive(Debug)]
pub struct Governed<'a, T>(pub T, pub &'a Governor);

6 changes: 3 additions & 3 deletions library/alloc/src/collections/btree/node.rs
Original file line number Diff line number Diff line change
@@ -134,13 +134,13 @@ pub type Root<K, V> = NodeRef<marker::Owned, K, V, marker::LeafOrInternal>;

impl<K, V> Root<K, V> {
/// Returns a new owned tree, with its own root node that is initially empty.
pub fn new_leaf() -> Self {
NodeRef::new().forget_type()
pub fn new() -> Self {
NodeRef::new_leaf().forget_type()
}
}

impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
fn new() -> Self {
fn new_leaf() -> Self {
Self::from_new_leaf(Box::new(unsafe { LeafNode::new() }))
}

4 changes: 2 additions & 2 deletions library/alloc/src/collections/btree/node/tests.rs
Original file line number Diff line number Diff line change
@@ -74,12 +74,12 @@ fn test_splitpoint() {

#[test]
fn test_partial_cmp_eq() {
let mut root1 = NodeRef::new();
let mut root1 = NodeRef::new_leaf();
let mut leaf1 = root1.borrow_mut();
leaf1.push(1, ());
let mut root1 = root1.forget_type();
root1.push_internal_level();
let root2 = Root::new_leaf();
let root2 = Root::new();
root1.reborrow().assert_back_pointers();
root2.reborrow().assert_back_pointers();

2 changes: 1 addition & 1 deletion library/alloc/src/collections/btree/search.rs
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ where
{
match search_linear(&node, key) {
(idx, true) => Found(unsafe { Handle::new_kv(node, idx) }),
(idx, false) => SearchResult::GoDown(unsafe { Handle::new_edge(node, idx) }),
(idx, false) => GoDown(unsafe { Handle::new_edge(node, idx) }),
}
}

21 changes: 10 additions & 11 deletions library/alloc/src/collections/btree/set/tests.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use super::super::DeterministicRng;
use super::*;
use crate::vec::Vec;
use std::cmp::Ordering;
use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::atomic::{AtomicU32, Ordering::SeqCst};

#[test]
fn test_clone_eq() {
@@ -355,7 +356,7 @@ fn test_drain_filter_drop_panic_leak() {
struct D(i32);
impl Drop for D {
fn drop(&mut self) {
if DROPS.fetch_add(1, Ordering::SeqCst) == 1 {
if DROPS.fetch_add(1, SeqCst) == 1 {
panic!("panic in `drop`");
}
}
@@ -368,14 +369,14 @@ fn test_drain_filter_drop_panic_leak() {

catch_unwind(move || {
drop(set.drain_filter(|d| {
PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst);
PREDS.fetch_add(1u32 << d.0, SeqCst);
true
}))
})
.ok();

assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
assert_eq!(PREDS.load(SeqCst), 0x011);
assert_eq!(DROPS.load(SeqCst), 3);
}

#[test]
@@ -387,7 +388,7 @@ fn test_drain_filter_pred_panic_leak() {
struct D(i32);
impl Drop for D {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::SeqCst);
DROPS.fetch_add(1, SeqCst);
}
}

@@ -398,7 +399,7 @@ fn test_drain_filter_pred_panic_leak() {

catch_unwind(AssertUnwindSafe(|| {
drop(set.drain_filter(|d| {
PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst);
PREDS.fetch_add(1u32 << d.0, SeqCst);
match d.0 {
0 => true,
_ => panic!(),
@@ -407,8 +408,8 @@ fn test_drain_filter_pred_panic_leak() {
}))
.ok();

assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
assert_eq!(PREDS.load(SeqCst), 0x011);
assert_eq!(DROPS.load(SeqCst), 1);
assert_eq!(set.len(), 2);
assert_eq!(set.first().unwrap().0, 4);
assert_eq!(set.last().unwrap().0, 8);
@@ -498,8 +499,6 @@ fn test_extend_ref() {

#[test]
fn test_recovery() {
use std::cmp::Ordering;

#[derive(Debug)]
struct Foo(&'static str, i32);

6 changes: 3 additions & 3 deletions library/core/src/alloc/layout.rs
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ impl Layout {
/// must not overflow (i.e., the rounded value must be less than
/// or equal to `usize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if !align.is_power_of_two() {
@@ -96,15 +96,15 @@ impl Layout {

/// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
pub const fn size(&self) -> usize {
self.size_
}

/// The minimum byte alignment for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
pub const fn align(&self) -> usize {
self.align_.get()
4 changes: 1 addition & 3 deletions library/core/src/bool.rs
Original file line number Diff line number Diff line change
@@ -23,12 +23,10 @@ impl bool {
/// # Examples
///
/// ```
/// #![feature(bool_to_option)]
///
/// assert_eq!(false.then(|| 0), None);
/// assert_eq!(true.then(|| 0), Some(0));
/// ```
#[unstable(feature = "bool_to_option", issue = "64260")]
#[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
#[inline]
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self { Some(f()) } else { None }
3 changes: 1 addition & 2 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
@@ -1027,7 +1027,6 @@ impl<T: Default> RefCell<T> {
/// # Examples
///
/// ```
/// #![feature(refcell_take)]
/// use std::cell::RefCell;
///
/// let c = RefCell::new(5);
@@ -1036,7 +1035,7 @@ impl<T: Default> RefCell<T> {
/// assert_eq!(five, 5);
/// assert_eq!(c.into_inner(), 0);
/// ```
#[unstable(feature = "refcell_take", issue = "71395")]
#[stable(feature = "refcell_take", since = "1.50.0")]
pub fn take(&self) -> T {
self.replace(Default::default())
}
3 changes: 1 addition & 2 deletions library/core/src/iter/adapters/chain.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
use crate::ops::Try;
use crate::usize;
use crate::{ops::Try, usize};

/// An iterator that links two iterators together, in a chain.
///
139 changes: 139 additions & 0 deletions library/core/src/iter/adapters/cloned.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess};
use crate::iter::{FusedIterator, TrustedLen};
use crate::ops::Try;

/// An iterator that clones the elements of an underlying iterator.
///
/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`cloned`]: Iterator::cloned
/// [`Iterator`]: trait.Iterator.html
#[stable(feature = "iter_cloned", since = "1.1.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct Cloned<I> {
it: I,
}

impl<I> Cloned<I> {
pub(in crate::iter) fn new(it: I) -> Cloned<I> {
Cloned { it }
}
}

fn clone_try_fold<T: Clone, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
move |acc, elt| f(acc, elt.clone())
}

#[stable(feature = "iter_cloned", since = "1.1.0")]
impl<'a, I, T: 'a> Iterator for Cloned<I>
where
I: Iterator<Item = &'a T>,
T: Clone,
{
type Item = T;

fn next(&mut self) -> Option<T> {
self.it.next().cloned()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}

fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
self.it.try_fold(init, clone_try_fold(f))
}

fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.it.map(T::clone).fold(init, f)
}

unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
unsafe { try_get_unchecked(&mut self.it, idx).clone() }
}
}

#[stable(feature = "iter_cloned", since = "1.1.0")]
impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
where
I: DoubleEndedIterator<Item = &'a T>,
T: Clone,
{
fn next_back(&mut self) -> Option<T> {
self.it.next_back().cloned()
}

fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
self.it.try_rfold(init, clone_try_fold(f))
}

fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.it.map(T::clone).rfold(init, f)
}
}

#[stable(feature = "iter_cloned", since = "1.1.0")]
impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
where
I: ExactSizeIterator<Item = &'a T>,
T: Clone,
{
fn len(&self) -> usize {
self.it.len()
}

fn is_empty(&self) -> bool {
self.it.is_empty()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<'a, I, T: 'a> FusedIterator for Cloned<I>
where
I: FusedIterator<Item = &'a T>,
T: Clone,
{
}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Cloned<I>
where
I: TrustedRandomAccess,
{
#[inline]
fn may_have_side_effect() -> bool {
true
}
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<'a, I, T: 'a> TrustedLen for Cloned<I>
where
I: TrustedLen<Item = &'a T>,
T: Clone,
{
}
155 changes: 155 additions & 0 deletions library/core/src/iter/adapters/copied.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess};
use crate::iter::{FusedIterator, TrustedLen};
use crate::ops::Try;

/// An iterator that copies the elements of an underlying iterator.
///
/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`copied`]: Iterator::copied
/// [`Iterator`]: trait.Iterator.html
#[stable(feature = "iter_copied", since = "1.36.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct Copied<I> {
it: I,
}

impl<I> Copied<I> {
pub(in crate::iter) fn new(it: I) -> Copied<I> {
Copied { it }
}
}

fn copy_fold<T: Copy, Acc>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc {
move |acc, &elt| f(acc, elt)
}

fn copy_try_fold<T: Copy, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
move |acc, &elt| f(acc, elt)
}

#[stable(feature = "iter_copied", since = "1.36.0")]
impl<'a, I, T: 'a> Iterator for Copied<I>
where
I: Iterator<Item = &'a T>,
T: Copy,
{
type Item = T;

fn next(&mut self) -> Option<T> {
self.it.next().copied()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}

fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
self.it.try_fold(init, copy_try_fold(f))
}

fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.it.fold(init, copy_fold(f))
}

fn nth(&mut self, n: usize) -> Option<T> {
self.it.nth(n).copied()
}

fn last(self) -> Option<T> {
self.it.last().copied()
}

fn count(self) -> usize {
self.it.count()
}

unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
*unsafe { try_get_unchecked(&mut self.it, idx) }
}
}

#[stable(feature = "iter_copied", since = "1.36.0")]
impl<'a, I, T: 'a> DoubleEndedIterator for Copied<I>
where
I: DoubleEndedIterator<Item = &'a T>,
T: Copy,
{
fn next_back(&mut self) -> Option<T> {
self.it.next_back().copied()
}

fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
self.it.try_rfold(init, copy_try_fold(f))
}

fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.it.rfold(init, copy_fold(f))
}
}

#[stable(feature = "iter_copied", since = "1.36.0")]
impl<'a, I, T: 'a> ExactSizeIterator for Copied<I>
where
I: ExactSizeIterator<Item = &'a T>,
T: Copy,
{
fn len(&self) -> usize {
self.it.len()
}

fn is_empty(&self) -> bool {
self.it.is_empty()
}
}

#[stable(feature = "iter_copied", since = "1.36.0")]
impl<'a, I, T: 'a> FusedIterator for Copied<I>
where
I: FusedIterator<Item = &'a T>,
T: Copy,
{
}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Copied<I>
where
I: TrustedRandomAccess,
{
#[inline]
fn may_have_side_effect() -> bool {
I::may_have_side_effect()
}
}

#[stable(feature = "iter_copied", since = "1.36.0")]
unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
where
I: TrustedLen<Item = &'a T>,
T: Copy,
{
}
87 changes: 87 additions & 0 deletions library/core/src/iter/adapters/cycle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::{iter::FusedIterator, ops::Try};

/// An iterator that repeats endlessly.
///
/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`cycle`]: Iterator::cycle
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Cycle<I> {
orig: I,
iter: I,
}

impl<I: Clone> Cycle<I> {
pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
Cycle { orig: iter.clone(), iter }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Cycle<I>
where
I: Clone + Iterator,
{
type Item = <I as Iterator>::Item;

#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
match self.iter.next() {
None => {
self.iter = self.orig.clone();
self.iter.next()
}
y => y,
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
// the cycle iterator is either empty or infinite
match self.orig.size_hint() {
sz @ (0, Some(0)) => sz,
(0, _) => (0, None),
_ => (usize::MAX, None),
}
}

#[inline]
fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
where
F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
// fully iterate the current iterator. this is necessary because
// `self.iter` may be empty even when `self.orig` isn't
acc = self.iter.try_fold(acc, &mut f)?;
self.iter = self.orig.clone();

// complete a full cycle, keeping track of whether the cycled
// iterator is empty or not. we need to return early in case
// of an empty iterator to prevent an infinite loop
let mut is_empty = true;
acc = self.iter.try_fold(acc, |acc, x| {
is_empty = false;
f(acc, x)
})?;

if is_empty {
return try { acc };
}

loop {
self.iter = self.orig.clone();
acc = self.iter.try_fold(acc, &mut f)?;
}
}

// No `fold` override, because `fold` doesn't make much sense for `Cycle`,
// and we can't do anything better than the default.
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
238 changes: 238 additions & 0 deletions library/core/src/iter/adapters/enumerate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::{Add, AddAssign, Try};

/// An iterator that yields the current count and the element during iteration.
///
/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`enumerate`]: Iterator::enumerate
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Enumerate<I> {
iter: I,
count: usize,
}
impl<I> Enumerate<I> {
pub(in crate::iter) fn new(iter: I) -> Enumerate<I> {
Enumerate { iter, count: 0 }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Enumerate<I>
where
I: Iterator,
{
type Item = (usize, <I as Iterator>::Item);

/// # Overflow Behavior
///
/// The method does no guarding against overflows, so enumerating more than
/// `usize::MAX` elements either produces the wrong result or panics. If
/// debug assertions are enabled, a panic is guaranteed.
///
/// # Panics
///
/// Might panic if the index of the element overflows a `usize`.
#[inline]
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
let a = self.iter.next()?;
let i = self.count;
// Possible undefined overflow.
AddAssign::add_assign(&mut self.count, 1);
Some((i, a))
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

#[inline]
fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
let a = self.iter.nth(n)?;
// Possible undefined overflow.
let i = Add::add(self.count, n);
self.count = Add::add(i, 1);
Some((i, a))
}

#[inline]
fn count(self) -> usize {
self.iter.count()
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
#[inline]
fn enumerate<'a, T, Acc, R>(
count: &'a mut usize,
mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, item| {
let acc = fold(acc, (*count, item));
// Possible undefined overflow.
AddAssign::add_assign(count, 1);
acc
}
}

self.iter.try_fold(init, enumerate(&mut self.count, fold))
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn enumerate<T, Acc>(
mut count: usize,
mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, item| {
let acc = fold(acc, (count, item));
// Possible undefined overflow.
AddAssign::add_assign(&mut count, 1);
acc
}
}

self.iter.fold(init, enumerate(self.count, fold))
}

unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
let value = unsafe { try_get_unchecked(&mut self.iter, idx) };
(Add::add(self.count, idx), value)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Enumerate<I>
where
I: ExactSizeIterator + DoubleEndedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
let a = self.iter.next_back()?;
let len = self.iter.len();
// Can safely add, `ExactSizeIterator` promises that the number of
// elements fits into a `usize`.
Some((self.count + len, a))
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<(usize, <I as Iterator>::Item)> {
let a = self.iter.nth_back(n)?;
let len = self.iter.len();
// Can safely add, `ExactSizeIterator` promises that the number of
// elements fits into a `usize`.
Some((self.count + len, a))
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
// Can safely add and subtract the count, as `ExactSizeIterator` promises
// that the number of elements fits into a `usize`.
fn enumerate<T, Acc, R>(
mut count: usize,
mut fold: impl FnMut(Acc, (usize, T)) -> R,
) -> impl FnMut(Acc, T) -> R {
move |acc, item| {
count -= 1;
fold(acc, (count, item))
}
}

let count = self.count + self.iter.len();
self.iter.try_rfold(init, enumerate(count, fold))
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
// Can safely add and subtract the count, as `ExactSizeIterator` promises
// that the number of elements fits into a `usize`.
fn enumerate<T, Acc>(
mut count: usize,
mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, item| {
count -= 1;
fold(acc, (count, item))
}
}

let count = self.count + self.iter.len();
self.iter.rfold(init, enumerate(count, fold))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Enumerate<I>
where
I: ExactSizeIterator,
{
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Enumerate<I>
where
I: TrustedRandomAccess,
{
fn may_have_side_effect() -> bool {
I::may_have_side_effect()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Enumerate<I>
where
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {}
152 changes: 152 additions & 0 deletions library/core/src/iter/adapters/filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::ops::Try;

/// An iterator that filters the elements of `iter` with `predicate`.
///
/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`filter`]: Iterator::filter
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct Filter<I, P> {
iter: I,
predicate: P,
}
impl<I, P> Filter<I, P> {
pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter<I, P> {
Filter { iter, predicate }
}
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, P> fmt::Debug for Filter<I, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Filter").field("iter", &self.iter).finish()
}
}

fn filter_fold<T, Acc>(
mut predicate: impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
}

fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>(
predicate: &'a mut impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, P> Iterator for Filter<I, P>
where
P: FnMut(&I::Item) -> bool,
{
type Item = I::Item;

#[inline]
fn next(&mut self) -> Option<I::Item> {
self.iter.find(&mut self.predicate)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}

// this special case allows the compiler to make `.filter(_).count()`
// branchless. Barring perfect branch prediction (which is unattainable in
// the general case), this will be much faster in >90% of cases (containing
// virtually all real workloads) and only a tiny bit slower in the rest.
//
// Having this specialization thus allows us to write `.filter(p).count()`
// where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is
// less readable and also less backwards-compatible to Rust before 1.10.
//
// Using the branchless version will also simplify the LLVM byte code, thus
// leaving more budget for LLVM optimizations.
#[inline]
fn count(self) -> usize {
#[inline]
fn to_usize<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize {
move |x| predicate(&x) as usize
}

self.iter.map(to_usize(self.predicate)).sum()
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.fold(init, filter_fold(self.predicate, fold))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
where
P: FnMut(&I::Item) -> bool,
{
#[inline]
fn next_back(&mut self) -> Option<I::Item> {
self.iter.rfind(&mut self.predicate)
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, filter_fold(self.predicate, fold))
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, P, I: Iterator> SourceIter for Filter<I, P>
where
P: FnMut(&I::Item) -> bool,
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
150 changes: 150 additions & 0 deletions library/core/src/iter/adapters/filter_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::ops::{ControlFlow, Try};

/// An iterator that uses `f` to both filter and map elements from `iter`.
///
/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`filter_map`]: Iterator::filter_map
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct FilterMap<I, F> {
iter: I,
f: F,
}
impl<I, F> FilterMap<I, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap<I, F> {
FilterMap { iter, f }
}
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, F> fmt::Debug for FilterMap<I, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FilterMap").field("iter", &self.iter).finish()
}
}

fn filter_map_fold<T, B, Acc>(
mut f: impl FnMut(T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, item| match f(item) {
Some(x) => fold(acc, x),
None => acc,
}
}

fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>(
f: &'a mut impl FnMut(T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, item| match f(item) {
Some(x) => fold(acc, x),
None => try { acc },
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
where
F: FnMut(I::Item) -> Option<B>,
{
type Item = B;

#[inline]
fn next(&mut self) -> Option<B> {
self.iter.find_map(&mut self.f)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.fold(init, filter_map_fold(self.f, fold))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
where
F: FnMut(I::Item) -> Option<B>,
{
#[inline]
fn next_back(&mut self) -> Option<B> {
#[inline]
fn find<T, B>(
f: &mut impl FnMut(T) -> Option<B>,
) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
move |(), x| match f(x) {
Some(x) => ControlFlow::Break(x),
None => ControlFlow::CONTINUE,
}
}

self.iter.try_rfold((), find(&mut self.f)).break_value()
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, filter_map_fold(self.f, fold))
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for FilterMap<I, F>
where
F: FnMut(I::Item) -> Option<B>,
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where
F: FnMut(I::Item) -> Option<B>
{
}
7 changes: 3 additions & 4 deletions library/core/src/iter/adapters/flatten.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::fmt;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map};
use crate::ops::Try;

use super::super::{DoubleEndedIterator, Fuse, FusedIterator, Iterator};
use super::Map;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
@@ -14,8 +12,9 @@ use super::Map;
pub struct FlatMap<I, U: IntoIterator, F> {
inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>,
}

impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
pub(in super::super) fn new(iter: I, f: F) -> 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)) }
}
}
7 changes: 2 additions & 5 deletions library/core/src/iter/adapters/fuse.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use super::InPlaceIterable;
use crate::intrinsics;
use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::adapters::SourceIter;
use crate::iter::TrustedRandomAccess;
use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter};
use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedRandomAccess};
use crate::ops::Try;

/// An iterator that yields `None` forever after the underlying iterator
167 changes: 167 additions & 0 deletions library/core/src/iter/adapters/inspect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::ops::Try;

/// An iterator that calls a function with a reference to each element before
/// yielding it.
///
/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`inspect`]: Iterator::inspect
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct Inspect<I, F> {
iter: I,
f: F,
}
impl<I, F> Inspect<I, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> Inspect<I, F> {
Inspect { iter, f }
}
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, F> fmt::Debug for Inspect<I, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Inspect").field("iter", &self.iter).finish()
}
}

impl<I: Iterator, F> Inspect<I, F>
where
F: FnMut(&I::Item),
{
#[inline]
fn do_inspect(&mut self, elt: Option<I::Item>) -> Option<I::Item> {
if let Some(ref a) = elt {
(self.f)(a);
}

elt
}
}

fn inspect_fold<T, Acc>(
mut f: impl FnMut(&T),
mut fold: impl FnMut(Acc, T) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, item| {
f(&item);
fold(acc, item)
}
}

fn inspect_try_fold<'a, T, Acc, R>(
f: &'a mut impl FnMut(&T),
mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, item| {
f(&item);
fold(acc, item)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, F> Iterator for Inspect<I, F>
where
F: FnMut(&I::Item),
{
type Item = I::Item;

#[inline]
fn next(&mut self) -> Option<I::Item> {
let next = self.iter.next();
self.do_inspect(next)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.fold(init, inspect_fold(self.f, fold))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
where
F: FnMut(&I::Item),
{
#[inline]
fn next_back(&mut self) -> Option<I::Item> {
let next = self.iter.next_back();
self.do_inspect(next)
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, inspect_fold(self.f, fold))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
where
F: FnMut(&I::Item),
{
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator, F> SourceIter for Inspect<I, F>
where
F: FnMut(&I::Item),
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> where F: FnMut(&I::Item) {}
213 changes: 213 additions & 0 deletions library/core/src/iter/adapters/map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
use crate::fmt;
use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator that maps the values of `iter` with `f`.
///
/// This `struct` is created by the [`map`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`map`]: Iterator::map
/// [`Iterator`]: trait.Iterator.html
///
/// # Notes about side effects
///
/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that
/// you can also [`map`] backwards:
///
/// ```rust
/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
///
/// assert_eq!(v, [4, 3, 2]);
/// ```
///
/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html
///
/// But if your closure has state, iterating backwards may act in a way you do
/// not expect. Let's go through an example. First, in the forward direction:
///
/// ```rust
/// let mut c = 0;
///
/// for pair in vec!['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) }) {
/// println!("{:?}", pair);
/// }
/// ```
///
/// This will print "('a', 1), ('b', 2), ('c', 3)".
///
/// Now consider this twist where we add a call to `rev`. This version will
/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed,
/// but the values of the counter still go in order. This is because `map()` is
/// still being called lazily on each item, but we are popping items off the
/// back of the vector now, instead of shifting them from the front.
///
/// ```rust
/// let mut c = 0;
///
/// for pair in vec!['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) })
/// .rev() {
/// println!("{:?}", pair);
/// }
/// ```
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct Map<I, F> {
iter: I,
f: F,
}
impl<I, F> Map<I, F> {
pub(in crate::iter) fn new(iter: I, f: F) -> Map<I, F> {
Map { iter, f }
}
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Map").field("iter", &self.iter).finish()
}
}

fn map_fold<T, B, Acc>(
mut f: impl FnMut(T) -> B,
mut g: impl FnMut(Acc, B) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, elt| g(acc, f(elt))
}

fn map_try_fold<'a, T, B, Acc, R>(
f: &'a mut impl FnMut(T) -> B,
mut g: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, elt| g(acc, f(elt))
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: Iterator, F> Iterator for Map<I, F>
where
F: FnMut(I::Item) -> B,
{
type Item = B;

#[inline]
fn next(&mut self) -> Option<B> {
self.iter.next().map(&mut self.f)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
where
Self: Sized,
G: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_fold(init, map_try_fold(&mut self.f, g))
}

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

unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`.
unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F>
where
F: FnMut(I::Item) -> B,
{
#[inline]
fn next_back(&mut self) -> Option<B> {
self.iter.next_back().map(&mut self.f)
}

fn try_rfold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
where
Self: Sized,
G: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
}

fn rfold<Acc, G>(self, init: Acc, g: G) -> Acc
where
G: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, map_fold(self.f, g))
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
where
F: FnMut(I::Item) -> B,
{
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<B, I, F> TrustedLen for Map<I, F>
where
I: TrustedLen,
F: FnMut(I::Item) -> B,
{
}

#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I, F> TrustedRandomAccess for Map<I, F>
where
I: TrustedRandomAccess,
{
#[inline]
fn may_have_side_effect() -> bool {
true
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for Map<I, F>
where
F: FnMut(I::Item) -> B,
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for Map<I, F> where F: FnMut(I::Item) -> B {}
101 changes: 101 additions & 0 deletions library/core/src/iter/adapters/map_while.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, InPlaceIterable};
use crate::ops::{ControlFlow, Try};

/// An iterator that only accepts elements while `predicate` returns `Some(_)`.
///
/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`map_while`]: Iterator::map_while
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
#[derive(Clone)]
pub struct MapWhile<I, P> {
iter: I,
predicate: P,
}

impl<I, P> MapWhile<I, P> {
pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
MapWhile { iter, predicate }
}
}

#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
impl<I: fmt::Debug, P> fmt::Debug for MapWhile<I, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapWhile").field("iter", &self.iter).finish()
}
}

#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
impl<B, I: Iterator, P> Iterator for MapWhile<I, P>
where
P: FnMut(I::Item) -> Option<B>,
{
type Item = B;

#[inline]
fn next(&mut self) -> Option<B> {
let x = self.iter.next()?;
(self.predicate)(x)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
let Self { iter, predicate } = self;
iter.try_fold(init, |acc, x| match predicate(x) {
Some(item) => ControlFlow::from_try(fold(acc, item)),
None => ControlFlow::Break(try { acc }),
})
.into_try()
}

#[inline]
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
move |acc, x| Ok(f(acc, x))
}

self.try_fold(init, ok(fold)).unwrap()
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, B, I: Iterator, P> SourceIter for MapWhile<I, P>
where
P: FnMut(I::Item) -> Option<B>,
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where
P: FnMut(I::Item) -> Option<B>
{
}
2,859 changes: 40 additions & 2,819 deletions library/core/src/iter/adapters/mod.rs

Large diffs are not rendered by default.

301 changes: 301 additions & 0 deletions library/core/src/iter/adapters/peekable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
iter: I,
/// Remember a peeked value, even if it was None.
peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
Peekable { iter, peeked: None }
}
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
type Item = I::Item;

#[inline]
fn next(&mut self) -> Option<I::Item> {
match self.peeked.take() {
Some(v) => v,
None => self.iter.next(),
}
}

#[inline]
#[rustc_inherit_overflow_checks]
fn count(mut self) -> usize {
match self.peeked.take() {
Some(None) => 0,
Some(Some(_)) => 1 + self.iter.count(),
None => self.iter.count(),
}
}

#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
match self.peeked.take() {
Some(None) => None,
Some(v @ Some(_)) if n == 0 => v,
Some(Some(_)) => self.iter.nth(n - 1),
None => self.iter.nth(n),
}
}

#[inline]
fn last(mut self) -> Option<I::Item> {
let peek_opt = match self.peeked.take() {
Some(None) => return None,
Some(v) => v,
None => None,
};
self.iter.last().or(peek_opt)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let peek_len = match self.peeked {
Some(None) => return (0, Some(0)),
Some(Some(_)) => 1,
None => 0,
};
let (lo, hi) = self.iter.size_hint();
let lo = lo.saturating_add(peek_len);
let hi = match hi {
Some(x) => x.checked_add(peek_len),
None => None,
};
(lo, hi)
}

#[inline]
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
let acc = match self.peeked.take() {
Some(None) => return try { init },
Some(Some(v)) => f(init, v)?,
None => init,
};
self.iter.try_fold(acc, f)
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let acc = match self.peeked {
Some(None) => return init,
Some(Some(v)) => fold(init, v),
None => init,
};
self.iter.fold(acc, fold)
}
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
I: DoubleEndedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match self.peeked.as_mut() {
Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
Some(None) => None,
None => self.iter.next_back(),
}
}

#[inline]
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
match self.peeked.take() {
Some(None) => try { init },
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
Ok(acc) => f(acc, v),
Err(e) => {
self.peeked = Some(Some(v));
Try::from_error(e)
}
},
None => self.iter.try_rfold(init, f),
}
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
match self.peeked {
Some(None) => init,
Some(Some(v)) => {
let acc = self.iter.rfold(init, &mut fold);
fold(acc, v)
}
None => self.iter.rfold(init, fold),
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
/// Returns a reference to the next() value without advancing the iterator.
///
/// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
/// But if the iteration is over, `None` is returned.
///
/// [`next`]: Iterator::next
///
/// Because `peek()` returns a reference, and many iterators iterate over
/// references, there can be a possibly confusing situation where the
/// return value is a double reference. You can see this effect in the
/// examples below.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let xs = [1, 2, 3];
///
/// let mut iter = xs.iter().peekable();
///
/// // peek() lets us see into the future
/// assert_eq!(iter.peek(), Some(&&1));
/// assert_eq!(iter.next(), Some(&1));
///
/// assert_eq!(iter.next(), Some(&2));
///
/// // The iterator does not advance even if we `peek` multiple times
/// assert_eq!(iter.peek(), Some(&&3));
/// assert_eq!(iter.peek(), Some(&&3));
///
/// assert_eq!(iter.next(), Some(&3));
///
/// // After the iterator is finished, so is `peek()`
/// assert_eq!(iter.peek(), None);
/// assert_eq!(iter.next(), None);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&mut self) -> Option<&I::Item> {
let iter = &mut self.iter;
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
}

/// Consume and return the next value of this iterator if a condition is true.
///
/// If `func` returns `true` for the next value of this iterator, consume and return it.
/// Otherwise, return `None`.
///
/// # Examples
/// Consume a number if it's equal to 0.
/// ```
/// #![feature(peekable_next_if)]
/// let mut iter = (0..5).peekable();
/// // The first item of the iterator is 0; consume it.
/// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
/// // The next item returned is now 1, so `consume` will return `false`.
/// assert_eq!(iter.next_if(|&x| x == 0), None);
/// // `next_if` saves the value of the next item if it was not equal to `expected`.
/// assert_eq!(iter.next(), Some(1));
/// ```
///
/// Consume any number less than 10.
/// ```
/// #![feature(peekable_next_if)]
/// let mut iter = (1..20).peekable();
/// // Consume all numbers less than 10
/// while iter.next_if(|&x| x < 10).is_some() {}
/// // The next value returned will be 10
/// assert_eq!(iter.next(), Some(10));
/// ```
#[unstable(feature = "peekable_next_if", issue = "72480")]
pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
match self.next() {
Some(matched) if func(&matched) => Some(matched),
other => {
// Since we called `self.next()`, we consumed `self.peeked`.
assert!(self.peeked.is_none());
self.peeked = Some(other);
None
}
}
}

/// Consume and return the next item if it is equal to `expected`.
///
/// # Example
/// Consume a number if it's equal to 0.
/// ```
/// #![feature(peekable_next_if)]
/// let mut iter = (0..5).peekable();
/// // The first item of the iterator is 0; consume it.
/// assert_eq!(iter.next_if_eq(&0), Some(0));
/// // The next item returned is now 1, so `consume` will return `false`.
/// assert_eq!(iter.next_if_eq(&0), None);
/// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
/// assert_eq!(iter.next(), Some(1));
/// ```
#[unstable(feature = "peekable_next_if", issue = "72480")]
pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
where
T: ?Sized,
I::Item: PartialEq<T>,
{
self.next_if(|next| next == expected)
}
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
137 changes: 137 additions & 0 deletions library/core/src/iter/adapters/rev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use crate::iter::{FusedIterator, TrustedLen};
use crate::ops::Try;

/// A double-ended iterator with the direction inverted.
///
/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`rev`]: Iterator::rev
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Rev<T> {
iter: T,
}

impl<T> Rev<T> {
pub(in crate::iter) fn new(iter: T) -> Rev<T> {
Rev { iter }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Rev<I>
where
I: DoubleEndedIterator,
{
type Item = <I as Iterator>::Item;

#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
self.iter.next_back()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
self.iter.advance_back_by(n)
}

#[inline]
fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
self.iter.nth_back(n)
}

fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
self.iter.try_rfold(init, f)
}

fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, f)
}

#[inline]
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
self.iter.rfind(predicate)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Rev<I>
where
I: DoubleEndedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
self.iter.next()
}

#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
self.iter.advance_by(n)
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
self.iter.nth(n)
}

fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok = B>,
{
self.iter.try_fold(init, f)
}

fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.fold(init, f)
}

fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
self.iter.find(predicate)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Rev<I>
where
I: ExactSizeIterator + DoubleEndedIterator,
{
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Rev<I> where I: FusedIterator + DoubleEndedIterator {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Rev<I> where I: TrustedLen + DoubleEndedIterator {}
111 changes: 111 additions & 0 deletions library/core/src/iter/adapters/scan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, InPlaceIterable};
use crate::ops::{ControlFlow, Try};

/// An iterator to maintain state while iterating another iterator.
///
/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`scan`]: Iterator::scan
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct Scan<I, St, F> {
iter: I,
f: F,
state: St,
}

impl<I, St, F> Scan<I, St, F> {
pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
Scan { iter, state, f }
}
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, St: fmt::Debug, F> fmt::Debug for Scan<I, St, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I, St, F> Iterator for Scan<I, St, F>
where
I: Iterator,
F: FnMut(&mut St, I::Item) -> Option<B>,
{
type Item = B;

#[inline]
fn next(&mut self) -> Option<B> {
let a = self.iter.next()?;
(self.f)(&mut self.state, a)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the scan function
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>(
state: &'a mut St,
f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
move |acc, x| match f(state, x) {
None => ControlFlow::Break(try { acc }),
Some(x) => ControlFlow::from_try(fold(acc, x)),
}
}

let state = &mut self.state;
let f = &mut self.f;
self.iter.try_fold(init, scan(state, f, fold)).into_try()
}

#[inline]
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
move |acc, x| Ok(f(acc, x))
}

self.try_fold(init, ok(fold)).unwrap()
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<St, F, B, S: Iterator, I: Iterator> SourceIter for Scan<I, St, F>
where
I: SourceIter<Source = S>,
F: FnMut(&mut St, I::Item) -> Option<B>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> where
F: FnMut(&mut St, I::Item) -> Option<B>
{
}
199 changes: 199 additions & 0 deletions library/core/src/iter/adapters/skip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::ops::{ControlFlow, Try};

/// An iterator that skips over `n` elements of `iter`.
///
/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`skip`]: Iterator::skip
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Skip<I> {
iter: I,
n: usize,
}

impl<I> Skip<I> {
pub(in crate::iter) fn new(iter: I, n: usize) -> Skip<I> {
Skip { iter, n }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Skip<I>
where
I: Iterator,
{
type Item = <I as Iterator>::Item;

#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.n == 0 {
self.iter.next()
} else {
let old_n = self.n;
self.n = 0;
self.iter.nth(old_n)
}
}

#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
// Can't just add n + self.n due to overflow.
if self.n > 0 {
let to_skip = self.n;
self.n = 0;
// nth(n) skips n+1
self.iter.nth(to_skip - 1)?;
}
self.iter.nth(n)
}

#[inline]
fn count(mut self) -> usize {
if self.n > 0 {
// nth(n) skips n+1
if self.iter.nth(self.n - 1).is_none() {
return 0;
}
}
self.iter.count()
}

#[inline]
fn last(mut self) -> Option<I::Item> {
if self.n > 0 {
// nth(n) skips n+1
self.iter.nth(self.n - 1)?;
}
self.iter.last()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.iter.size_hint();

let lower = lower.saturating_sub(self.n);
let upper = match upper {
Some(x) => Some(x.saturating_sub(self.n)),
None => None,
};

(lower, upper)
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
let n = self.n;
self.n = 0;
if n > 0 {
// nth(n) skips n+1
if self.iter.nth(n - 1).is_none() {
return try { init };
}
}
self.iter.try_fold(init, fold)
}

#[inline]
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if self.n > 0 {
// nth(n) skips n+1
if self.iter.nth(self.n - 1).is_none() {
return init;
}
}
self.iter.fold(init, fold)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}

#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")]
impl<I> DoubleEndedIterator for Skip<I>
where
I: DoubleEndedIterator + ExactSizeIterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.len() > 0 { self.iter.next_back() } else { None }
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
let len = self.len();
if n < len {
self.iter.nth_back(n)
} else {
if len > 0 {
// consume the original iterator
self.iter.nth_back(len - 1);
}
None
}
}

fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
fn check<T, Acc, R: Try<Ok = Acc>>(
mut n: usize,
mut fold: impl FnMut(Acc, T) -> R,
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
move |acc, x| {
n -= 1;
let r = fold(acc, x);
if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
}
}

let n = self.len();
if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
}

fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
move |acc, x| Ok(f(acc, x))
}

self.try_rfold(init, ok(fold)).unwrap()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Skip<I> where I: FusedIterator {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Skip<I>
where
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {}
126 changes: 126 additions & 0 deletions library/core/src/iter/adapters/skip_while.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::ops::Try;

/// An iterator that rejects elements while `predicate` returns `true`.
///
/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`skip_while`]: Iterator::skip_while
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct SkipWhile<I, P> {
iter: I,
flag: bool,
predicate: P,
}

impl<I, P> SkipWhile<I, P> {
pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
SkipWhile { iter, flag: false, predicate }
}
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, P> fmt::Debug for SkipWhile<I, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, P> Iterator for SkipWhile<I, P>
where
P: FnMut(&I::Item) -> bool,
{
type Item = I::Item;

#[inline]
fn next(&mut self) -> Option<I::Item> {
fn check<'a, T>(
flag: &'a mut bool,
pred: &'a mut impl FnMut(&T) -> bool,
) -> impl FnMut(&T) -> bool + 'a {
move |x| {
if *flag || !pred(x) {
*flag = true;
true
} else {
false
}
}
}

let flag = &mut self.flag;
let pred = &mut self.predicate;
self.iter.find(check(flag, pred))
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if !self.flag {
match self.next() {
Some(v) => init = fold(init, v)?,
None => return try { init },
}
}
self.iter.try_fold(init, fold)
}

#[inline]
fn fold<Acc, Fold>(mut self, mut init: Acc, mut fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if !self.flag {
match self.next() {
Some(v) => init = fold(init, v),
None => return init,
}
}
self.iter.fold(init, fold)
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, P> FusedIterator for SkipWhile<I, P>
where
I: FusedIterator,
P: FnMut(&I::Item) -> bool,
{
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, P, I: Iterator> SourceIter for SkipWhile<I, P>
where
P: FnMut(&I::Item) -> bool,
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where
F: FnMut(&I::Item) -> bool
{
}
235 changes: 235 additions & 0 deletions library/core/src/iter/adapters/step_by.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
use crate::{intrinsics, iter::from_fn, ops::Try};

/// An iterator for stepping iterators by a custom amount.
///
/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
/// its documentation for more.
///
/// [`step_by`]: Iterator::step_by
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_step_by", since = "1.28.0")]
#[derive(Clone, Debug)]
pub struct StepBy<I> {
iter: I,
step: usize,
first_take: bool,
}

impl<I> StepBy<I> {
pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> {
assert!(step != 0);
StepBy { iter, step: step - 1, first_take: true }
}
}

#[stable(feature = "iterator_step_by", since = "1.28.0")]
impl<I> Iterator for StepBy<I>
where
I: Iterator,
{
type Item = I::Item;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.first_take {
self.first_take = false;
self.iter.next()
} else {
self.iter.nth(self.step)
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
#[inline]
fn first_size(step: usize) -> impl Fn(usize) -> usize {
move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) }
}

#[inline]
fn other_size(step: usize) -> impl Fn(usize) -> usize {
move |n| n / (step + 1)
}

let (low, high) = self.iter.size_hint();

if self.first_take {
let f = first_size(self.step);
(f(low), high.map(f))
} else {
let f = other_size(self.step);
(f(low), high.map(f))
}
}

#[inline]
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
if self.first_take {
self.first_take = false;
let first = self.iter.next();
if n == 0 {
return first;
}
n -= 1;
}
// n and self.step are indices, we need to add 1 to get the amount of elements
// When calling `.nth`, we need to subtract 1 again to convert back to an index
// step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
let mut step = self.step + 1;
// n + 1 could overflow
// thus, if n is usize::MAX, instead of adding one, we call .nth(step)
if n == usize::MAX {
self.iter.nth(step - 1);
} else {
n += 1;
}

// overflow handling
loop {
let mul = n.checked_mul(step);
{
if intrinsics::likely(mul.is_some()) {
return self.iter.nth(mul.unwrap() - 1);
}
}
let div_n = usize::MAX / n;
let div_step = usize::MAX / step;
let nth_n = div_n * n;
let nth_step = div_step * step;
let nth = if nth_n > nth_step {
step -= div_n;
nth_n
} else {
n -= div_step;
nth_step
};
self.iter.nth(nth - 1);
}
}

fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
where
F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
#[inline]
fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
move || iter.nth(step)
}

if self.first_take {
self.first_take = false;
match self.iter.next() {
None => return try { acc },
Some(x) => acc = f(acc, x)?,
}
}
from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
}

fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
move || iter.nth(step)
}

if self.first_take {
self.first_take = false;
match self.iter.next() {
None => return acc,
Some(x) => acc = f(acc, x),
}
}
from_fn(nth(&mut self.iter, self.step)).fold(acc, f)
}
}

impl<I> StepBy<I>
where
I: ExactSizeIterator,
{
// The zero-based index starting from the end of the iterator of the
// last element. Used in the `DoubleEndedIterator` implementation.
fn next_back_index(&self) -> usize {
let rem = self.iter.len() % (self.step + 1);
if self.first_take {
if rem == 0 { self.step } else { rem - 1 }
} else {
rem
}
}
}

#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for StepBy<I>
where
I: DoubleEndedIterator + ExactSizeIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.nth_back(self.next_back_index())
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
// `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
// is out of bounds because the length of `self.iter` does not exceed
// `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
// zero-indexed
let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index());
self.iter.nth_back(n)
}

fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
where
F: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
#[inline]
fn nth_back<I: DoubleEndedIterator>(
iter: &mut I,
step: usize,
) -> impl FnMut() -> Option<I::Item> + '_ {
move || iter.nth_back(step)
}

match self.next_back() {
None => try { init },
Some(x) => {
let acc = f(init, x)?;
from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f)
}
}
}

#[inline]
fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
where
Self: Sized,
F: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn nth_back<I: DoubleEndedIterator>(
iter: &mut I,
step: usize,
) -> impl FnMut() -> Option<I::Item> + '_ {
move || iter.nth_back(step)
}

match self.next_back() {
None => init,
Some(x) => {
let acc = f(init, x);
from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f)
}
}
}
}

// StepBy can only make the iterator shorter, so the len will still fit.
#[stable(feature = "iterator_step_by", since = "1.28.0")]
impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
209 changes: 209 additions & 0 deletions library/core/src/iter/adapters/take.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use crate::cmp;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::{ControlFlow, Try};

/// An iterator that only iterates over the first `n` iterations of `iter`.
///
/// This `struct` is created by the [`take`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`take`]: Iterator::take
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Take<I> {
iter: I,
n: usize,
}

impl<I> Take<I> {
pub(in crate::iter) fn new(iter: I, n: usize) -> Take<I> {
Take { iter, n }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Take<I>
where
I: Iterator,
{
type Item = <I as Iterator>::Item;

#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
if self.n != 0 {
self.n -= 1;
self.iter.next()
} else {
None
}
}

#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
if self.n > n {
self.n -= n + 1;
self.iter.nth(n)
} else {
if self.n > 0 {
self.iter.nth(self.n - 1);
self.n = 0;
}
None
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.n == 0 {
return (0, Some(0));
}

let (lower, upper) = self.iter.size_hint();

let lower = cmp::min(lower, self.n);

let upper = match upper {
Some(x) if x < self.n => Some(x),
_ => Some(self.n),
};

(lower, upper)
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
fn check<'a, T, Acc, R: Try<Ok = Acc>>(
n: &'a mut usize,
mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
move |acc, x| {
*n -= 1;
let r = fold(acc, x);
if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
}
}

if self.n == 0 {
try { init }
} else {
let n = &mut self.n;
self.iter.try_fold(init, check(n, fold)).into_try()
}
}

#[inline]
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
move |acc, x| Ok(f(acc, x))
}

self.try_fold(init, ok(fold)).unwrap()
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Take<I>
where
I: SourceIter<Source = S>,
{
type Source = S;

#[inline]
unsafe fn as_inner(&mut self) -> &mut S {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {}

#[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Take<I>
where
I: DoubleEndedIterator + ExactSizeIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.n == 0 {
None
} else {
let n = self.n;
self.n -= 1;
self.iter.nth_back(self.iter.len().saturating_sub(n))
}
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let len = self.iter.len();
if self.n > n {
let m = len.saturating_sub(self.n) + n;
self.n -= n + 1;
self.iter.nth_back(m)
} else {
if len > 0 {
self.iter.nth_back(len - 1);
}
None
}
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if self.n == 0 {
try { init }
} else {
let len = self.iter.len();
if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
try { init }
} else {
self.iter.try_rfold(init, fold)
}
}
}

#[inline]
fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if self.n == 0 {
init
} else {
let len = self.iter.len();
if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
init
} else {
self.iter.rfold(init, fold)
}
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Take<I> where I: FusedIterator {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
Loading