diff options
author | Woohyun Jung <wh0705.jung@samsung.com> | 2023-03-14 18:35:04 +0900 |
---|---|---|
committer | Woohyun Jung <wh0705.jung@samsung.com> | 2023-03-14 18:35:04 +0900 |
commit | 575b828679a49397abd7fb93b504d0532dd80444 (patch) | |
tree | dfd95ab0ac90586a2cccf95bcc760dc88b9bd47c | |
download | rust-fallible-iterator-upstream.tar.gz rust-fallible-iterator-upstream.tar.bz2 rust-fallible-iterator-upstream.zip |
Import fallible-iterator 0.2.0upstream/0.2.0upstream
-rw-r--r-- | .cargo_vcs_info.json | 5 | ||||
-rw-r--r-- | .circleci/config.yml | 60 | ||||
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | CHANGELOG.md | 26 | ||||
-rw-r--r-- | Cargo.toml | 27 | ||||
-rw-r--r-- | Cargo.toml.orig | 15 | ||||
-rw-r--r-- | LICENSE-APACHE | 202 | ||||
-rw-r--r-- | LICENSE-MIT | 19 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | src/lib.rs | 2606 | ||||
-rw-r--r-- | src/test.rs | 455 |
11 files changed, 3434 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..37ca5ef --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "03b701c04b37fcd1ab1045c4623542606abf378b" + } +} diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..cf9d2e4 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,60 @@ +restore_registry: &RESTORE_REGISTRY + restore_cache: + key: registry +save_registry: &SAVE_REGISTRY + save_cache: + key: registry-{{ .BuildNum }} + paths: + - /usr/local/cargo/registry/index +deps_key: &DEPS_KEY + key: deps-{{ checksum "~/rust-version" }}-{{ checksum "Cargo.lock" }} +restore_deps: &RESTORE_DEPS + restore_cache: + <<: *DEPS_KEY +save_deps: &SAVE_DEPS + save_cache: + <<: *DEPS_KEY + paths: + - target + - /usr/local/cargo/registry/cache + +version: 2 +jobs: + stable: + docker: + - image: rust:1.33.0 + environment: + RUSTFLAGS: -D warnings + working_directory: ~/build + steps: + - checkout + - *RESTORE_REGISTRY + - run: cargo generate-lockfile + - *SAVE_REGISTRY + - run: rustc --version > ~/rust-version + - *RESTORE_DEPS + - run: cargo test + - run: cargo test --features std + - *SAVE_DEPS + nightly: + docker: + - image: rustlang/rust:nightly + environment: + RUSTFLAGS: -D warnings + working_directory: ~/build + steps: + - checkout + - *RESTORE_REGISTRY + - run: cargo generate-lockfile + - *SAVE_REGISTRY + - run: rustc --version > ~/rust-version + - *RESTORE_DEPS + - run: cargo test --features alloc + - *SAVE_DEPS + +workflows: + version: 2 + tests: + jobs: + - stable + - nightly diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03814ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target +Cargo.lock +.idea/ +*.iml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c2cb0c6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +# Change Log + +## [Unreleased] + +## [v0.2.0] - 2019-03-10 + +### Changed + +* All closures used by adaptor methods now return `Result`s. +* `FromFallibleIterator::from_fallible_iterator` has been renamed to `from_fallible_iter` and now takes an + `IntoFallibleIterator`. +* `IntoFallibleIterator::into_fallible_iterator` has been renamed to `into_fallible_iter`. +* `IntoFallibleIterator::IntoIter` has been renamed to `IntoFallibleIter`. + +### Removed + +* `FallibleIterator::and_then` has been removed as `FallibleIterator::map` is now equivalent. + +### Added + +* Added `step_by`, `for_each`, `skip_while`, `take_while`, `skip`, `scan`, `flat_map`, `flatten`, `inspect`, + `partition`, `find_map`, `max_by`, `min_by`, `unzip`, `cycle`, and `try_fold` to `FallibleIterator`. +* Added `rfold` and `try_rfold` to `DoubleEndedFallibleIterator`. + +[Unreleased]: https://github.com/sfackler/rust-fallible-iterator/compare/v0.2.0...master +[v0.2.0]: https://github.com/sfackler/rust-fallible-iterator/compare/v0.1.5...v0.2.0 diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b7a15c1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "fallible-iterator" +version = "0.2.0" +authors = ["Steven Fackler <sfackler@gmail.com>"] +description = "Fallible iterator traits" +readme = "README.md" +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/rust-fallible-iterator" + +[features] +alloc = [] +default = ["std"] +std = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..e8fd7e9 --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,15 @@ +[package] +name = "fallible-iterator" +version = "0.2.0" +authors = ["Steven Fackler <sfackler@gmail.com>"] +edition = "2018" +license = "MIT/Apache-2.0" +description = "Fallible iterator traits" +repository = "https://github.com/sfackler/rust-fallible-iterator" +readme = "README.md" +categories = ["algorithms", "no-std"] + +[features] +alloc = [] +std = [] +default = ["std"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..a7cfbe0 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015 The rust-openssl-verify Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e7a4af2 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# rust-fallible-iterator + +[![CircleCI](https://circleci.com/gh/sfackler/rust-fallible-iterator.svg?style=shield)](https://circleci.com/gh/sfackler/rust-fallible-iterator) + +[Documentation](https://sfackler.github.io/rust-fallible-iterator/doc/v0.1.3/fallible_iterator) + +"Fallible" iterators for Rust. + +## Features + +If the `std` or `alloc` features are enabled, this crate provides implementations for +`Box`, `Vec`, `BTreeMap`, and `BTreeSet`. If the `std` feature is enabled, this crate +additionally provides implementations for `HashMap` and `HashSet`. + +If the `std` feature is disabled, this crate does not depend on `libstd`. diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f5f77b2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2606 @@ +//! "Fallible" iterators. +//! +//! The iterator APIs in the Rust standard library do not support iteration +//! that can fail in a first class manner. These iterators are typically modeled +//! as iterating over `Result<T, E>` values; for example, the `Lines` iterator +//! returns `io::Result<String>`s. When simply iterating over these types, the +//! value being iterated over must be unwrapped in some way before it can be +//! used: +//! +//! ```ignore +//! for line in reader.lines() { +//! let line = line?; +//! // work with line +//! } +//! ``` +//! +//! In addition, many of the additional methods on the `Iterator` trait will +//! not behave properly in the presence of errors when working with these kinds +//! of iterators. For example, if one wanted to count the number of lines of +//! text in a `Read`er, this might be a way to go about it: +//! +//! ```ignore +//! let count = reader.lines().count(); +//! ``` +//! +//! This will return the proper value when the reader operates successfully, but +//! if it encounters an IO error, the result will either be slightly higher than +//! expected if the error is transient, or it may run forever if the error is +//! returned repeatedly! +//! +//! In contrast, a fallible iterator is built around the concept that a call to +//! `next` can fail. The trait has an additional `Error` associated type in +//! addition to the `Item` type, and `next` returns `Result<Option<Self::Item>, +//! Self::Error>` rather than `Option<Self::Item>`. Methods like `count` return +//! `Result`s as well. +//! +//! This does mean that fallible iterators are incompatible with Rust's `for` +//! loop syntax, but `while let` loops offer a similar level of ergonomics: +//! +//! ```ignore +//! while let Some(item) = iter.next()? { +//! // work with item +//! } +//! ``` +//! +//! ## Fallible closure arguments +//! +//! Like `Iterator`, many `FallibleIterator` methods take closures as arguments. +//! These use the same signatures as their `Iterator` counterparts, except that +//! `FallibleIterator` expects the closures to be fallible: they return +//! `Result<T, Self::Error>` instead of simply `T`. +//! +//! For example, the standard library's `Iterator::filter` adapter method +//! filters the underlying iterator according to a predicate provided by the +//! user, whose return type is `bool`. In `FallibleIterator::filter`, however, +//! the predicate returns `Result<bool, Self::Error>`: +//! +//! ``` +//! # use std::error::Error; +//! # use std::str::FromStr; +//! # use fallible_iterator::{convert, FallibleIterator}; +//! let numbers = convert("100\n200\nfern\n400".lines().map(Ok::<&str, Box<Error>>)); +//! let big_numbers = numbers.filter(|n| Ok(u64::from_str(n)? > 100)); +//! assert!(big_numbers.count().is_err()); +//! ``` +#![doc(html_root_url = "https://docs.rs/fallible-iterator/0.2")] +#![warn(missing_docs)] +#![cfg_attr(feature = "alloc", feature(alloc))] +#![no_std] + +use core::cmp::{self, Ordering}; +use core::iter; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[cfg_attr(test, macro_use)] +extern crate alloc; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +mod imports { + pub use alloc::boxed::Box; + pub use alloc::collections::btree_map::BTreeMap; + pub use alloc::collections::btree_set::BTreeSet; + pub use alloc::vec::Vec; +} + +#[cfg(feature = "std")] +#[cfg_attr(test, macro_use)] +extern crate std; + +#[cfg(feature = "std")] +mod imports { + pub use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; + pub use std::hash::{BuildHasher, Hash}; + pub use std::prelude::v1::*; +} + +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::imports::*; + +#[cfg(any(feature = "std", feature = "alloc"))] +#[cfg(test)] +mod test; + +enum FoldStop<T, E> { + Break(T), + Err(E), +} + +impl<T, E> From<E> for FoldStop<T, E> { + #[inline] + fn from(e: E) -> FoldStop<T, E> { + FoldStop::Err(e) + } +} + +trait ResultExt<T, E> { + fn unpack_fold(self) -> Result<T, E>; +} + +impl<T, E> ResultExt<T, E> for Result<T, FoldStop<T, E>> { + #[inline] + fn unpack_fold(self) -> Result<T, E> { + match self { + Ok(v) => Ok(v), + Err(FoldStop::Break(v)) => Ok(v), + Err(FoldStop::Err(e)) => Err(e), + } + } +} + +/// An `Iterator`-like trait that allows for calculation of items to fail. +pub trait FallibleIterator { + /// The type being iterated over. + type Item; + + /// The error type. + type Error; + + /// Advances the iterator and returns the next value. + /// + /// Returns `Ok(None)` when iteration is finished. + /// + /// The behavior of calling this method after a previous call has returned + /// `Ok(None)` or `Err` is implemenetation defined. + fn next(&mut self) -> Result<Option<Self::Item>, Self::Error>; + + /// Returns bounds on the remaining length of the iterator. + /// + /// Specifically, the first half of the returned tuple is a lower bound and + /// the second half is an upper bound. + /// + /// For the upper bound, `None` indicates that the upper bound is either + /// unknown or larger than can be represented as a `usize`. + /// + /// Both bounds assume that all remaining calls to `next` succeed. That is, + /// `next` could return an `Err` in fewer calls than specified by the lower + /// bound. + /// + /// The default implementation returns `(0, None)`, which is correct for + /// any iterator. + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (0, None) + } + + /// Consumes the iterator, returning the number of remaining items. + #[inline] + fn count(self) -> Result<usize, Self::Error> + where + Self: Sized, + { + self.fold(0, |n, _| Ok(n + 1)) + } + + /// Returns the last element of the iterator. + #[inline] + fn last(self) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + { + self.fold(None, |_, v| Ok(Some(v))) + } + + /// Returns the `n`th element of the iterator. + #[inline] + fn nth(&mut self, mut n: usize) -> Result<Option<Self::Item>, Self::Error> { + while let Some(e) = self.next()? { + if n == 0 { + return Ok(Some(e)); + } + n -= 1; + } + Ok(None) + } + + /// Returns an iterator starting at the same point, but stepping by the given amount at each iteration. + /// + /// # Panics + /// + /// Panics if `step` is 0. + #[inline] + fn step_by(self, step: usize) -> StepBy<Self> + where + Self: Sized, + { + assert!(step != 0); + StepBy { + it: self, + step: step - 1, + first_take: true, + } + } + + /// Returns an iterator which yields the elements of this iterator followed + /// by another. + #[inline] + fn chain<I>(self, it: I) -> Chain<Self, I> + where + I: IntoFallibleIterator<Item = Self::Item, Error = Self::Error>, + Self: Sized, + { + Chain { + front: self, + back: it, + state: ChainState::Both, + } + } + + /// Returns an iterator that yields pairs of this iterator's and another + /// iterator's values. + #[inline] + fn zip<I>(self, o: I) -> Zip<Self, I::IntoFallibleIter> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + { + Zip(self, o.into_fallible_iter()) + } + + /// Returns an iterator which applies a fallible transform to the elements + /// of the underlying iterator. + #[inline] + fn map<F, B>(self, f: F) -> Map<Self, F> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<B, Self::Error>, + { + Map { it: self, f: f } + } + + /// Calls a fallible closure on each element of an iterator. + #[inline] + fn for_each<F>(self, mut f: F) -> Result<(), Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<(), Self::Error>, + { + self.fold((), move |(), item| f(item)) + } + + /// Returns an iterator which uses a predicate to determine which values + /// should be yielded. The predicate may fail; such failures are passed to + /// the caller. + #[inline] + fn filter<F>(self, f: F) -> Filter<Self, F> + where + Self: Sized, + F: FnMut(&Self::Item) -> Result<bool, Self::Error>, + { + Filter { it: self, f: f } + } + + /// Returns an iterator which both filters and maps. The closure may fail; + /// such failures are passed along to the consumer. + #[inline] + fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<Option<B>, Self::Error>, + { + FilterMap { it: self, f: f } + } + + /// Returns an iterator which yields the current iteration count as well + /// as the value. + #[inline] + fn enumerate(self) -> Enumerate<Self> + where + Self: Sized, + { + Enumerate { it: self, n: 0 } + } + + /// Returns an iterator that can peek at the next element without consuming + /// it. + #[inline] + fn peekable(self) -> Peekable<Self> + where + Self: Sized, + { + Peekable { + it: self, + next: None, + } + } + + /// Returns an iterator that skips elements based on a predicate. + #[inline] + fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P> + where + Self: Sized, + P: FnMut(&Self::Item) -> Result<bool, Self::Error>, + { + SkipWhile { + it: self, + flag: false, + predicate, + } + } + + /// Returns an iterator that yields elements based on a predicate. + #[inline] + fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P> + where + Self: Sized, + P: FnMut(&Self::Item) -> Result<bool, Self::Error>, + { + TakeWhile { + it: self, + flag: false, + predicate, + } + } + + /// Returns an iterator which skips the first `n` values of this iterator. + #[inline] + fn skip(self, n: usize) -> Skip<Self> + where + Self: Sized, + { + Skip { it: self, n } + } + + /// Returns an iterator that yields only the first `n` values of this + /// iterator. + #[inline] + fn take(self, n: usize) -> Take<Self> + where + Self: Sized, + { + Take { + it: self, + remaining: n, + } + } + + /// Returns an iterator which applies a stateful map to values of this + /// iterator. + #[inline] + fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F> + where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Result<Option<B>, Self::Error>, + { + Scan { + it: self, + f, + state: initial_state, + } + } + + /// Returns an iterator which maps this iterator's elements to iterators, yielding those iterators' values. + #[inline] + fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F> + where + Self: Sized, + U: IntoFallibleIterator<Error = Self::Error>, + F: FnMut(Self::Item) -> Result<U, Self::Error>, + { + FlatMap { + it: self.map(f), + cur: None, + } + } + + /// Returns an iterator which flattens an iterator of iterators, yielding those iterators' values. + #[inline] + fn flatten(self) -> Flatten<Self> + where + Self: Sized, + Self::Item: IntoFallibleIterator<Error = Self::Error>, + { + Flatten { + it: self, + cur: None, + } + } + + /// Returns an iterator which yields this iterator's elements and ends after + /// the first `Ok(None)`. + /// + /// The behavior of calling `next` after it has previously returned + /// `Ok(None)` is normally unspecified. The iterator returned by this method + /// guarantees that `Ok(None)` will always be returned. + #[inline] + fn fuse(self) -> Fuse<Self> + where + Self: Sized, + { + Fuse { + it: self, + done: false, + } + } + + /// Returns an iterator which passes each element to a closure before returning it. + #[inline] + fn inspect<F>(self, f: F) -> Inspect<Self, F> + where + Self: Sized, + F: FnMut(&Self::Item) -> Result<(), Self::Error>, + { + Inspect { it: self, f } + } + + /// Borrow an iterator rather than consuming it. + /// + /// This is useful to allow the use of iterator adaptors that would + /// otherwise consume the value. + #[inline] + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } + + /// Transforms the iterator into a collection. + /// + /// An `Err` will be returned if any invocation of `next` returns `Err`. + #[inline] + fn collect<T>(self) -> Result<T, Self::Error> + where + T: FromFallibleIterator<Self::Item>, + Self: Sized, + { + T::from_fallible_iter(self) + } + + /// Transforms the iterator into two collections, partitioning elements by a closure. + #[inline] + fn partition<B, F>(self, mut f: F) -> Result<(B, B), Self::Error> + where + Self: Sized, + B: Default + Extend<Self::Item>, + F: FnMut(&Self::Item) -> Result<bool, Self::Error>, + { + let mut a = B::default(); + let mut b = B::default(); + + self.for_each(|i| { + if f(&i)? { + a.extend(Some(i)); + } else { + b.extend(Some(i)); + } + Ok(()) + })?; + + Ok((a, b)) + } + + /// Applies a function over the elements of the iterator, producing a single + /// final value. + #[inline] + fn fold<B, F>(mut self, init: B, f: F) -> Result<B, Self::Error> + where + Self: Sized, + F: FnMut(B, Self::Item) -> Result<B, Self::Error>, + { + self.try_fold(init, f) + } + + /// Applies a function over the elements of the iterator, producing a single final value. + /// + /// This is used as the "base" of many methods on `FallibleIterator`. + #[inline] + fn try_fold<B, E, F>(&mut self, mut init: B, mut f: F) -> Result<B, E> + where + Self: Sized, + E: From<Self::Error>, + F: FnMut(B, Self::Item) -> Result<B, E>, + { + while let Some(v) = self.next()? { + init = f(init, v)?; + } + Ok(init) + } + + /// Determines if all elements of this iterator match a predicate. + #[inline] + fn all<F>(&mut self, mut f: F) -> Result<bool, Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<bool, Self::Error>, + { + self.try_fold((), |(), v| { + if !f(v)? { + return Err(FoldStop::Break(false)); + } + Ok(()) + }) + .map(|()| true) + .unpack_fold() + } + + /// Determines if any element of this iterator matches a predicate. + #[inline] + fn any<F>(&mut self, mut f: F) -> Result<bool, Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<bool, Self::Error>, + { + self.try_fold((), |(), v| { + if f(v)? { + return Err(FoldStop::Break(true)); + } + Ok(()) + }) + .map(|()| false) + .unpack_fold() + } + + /// Returns the first element of the iterator that matches a predicate. + #[inline] + fn find<F>(&mut self, mut f: F) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + F: FnMut(&Self::Item) -> Result<bool, Self::Error>, + { + self.try_fold((), |(), v| { + if f(&v)? { + return Err(FoldStop::Break(Some(v))); + } + Ok(()) + }) + .map(|()| None) + .unpack_fold() + } + + /// Applies a function to the elements of the iterator, returning the first non-`None` result. + #[inline] + fn find_map<B, F>(&mut self, f: F) -> Result<Option<B>, Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<Option<B>, Self::Error>, + { + self.filter_map(f).next() + } + + /// Returns the position of the first element of this iterator that matches + /// a predicate. The predicate may fail; such failures are returned to the + /// caller. + #[inline] + fn position<F>(&mut self, mut f: F) -> Result<Option<usize>, Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<bool, Self::Error>, + { + self.try_fold(0, |n, v| { + if f(v)? { + return Err(FoldStop::Break(Some(n))); + } + Ok(n + 1) + }) + .map(|_| None) + .unpack_fold() + } + + /// Returns the maximal element of the iterator. + #[inline] + fn max(self) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + Self::Item: Ord, + { + self.max_by(|a, b| Ok(a.cmp(b))) + } + + /// Returns the element of the iterator which gives the maximum value from + /// the function. + #[inline] + fn max_by_key<B, F>(mut self, mut f: F) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + B: Ord, + F: FnMut(&Self::Item) -> Result<B, Self::Error>, + { + let max = match self.next()? { + Some(v) => (f(&v)?, v), + None => return Ok(None), + }; + + self.fold(max, |(key, max), v| { + let new_key = f(&v)?; + if key > new_key { + Ok((key, max)) + } else { + Ok((new_key, v)) + } + }) + .map(|v| Some(v.1)) + } + + /// Returns the element that gives the maximum value with respect to the function. + #[inline] + fn max_by<F>(mut self, mut f: F) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Result<Ordering, Self::Error>, + { + let max = match self.next()? { + Some(v) => v, + None => return Ok(None), + }; + + self.fold(max, |max, v| { + if f(&max, &v)? == Ordering::Greater { + Ok(max) + } else { + Ok(v) + } + }) + .map(Some) + } + + /// Returns the minimal element of the iterator. + #[inline] + fn min(self) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + Self::Item: Ord, + { + self.min_by(|a, b| Ok(a.cmp(b))) + } + + /// Returns the element of the iterator which gives the minimum value from + /// the function. + #[inline] + fn min_by_key<B, F>(mut self, mut f: F) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + B: Ord, + F: FnMut(&Self::Item) -> Result<B, Self::Error>, + { + let min = match self.next()? { + Some(v) => (f(&v)?, v), + None => return Ok(None), + }; + + self.fold(min, |(key, min), v| { + let new_key = f(&v)?; + if key < new_key { + Ok((key, min)) + } else { + Ok((new_key, v)) + } + }) + .map(|v| Some(v.1)) + } + + /// Returns the element that gives the minimum value with respect to the function. + #[inline] + fn min_by<F>(mut self, mut f: F) -> Result<Option<Self::Item>, Self::Error> + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Result<Ordering, Self::Error>, + { + let min = match self.next()? { + Some(v) => v, + None => return Ok(None), + }; + + self.fold(min, |min, v| { + if f(&min, &v)? == Ordering::Less { + Ok(min) + } else { + Ok(v) + } + }) + .map(Some) + } + + /// Returns an iterator that yields this iterator's items in the opposite + /// order. + #[inline] + fn rev(self) -> Rev<Self> + where + Self: Sized + DoubleEndedFallibleIterator, + { + Rev(self) + } + + /// Converts an iterator of pairs into a pair of containers. + #[inline] + fn unzip<A, B, FromA, FromB>(self) -> Result<(FromA, FromB), Self::Error> + where + Self: Sized + FallibleIterator<Item = (A, B)>, + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + { + let mut from_a = FromA::default(); + let mut from_b = FromB::default(); + + self.for_each(|(a, b)| { + from_a.extend(Some(a)); + from_b.extend(Some(b)); + Ok(()) + })?; + + Ok((from_a, from_b)) + } + + /// Returns an iterator which clones all of its elements. + #[inline] + fn cloned<'a, T>(self) -> Cloned<Self> + where + Self: Sized + FallibleIterator<Item = &'a T>, + T: 'a + Clone, + { + Cloned(self) + } + + /// Returns an iterator which repeas this iterator endlessly. + #[inline] + fn cycle(self) -> Cycle<Self> + where + Self: Sized + Clone, + { + Cycle { + it: self.clone(), + cur: self, + } + } + + /// Lexicographically compares the elements of this iterator to that of + /// another. + #[inline] + fn cmp<I>(mut self, other: I) -> Result<Ordering, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Item = Self::Item, Error = Self::Error>, + Self::Item: Ord, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(Ordering::Equal), + (None, _) => return Ok(Ordering::Less), + (_, None) => return Ok(Ordering::Greater), + (Some(x), Some(y)) => match x.cmp(&y) { + Ordering::Equal => {} + o => return Ok(o), + }, + } + } + } + + /// Lexicographically compares the elements of this iterator to that of + /// another. + #[inline] + fn partial_cmp<I>(mut self, other: I) -> Result<Option<Ordering>, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialOrd<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(Some(Ordering::Equal)), + (None, _) => return Ok(Some(Ordering::Less)), + (_, None) => return Ok(Some(Ordering::Greater)), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Equal) => {} + o => return Ok(o), + }, + } + } + } + + /// Determines if the elements of this iterator are equal to those of + /// another. + #[inline] + fn eq<I>(mut self, other: I) -> Result<bool, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialEq<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(true), + (None, _) | (_, None) => return Ok(false), + (Some(x), Some(y)) => { + if x != y { + return Ok(false); + } + } + } + } + } + + /// Determines if the elements of this iterator are not equal to those of + /// another. + #[inline] + fn ne<I>(mut self, other: I) -> Result<bool, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialEq<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(false), + (None, _) | (_, None) => return Ok(true), + (Some(x), Some(y)) => { + if x != y { + return Ok(true); + } + } + } + } + } + + /// Determines if the elements of this iterator are lexicographically less + /// than those of another. + #[inline] + fn lt<I>(mut self, other: I) -> Result<bool, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialOrd<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(false), + (None, _) => return Ok(true), + (_, None) => return Ok(false), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(true), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(false), + None => return Ok(false), + }, + } + } + } + + /// Determines if the elements of this iterator are lexicographically less + /// than or equal to those of another. + #[inline] + fn le<I>(mut self, other: I) -> Result<bool, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialOrd<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(true), + (None, _) => return Ok(true), + (_, None) => return Ok(false), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(true), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(false), + None => return Ok(false), + }, + } + } + } + + /// Determines if the elements of this iterator are lexicographically + /// greater than those of another. + #[inline] + fn gt<I>(mut self, other: I) -> Result<bool, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialOrd<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(false), + (None, _) => return Ok(false), + (_, None) => return Ok(true), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(false), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(true), + None => return Ok(false), + }, + } + } + } + + /// Determines if the elements of this iterator are lexicographically + /// greater than or equal to those of another. + #[inline] + fn ge<I>(mut self, other: I) -> Result<bool, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator<Error = Self::Error>, + Self::Item: PartialOrd<I::Item>, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(true), + (None, _) => return Ok(false), + (_, None) => return Ok(true), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(false), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(true), + None => return Ok(false), + }, + } + } + } + + /// Returns a normal (non-fallible) iterator over `Result<Item, Error>`. + #[inline] + fn iterator(self) -> Iterator<Self> + where + Self: Sized, + { + Iterator(self) + } + + /// Returns an iterator which applies a transform to the errors of the + /// underlying iterator. + #[inline] + fn map_err<B, F>(self, f: F) -> MapErr<Self, F> + where + F: FnMut(Self::Error) -> B, + Self: Sized, + { + MapErr { it: self, f: f } + } +} + +impl<I: FallibleIterator + ?Sized> FallibleIterator for &mut I { + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + (**self).next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Result<Option<I::Item>, I::Error> { + (**self).nth(n) + } +} + +impl<I: DoubleEndedFallibleIterator + ?Sized> DoubleEndedFallibleIterator for &mut I { + #[inline] + fn next_back(&mut self) -> Result<Option<I::Item>, I::Error> { + (**self).next_back() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<I: FallibleIterator + ?Sized> FallibleIterator for Box<I> { + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + (**self).next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Result<Option<I::Item>, I::Error> { + (**self).nth(n) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<I: DoubleEndedFallibleIterator + ?Sized> DoubleEndedFallibleIterator for Box<I> { + #[inline] + fn next_back(&mut self) -> Result<Option<I::Item>, I::Error> { + (**self).next_back() + } +} + +/// A fallible iterator able to yield elements from both ends. +pub trait DoubleEndedFallibleIterator: FallibleIterator { + /// Advances the end of the iterator, returning the last value. + fn next_back(&mut self) -> Result<Option<Self::Item>, Self::Error>; + + /// Applies a function over the elements of the iterator in reverse order, producing a single final value. + #[inline] + fn rfold<B, F>(mut self, init: B, f: F) -> Result<B, Self::Error> + where + Self: Sized, + F: FnMut(B, Self::Item) -> Result<B, Self::Error>, + { + self.try_rfold(init, f) + } + + /// Applies a function over the elements of the iterator in reverse, producing a single final value. + /// + /// This is used as the "base" of many methods on `DoubleEndedFallibleIterator`. + #[inline] + fn try_rfold<B, E, F>(&mut self, mut init: B, mut f: F) -> Result<B, E> + where + Self: Sized, + E: From<Self::Error>, + F: FnMut(B, Self::Item) -> Result<B, E>, + { + while let Some(v) = self.next_back()? { + init = f(init, v)?; + } + Ok(init) + } +} + +/// Conversion from a fallible iterator. +pub trait FromFallibleIterator<T>: Sized { + /// Creates a value from a fallible iterator. + fn from_fallible_iter<I>(it: I) -> Result<Self, I::Error> + where + I: IntoFallibleIterator<Item = T>; +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<T> FromFallibleIterator<T> for Vec<T> { + #[inline] + fn from_fallible_iter<I>(it: I) -> Result<Vec<T>, I::Error> + where + I: IntoFallibleIterator<Item = T>, + { + let it = it.into_fallible_iter(); + let mut vec = Vec::with_capacity(it.size_hint().0); + it.for_each(|v| Ok(vec.push(v)))?; + Ok(vec) + } +} + +#[cfg(feature = "std")] +impl<T, S> FromFallibleIterator<T> for HashSet<T, S> +where + T: Hash + Eq, + S: BuildHasher + Default, +{ + #[inline] + fn from_fallible_iter<I>(it: I) -> Result<HashSet<T, S>, I::Error> + where + I: IntoFallibleIterator<Item = T>, + { + let it = it.into_fallible_iter(); + let mut set = HashSet::default(); + set.reserve(it.size_hint().0); + it.for_each(|v| { + set.insert(v); + Ok(()) + })?; + Ok(set) + } +} + +#[cfg(feature = "std")] +impl<K, V, S> FromFallibleIterator<(K, V)> for HashMap<K, V, S> +where + K: Hash + Eq, + S: BuildHasher + Default, +{ + #[inline] + fn from_fallible_iter<I>(it: I) -> Result<HashMap<K, V, S>, I::Error> + where + I: IntoFallibleIterator<Item = (K, V)>, + { + let it = it.into_fallible_iter(); + let mut map = HashMap::default(); + map.reserve(it.size_hint().0); + it.for_each(|(k, v)| { + map.insert(k, v); + Ok(()) + })?; + Ok(map) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<T> FromFallibleIterator<T> for BTreeSet<T> +where + T: Ord, +{ + #[inline] + fn from_fallible_iter<I>(it: I) -> Result<BTreeSet<T>, I::Error> + where + I: IntoFallibleIterator<Item = T>, + { + let it = it.into_fallible_iter(); + let mut set = BTreeSet::new(); + it.for_each(|v| { + set.insert(v); + Ok(()) + })?; + Ok(set) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<K, V> FromFallibleIterator<(K, V)> for BTreeMap<K, V> +where + K: Ord, +{ + #[inline] + fn from_fallible_iter<I>(it: I) -> Result<BTreeMap<K, V>, I::Error> + where + I: IntoFallibleIterator<Item = (K, V)>, + { + let it = it.into_fallible_iter(); + let mut map = BTreeMap::new(); + it.for_each(|(k, v)| { + map.insert(k, v); + Ok(()) + })?; + Ok(map) + } +} + +/// Conversion into a `FallibleIterator`. +pub trait IntoFallibleIterator { + /// The elements of the iterator. + type Item; + + /// The error value of the iterator. + type Error; + + /// The iterator. + type IntoFallibleIter: FallibleIterator<Item = Self::Item, Error = Self::Error>; + + /// Creates a fallible iterator from a value. + fn into_fallible_iter(self) -> Self::IntoFallibleIter; +} + +impl<I> IntoFallibleIterator for I +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + type IntoFallibleIter = I; + + #[inline] + fn into_fallible_iter(self) -> I { + self + } +} + +/// An iterator which applies a fallible transform to the elements of the +/// underlying iterator. +#[derive(Clone, Debug)] +pub struct Map<T, F> { + it: T, + f: F, +} + +impl<T, F, B> FallibleIterator for Map<T, F> +where + T: FallibleIterator, + F: FnMut(T::Item) -> Result<B, T::Error>, +{ + type Item = B; + type Error = T::Error; + + #[inline] + fn next(&mut self) -> Result<Option<B>, T::Error> { + match self.it.next() { + Ok(Some(v)) => Ok(Some((self.f)(v)?)), + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.it.size_hint() + } + + #[inline] + fn try_fold<C, E, G>(&mut self, init: C, mut f: G) -> Result<C, E> + where + E: From<T::Error>, + G: FnMut(C, B) -> Result<C, E>, + { + let map = &mut self.f; + self.it.try_fold(init, |b, v| f(b, map(v)?)) + } +} + +impl<B, F, I> DoubleEndedFallibleIterator for Map<I, F> +where + I: DoubleEndedFallibleIterator, + F: FnMut(I::Item) -> Result<B, I::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<B>, I::Error> { + match self.it.next_back() { + Ok(Some(v)) => Ok(Some((self.f)(v)?)), + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + + #[inline] + fn try_rfold<C, E, G>(&mut self, init: C, mut f: G) -> Result<C, E> + where + E: From<I::Error>, + G: FnMut(C, B) -> Result<C, E>, + { + let map = &mut self.f; + self.it.try_rfold(init, |acc, v| f(acc, map(v)?)) + } +} + +#[derive(Clone, Debug)] +enum ChainState { + Both, + Front, + Back, +} + +/// An iterator which yields the elements of one iterator followed by another. +#[derive(Clone, Debug)] +pub struct Chain<T, U> { + front: T, + back: U, + state: ChainState, +} + +impl<T, U> FallibleIterator for Chain<T, U> +where + T: FallibleIterator, + U: FallibleIterator<Item = T::Item, Error = T::Error>, +{ + type Item = T::Item; + type Error = T::Error; + + #[inline] + fn next(&mut self) -> Result<Option<T::Item>, T::Error> { + match self.state { + ChainState::Both => match self.front.next()? { + Some(e) => Ok(Some(e)), + None => { + self.state = ChainState::Back; + self.back.next() + } + }, + ChainState::Front => self.front.next(), + ChainState::Back => self.back.next(), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let front_hint = self.front.size_hint(); + let back_hint = self.back.size_hint(); + + let low = front_hint.0.saturating_add(back_hint.0); + let high = match (front_hint.1, back_hint.1) { + (Some(f), Some(b)) => f.checked_add(b), + _ => None, + }; + + (low, high) + } + + #[inline] + fn count(self) -> Result<usize, T::Error> { + match self.state { + ChainState::Both => Ok(self.front.count()? + self.back.count()?), + ChainState::Front => self.front.count(), + ChainState::Back => self.back.count(), + } + } + + #[inline] + fn try_fold<B, E, F>(&mut self, init: B, mut f: F) -> Result<B, E> + where + E: From<T::Error>, + F: FnMut(B, T::Item) -> Result<B, E>, + { + match self.state { + ChainState::Both => { + let init = self.front.try_fold(init, &mut f)?; + self.state = ChainState::Back; + self.back.try_fold(init, f) + } + ChainState::Front => self.front.try_fold(init, f), + ChainState::Back => self.back.try_fold(init, f), + } + } + + #[inline] + fn find<F>(&mut self, mut f: F) -> Result<Option<T::Item>, T::Error> + where + F: FnMut(&T::Item) -> Result<bool, T::Error>, + { + match self.state { + ChainState::Both => match self.front.find(&mut f)? { + Some(v) => Ok(Some(v)), + None => { + self.state = ChainState::Back; + self.back.find(f) + } + }, + ChainState::Front => self.front.find(f), + ChainState::Back => self.back.find(f), + } + } + + #[inline] + fn last(self) -> Result<Option<T::Item>, T::Error> { + match self.state { + ChainState::Both => { + self.front.last()?; + self.back.last() + } + ChainState::Front => self.front.last(), + ChainState::Back => self.back.last(), + } + } +} + +impl<T, U> DoubleEndedFallibleIterator for Chain<T, U> +where + T: DoubleEndedFallibleIterator, + U: DoubleEndedFallibleIterator<Item = T::Item, Error = T::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<T::Item>, T::Error> { + match self.state { + ChainState::Both => match self.back.next_back()? { + Some(e) => Ok(Some(e)), + None => { + self.state = ChainState::Front; + self.front.next_back() + } + }, + ChainState::Front => self.front.next_back(), + ChainState::Back => self.back.next_back(), + } + } + + #[inline] + fn try_rfold<B, E, F>(&mut self, init: B, mut f: F) -> Result<B, E> + where + E: From<T::Error>, + F: FnMut(B, T::Item) -> Result<B, E>, + { + match self.state { + ChainState::Both => { + let init = self.back.try_rfold(init, &mut f)?; + self.state = ChainState::Front; + self.front.try_rfold(init, f) + } + ChainState::Front => self.front.try_rfold(init, f), + ChainState::Back => self.back.try_rfold(init, f), + } + } +} + +/// An iterator which clones the elements of the underlying iterator. +#[derive(Clone, Debug)] +pub struct Cloned<I>(I); + +impl<'a, T, I> FallibleIterator for Cloned<I> +where + I: FallibleIterator<Item = &'a T>, + T: 'a + Clone, +{ + type Item = T; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<T>, I::Error> { + self.0.next().map(|o| o.cloned()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + + #[inline] + fn try_fold<B, E, F>(&mut self, init: B, mut f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, T) -> Result<B, E>, + { + self.0.try_fold(init, |acc, v| f(acc, v.clone())) + } +} + +impl<'a, T, I> DoubleEndedFallibleIterator for Cloned<I> +where + I: DoubleEndedFallibleIterator<Item = &'a T>, + T: 'a + Clone, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<T>, I::Error> { + self.0.next_back().map(|o| o.cloned()) + } + + #[inline] + fn try_rfold<B, E, F>(&mut self, init: B, mut f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, T) -> Result<B, E>, + { + self.0.try_rfold(init, |acc, v| f(acc, v.clone())) + } +} + +/// Converts an `Iterator<Item = Result<T, E>>` into a `FallibleIterator<Item = T, Error = E>`. +#[inline] +pub fn convert<T, E, I>(it: I) -> Convert<I> +where + I: iter::Iterator<Item = Result<T, E>>, +{ + Convert(it) +} + +/// A fallible iterator that wraps a normal iterator over `Result`s. +#[derive(Clone, Debug)] +pub struct Convert<I>(I); + +impl<T, E, I> FallibleIterator for Convert<I> +where + I: iter::Iterator<Item = Result<T, E>>, +{ + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result<Option<T>, E> { + match self.0.next() { + Some(Ok(i)) => Ok(Some(i)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + + #[inline] + fn try_fold<B, E2, F>(&mut self, init: B, mut f: F) -> Result<B, E2> + where + E2: From<E>, + F: FnMut(B, T) -> Result<B, E2>, + { + self.0.try_fold(init, |acc, v| f(acc, v?)) + } +} + +impl<T, E, I> DoubleEndedFallibleIterator for Convert<I> +where + I: DoubleEndedIterator<Item = Result<T, E>>, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<T>, E> { + match self.0.next_back() { + Some(Ok(i)) => Ok(Some(i)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } + + #[inline] + fn try_rfold<B, E2, F>(&mut self, init: B, mut f: F) -> Result<B, E2> + where + E2: From<E>, + F: FnMut(B, T) -> Result<B, E2>, + { + self.0.try_rfold(init, |acc, v| f(acc, v?)) + } +} + +/// An iterator that yields the iteration count as well as the values of the +/// underlying iterator. +#[derive(Clone, Debug)] +pub struct Enumerate<I> { + it: I, + n: usize, +} + +impl<I> FallibleIterator for Enumerate<I> +where + I: FallibleIterator, +{ + type Item = (usize, I::Item); + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<(usize, I::Item)>, I::Error> { + self.it.next().map(|o| { + o.map(|e| { + let i = self.n; + self.n += 1; + (i, e) + }) + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.it.size_hint() + } + + #[inline] + fn count(self) -> Result<usize, I::Error> { + self.it.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Result<Option<(usize, I::Item)>, I::Error> { + match self.it.nth(n)? { + Some(v) => { + let i = self.n + n; + self.n = i + 1; + Ok(Some((i, v))) + } + None => Ok(None), + } + } + + #[inline] + fn try_fold<B, E, F>(&mut self, init: B, mut f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, (usize, I::Item)) -> Result<B, E>, + { + let n = &mut self.n; + self.it.try_fold(init, |acc, v| { + let i = *n; + *n += 1; + f(acc, (i, v)) + }) + } +} + +/// An iterator which uses a fallible predicate to determine which values of the +/// underlying iterator should be yielded. +#[derive(Clone, Debug)] +pub struct Filter<I, F> { + it: I, + f: F, +} + +impl<I, F> FallibleIterator for Filter<I, F> +where + I: FallibleIterator, + F: FnMut(&I::Item) -> Result<bool, I::Error>, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + let filter = &mut self.f; + self.it + .try_fold((), |(), v| { + if filter(&v)? { + return Err(FoldStop::Break(Some(v))); + } + Ok(()) + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (0, self.it.size_hint().1) + } + + #[inline] + fn try_fold<B, E, G>(&mut self, init: B, mut f: G) -> Result<B, E> + where + E: From<I::Error>, + G: FnMut(B, I::Item) -> Result<B, E>, + { + let predicate = &mut self.f; + self.it.try_fold( + init, + |acc, v| { + if predicate(&v)? { + f(acc, v) + } else { + Ok(acc) + } + }, + ) + } +} + +impl<I, F> DoubleEndedFallibleIterator for Filter<I, F> +where + I: DoubleEndedFallibleIterator, + F: FnMut(&I::Item) -> Result<bool, I::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<I::Item>, I::Error> { + let filter = &mut self.f; + self.it + .try_rfold((), |(), v| { + if filter(&v)? { + return Err(FoldStop::Break(Some(v))); + } + Ok(()) + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn try_rfold<B, E, G>(&mut self, init: B, mut f: G) -> Result<B, E> + where + E: From<I::Error>, + G: FnMut(B, I::Item) -> Result<B, E>, + { + let predicate = &mut self.f; + self.it.try_rfold( + init, + |acc, v| { + if predicate(&v)? { + f(acc, v) + } else { + Ok(acc) + } + }, + ) + } +} + +/// An iterator which both filters and maps the values of the underlying +/// iterator. +#[derive(Clone, Debug)] +pub struct FilterMap<I, F> { + it: I, + f: F, +} + +impl<B, I, F> FallibleIterator for FilterMap<I, F> +where + I: FallibleIterator, + F: FnMut(I::Item) -> Result<Option<B>, I::Error>, +{ + type Item = B; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<B>, I::Error> { + let map = &mut self.f; + self.it + .try_fold((), |(), v| match map(v)? { + Some(v) => Err(FoldStop::Break(Some(v))), + None => Ok(()), + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (0, self.it.size_hint().1) + } + + #[inline] + fn try_fold<C, E, G>(&mut self, init: C, mut f: G) -> Result<C, E> + where + E: From<I::Error>, + G: FnMut(C, B) -> Result<C, E>, + { + let map = &mut self.f; + self.it.try_fold(init, |acc, v| match map(v)? { + Some(v) => f(acc, v), + None => Ok(acc), + }) + } +} + +impl<B, I, F> DoubleEndedFallibleIterator for FilterMap<I, F> +where + I: DoubleEndedFallibleIterator, + F: FnMut(I::Item) -> Result<Option<B>, I::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<B>, I::Error> { + let map = &mut self.f; + self.it + .try_rfold((), |(), v| match map(v)? { + Some(v) => Err(FoldStop::Break(Some(v))), + None => Ok(()), + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn try_rfold<C, E, G>(&mut self, init: C, mut f: G) -> Result<C, E> + where + E: From<I::Error>, + G: FnMut(C, B) -> Result<C, E>, + { + let map = &mut self.f; + self.it.try_rfold(init, |acc, v| match map(v)? { + Some(v) => f(acc, v), + None => Ok(acc), + }) + } +} + +/// An iterator which maps each element to another iterator, yielding those iterator's elements. +#[derive(Clone, Debug)] +pub struct FlatMap<I, U, F> +where + U: IntoFallibleIterator, +{ + it: Map<I, F>, + cur: Option<U::IntoFallibleIter>, +} + +impl<I, U, F> FallibleIterator for FlatMap<I, U, F> +where + I: FallibleIterator, + U: IntoFallibleIterator<Error = I::Error>, + F: FnMut(I::Item) -> Result<U, I::Error>, +{ + type Item = U::Item; + type Error = U::Error; + + #[inline] + fn next(&mut self) -> Result<Option<U::Item>, U::Error> { + loop { + if let Some(it) = &mut self.cur { + if let Some(v) = it.next()? { + return Ok(Some(v)); + } + } + match self.it.next()? { + Some(it) => self.cur = Some(it.into_fallible_iter()), + None => return Ok(None), + } + } + } + + #[inline] + fn try_fold<B, E, G>(&mut self, init: B, mut f: G) -> Result<B, E> + where + E: From<U::Error>, + G: FnMut(B, U::Item) -> Result<B, E>, + { + let mut acc = init; + if let Some(cur) = &mut self.cur { + acc = cur.try_fold(acc, &mut f)?; + self.cur = None; + } + + let cur = &mut self.cur; + self.it.try_fold(acc, |acc, v| { + let mut it = v.into_fallible_iter(); + match it.try_fold(acc, &mut f) { + Ok(acc) => Ok(acc), + Err(e) => { + *cur = Some(it); + Err(e) + } + } + }) + } +} + +/// An iterator which flattens an iterator of iterators, yielding those iterators' elements. +pub struct Flatten<I> +where + I: FallibleIterator, + I::Item: IntoFallibleIterator, +{ + it: I, + cur: Option<<I::Item as IntoFallibleIterator>::IntoFallibleIter>, +} + +impl<I> Clone for Flatten<I> +where + I: FallibleIterator + Clone, + I::Item: IntoFallibleIterator, + <I::Item as IntoFallibleIterator>::IntoFallibleIter: Clone, +{ + #[inline] + fn clone(&self) -> Flatten<I> { + Flatten { + it: self.it.clone(), + cur: self.cur.clone(), + } + } +} + +impl<I> FallibleIterator for Flatten<I> +where + I: FallibleIterator, + I::Item: IntoFallibleIterator<Error = I::Error>, +{ + type Item = <I::Item as IntoFallibleIterator>::Item; + type Error = <I::Item as IntoFallibleIterator>::Error; + + #[inline] + fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> { + loop { + if let Some(it) = &mut self.cur { + if let Some(v) = it.next()? { + return Ok(Some(v)); + } + } + match self.it.next()? { + Some(it) => self.cur = Some(it.into_fallible_iter()), + None => return Ok(None), + } + } + } + + #[inline] + fn try_fold<B, E, G>(&mut self, init: B, mut f: G) -> Result<B, E> + where + E: From<Self::Error>, + G: FnMut(B, Self::Item) -> Result<B, E>, + { + let mut acc = init; + if let Some(cur) = &mut self.cur { + acc = cur.try_fold(acc, &mut f)?; + self.cur = None; + } + + let cur = &mut self.cur; + self.it.try_fold(acc, |acc, v| { + let mut it = v.into_fallible_iter(); + match it.try_fold(acc, &mut f) { + Ok(acc) => Ok(acc), + Err(e) => { + *cur = Some(it); + Err(e) + } + } + }) + } +} + +/// An iterator that yields `Ok(None)` forever after the underlying iterator +/// yields `Ok(None)` once. +#[derive(Clone, Debug)] +pub struct Fuse<I> { + it: I, + done: bool, +} + +impl<I> FallibleIterator for Fuse<I> +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + if self.done { + return Ok(None); + } + + match self.it.next()? { + Some(i) => Ok(Some(i)), + None => { + self.done = true; + Ok(None) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + if self.done { + (0, Some(0)) + } else { + self.it.size_hint() + } + } + + #[inline] + fn count(self) -> Result<usize, I::Error> { + if self.done { + Ok(0) + } else { + self.it.count() + } + } + + #[inline] + fn last(self) -> Result<Option<I::Item>, I::Error> { + if self.done { + Ok(None) + } else { + self.it.last() + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Result<Option<I::Item>, I::Error> { + if self.done { + Ok(None) + } else { + let v = self.it.nth(n)?; + if v.is_none() { + self.done = true; + } + Ok(v) + } + } + + #[inline] + fn try_fold<B, E, F>(&mut self, init: B, f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, I::Item) -> Result<B, E>, + { + if self.done { + Ok(init) + } else { + self.it.try_fold(init, f) + } + } +} + +/// An iterator which passes each element to a closure before returning it. +#[derive(Clone, Debug)] +pub struct Inspect<I, F> { + it: I, + f: F, +} + +impl<I, F> FallibleIterator for Inspect<I, F> +where + I: FallibleIterator, + F: FnMut(&I::Item) -> Result<(), I::Error>, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + match self.it.next()? { + Some(i) => { + (self.f)(&i)?; + Ok(Some(i)) + } + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.it.size_hint() + } + + #[inline] + fn try_fold<B, E, G>(&mut self, init: B, mut f: G) -> Result<B, E> + where + E: From<I::Error>, + G: FnMut(B, I::Item) -> Result<B, E>, + { + let inspect = &mut self.f; + self.it.try_fold(init, |acc, v| { + inspect(&v)?; + f(acc, v) + }) + } +} + +impl<I, F> DoubleEndedFallibleIterator for Inspect<I, F> +where + I: DoubleEndedFallibleIterator, + F: FnMut(&I::Item) -> Result<(), I::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<I::Item>, I::Error> { + match self.it.next_back()? { + Some(i) => { + (self.f)(&i)?; + Ok(Some(i)) + } + None => Ok(None), + } + } + + #[inline] + fn try_rfold<B, E, G>(&mut self, init: B, mut f: G) -> Result<B, E> + where + E: From<I::Error>, + G: FnMut(B, I::Item) -> Result<B, E>, + { + let inspect = &mut self.f; + self.it.try_rfold(init, |acc, v| { + inspect(&v)?; + f(acc, v) + }) + } +} + +/// A normal (non-fallible) iterator which wraps a fallible iterator. +#[derive(Clone, Debug)] +pub struct Iterator<I>(I); + +impl<I> iter::Iterator for Iterator<I> +where + I: FallibleIterator, +{ + type Item = Result<I::Item, I::Error>; + + #[inline] + fn next(&mut self) -> Option<Result<I::Item, I::Error>> { + match self.0.next() { + Ok(Some(v)) => Some(Ok(v)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +impl<I> DoubleEndedIterator for Iterator<I> +where + I: DoubleEndedFallibleIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<Result<I::Item, I::Error>> { + match self.0.next_back() { + Ok(Some(v)) => Some(Ok(v)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } +} + +/// An iterator which applies a transform to the errors of the underlying +/// iterator. +#[derive(Clone, Debug)] +pub struct MapErr<I, F> { + it: I, + f: F, +} + +impl<B, F, I> FallibleIterator for MapErr<I, F> +where + I: FallibleIterator, + F: FnMut(I::Error) -> B, +{ + type Item = I::Item; + type Error = B; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, B> { + self.it.next().map_err(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.it.size_hint() + } + + #[inline] + fn count(mut self) -> Result<usize, B> { + self.it.count().map_err(&mut self.f) + } + + #[inline] + fn last(mut self) -> Result<Option<I::Item>, B> { + self.it.last().map_err(&mut self.f) + } + + #[inline] + fn nth(&mut self, n: usize) -> Result<Option<I::Item>, B> { + self.it.nth(n).map_err(&mut self.f) + } + + #[inline] + fn try_fold<C, E, G>(&mut self, init: C, mut f: G) -> Result<C, E> + where + E: From<B>, + G: FnMut(C, I::Item) -> Result<C, E>, + { + self.it + .try_fold(init, |acc, v| f(acc, v).map_err(MappedErr::Fold)) + .map_err(|e| match e { + MappedErr::It(e) => (self.f)(e).into(), + MappedErr::Fold(e) => e, + }) + } +} + +impl<B, F, I> DoubleEndedFallibleIterator for MapErr<I, F> +where + I: DoubleEndedFallibleIterator, + F: FnMut(I::Error) -> B, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<I::Item>, B> { + self.it.next_back().map_err(&mut self.f) + } + + #[inline] + fn try_rfold<C, E, G>(&mut self, init: C, mut f: G) -> Result<C, E> + where + E: From<B>, + G: FnMut(C, I::Item) -> Result<C, E>, + { + self.it + .try_rfold(init, |acc, v| f(acc, v).map_err(MappedErr::Fold)) + .map_err(|e| match e { + MappedErr::It(e) => (self.f)(e).into(), + MappedErr::Fold(e) => e, + }) + } +} + +enum MappedErr<T, U> { + It(T), + Fold(U), +} + +impl<T, U> From<T> for MappedErr<T, U> { + #[inline] + fn from(t: T) -> MappedErr<T, U> { + MappedErr::It(t) + } +} + +/// An iterator which can look at the next element without consuming it. +#[derive(Clone, Debug)] +pub struct Peekable<I: FallibleIterator> { + it: I, + next: Option<I::Item>, +} + +impl<I> Peekable<I> +where + I: FallibleIterator, +{ + /// Returns a reference to the next value without advancing the iterator. + #[inline] + pub fn peek(&mut self) -> Result<Option<&I::Item>, I::Error> { + if self.next.is_none() { + self.next = self.it.next()?; + } + + Ok(self.next.as_ref()) + } +} + +impl<I> FallibleIterator for Peekable<I> +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + if let Some(next) = self.next.take() { + return Ok(Some(next)); + } + + self.it.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let mut hint = self.it.size_hint(); + if self.next.is_some() { + hint.0 = hint.0.saturating_add(1); + hint.1 = hint.1.and_then(|h| h.checked_add(1)); + } + hint + } + + #[inline] + fn try_fold<B, E, F>(&mut self, init: B, mut f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, I::Item) -> Result<B, E>, + { + let mut acc = init; + if let Some(v) = self.next.take() { + acc = f(acc, v)?; + } + self.it.try_fold(acc, f) + } +} + +/// An iterator which yields elements of the underlying iterator in reverse +/// order. +#[derive(Clone, Debug)] +pub struct Rev<I>(I); + +impl<I> FallibleIterator for Rev<I> +where + I: DoubleEndedFallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + self.0.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + + #[inline] + fn count(self) -> Result<usize, I::Error> { + self.0.count() + } + + #[inline] + fn try_fold<B, E, F>(&mut self, init: B, f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, I::Item) -> Result<B, E>, + { + self.0.try_rfold(init, f) + } +} + +impl<I> DoubleEndedFallibleIterator for Rev<I> +where + I: DoubleEndedFallibleIterator, +{ + #[inline] + fn next_back(&mut self) -> Result<Option<I::Item>, I::Error> { + self.0.next() + } + + #[inline] + fn try_rfold<B, E, F>(&mut self, init: B, f: F) -> Result<B, E> + where + E: From<I::Error>, + F: FnMut(B, I::Item) -> Result<B, E>, + { + self.0.try_fold(init, f) + } +} + +/// An iterator which applies a stateful closure. +#[derive(Clone, Debug)] +pub struct Scan<I, St, F> { + it: I, + f: F, + state: St, +} + +impl<B, I, St, F> FallibleIterator for Scan<I, St, F> +where + I: FallibleIterator, + F: FnMut(&mut St, I::Item) -> Result<Option<B>, I::Error>, +{ + type Item = B; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<B>, I::Error> { + match self.it.next()? { + Some(v) => (self.f)(&mut self.state, v), + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let hint = self.it.size_hint(); + (0, hint.1) + } +} + +/// An iterator which skips initial elements. +#[derive(Clone, Debug)] +pub struct Skip<I> { + it: I, + n: usize, +} + +impl<I> FallibleIterator for Skip<I> +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + if self.n == 0 { + self.it.next() + } else { + let n = self.n; + self.n = 0; + self.it.nth(n) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let hint = self.it.size_hint(); + + ( + hint.0.saturating_sub(self.n), + hint.1.map(|x| x.saturating_sub(self.n)), + ) + } +} + +/// An iterator which skips initial elements based on a predicate. +#[derive(Clone, Debug)] +pub struct SkipWhile<I, P> { + it: I, + flag: bool, + predicate: P, +} + +impl<I, P> FallibleIterator for SkipWhile<I, P> +where + I: FallibleIterator, + P: FnMut(&I::Item) -> Result<bool, I::Error>, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + let flag = &mut self.flag; + let pred = &mut self.predicate; + self.it.find(move |x| { + if *flag || !pred(x)? { + *flag = true; + Ok(true) + } else { + Ok(false) + } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let hint = self.it.size_hint(); + if self.flag { + hint + } else { + (0, hint.1) + } + } +} + +/// An iterator which steps through the elements of the underlying iterator by a certain amount. +#[derive(Clone, Debug)] +pub struct StepBy<I> { + it: I, + step: usize, + first_take: bool, +} + +impl<I> FallibleIterator for StepBy<I> +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + if self.first_take { + self.first_take = false; + self.it.next() + } else { + self.it.nth(self.step) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let inner_hint = self.it.size_hint(); + + if self.first_take { + let f = |n| { + if n == 0 { + 0 + } else { + 1 + (n - 1) / (self.step + 1) + } + }; + (f(inner_hint.0), inner_hint.1.map(f)) + } else { + let f = |n| n / (self.step + 1); + (f(inner_hint.0), inner_hint.1.map(f)) + } + } +} + +/// An iterator which yields a limited number of elements from the underlying +/// iterator. +#[derive(Clone, Debug)] +pub struct Take<I> { + it: I, + remaining: usize, +} + +impl<I> FallibleIterator for Take<I> +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + if self.remaining == 0 { + return Ok(None); + } + + let next = self.it.next(); + if let Ok(Some(_)) = next { + self.remaining -= 1; + } + next + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let hint = self.it.size_hint(); + ( + cmp::min(hint.0, self.remaining), + hint.1.map(|n| cmp::min(n, self.remaining)), + ) + } +} + +/// An iterator which yields elements based on a predicate. +#[derive(Clone, Debug)] +pub struct TakeWhile<I, P> { + it: I, + flag: bool, + predicate: P, +} + +impl<I, P> FallibleIterator for TakeWhile<I, P> +where + I: FallibleIterator, + P: FnMut(&I::Item) -> Result<bool, I::Error>, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + if self.flag { + Ok(None) + } else { + match self.it.next()? { + Some(item) => { + if (self.predicate)(&item)? { + Ok(Some(item)) + } else { + self.flag = true; + Ok(None) + } + } + None => Ok(None), + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + if self.flag { + (0, Some(0)) + } else { + let hint = self.it.size_hint(); + (0, hint.1) + } + } +} + +/// An iterator which cycles another endlessly. +#[derive(Clone, Debug)] +pub struct Cycle<I> { + it: I, + cur: I, +} + +impl<I> FallibleIterator for Cycle<I> +where + I: FallibleIterator + Clone, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result<Option<I::Item>, I::Error> { + match self.cur.next()? { + None => { + self.cur = self.it.clone(); + self.cur.next() + } + Some(v) => Ok(Some(v)), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (usize::max_value(), None) + } +} + +/// An iterator that yields pairs of this iterator's and another iterator's +/// values. +#[derive(Clone, Debug)] +pub struct Zip<T, U>(T, U); + +impl<T, U> FallibleIterator for Zip<T, U> +where + T: FallibleIterator, + U: FallibleIterator<Error = T::Error>, +{ + type Item = (T::Item, U::Item); + type Error = T::Error; + + #[inline] + fn next(&mut self) -> Result<Option<(T::Item, U::Item)>, T::Error> { + match (self.0.next()?, self.1.next()?) { + (Some(a), Some(b)) => Ok(Some((a, b))), + _ => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let a = self.0.size_hint(); + let b = self.1.size_hint(); + + let low = cmp::min(a.0, b.0); + + let high = match (a.1, b.1) { + (Some(a), Some(b)) => Some(cmp::min(a, b)), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + }; + + (low, high) + } +} + +fn _is_object_safe(_: &dyn DoubleEndedFallibleIterator<Item = (), Error = ()>) {} diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..f7627c4 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,455 @@ +use core::iter; +use core::ops::Range; + +use super::{convert, FallibleIterator, Vec}; + +#[test] +fn all() { + assert!(convert([0, 1, 2, 3].iter().map(Ok::<&u32, ()>)) + .all(|&i| Ok(i < 4)) + .unwrap()); + assert!(!convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .all(|&i| Ok(i < 4)) + .unwrap()); + assert!(convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .all(|_| Err(())) + .is_err()); +} + +#[test] +fn any() { + assert!(convert([0, 1, 2, 3].iter().map(Ok::<&u32, ()>)) + .any(|&i| Ok(i == 3)) + .unwrap()); + assert!(!convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .any(|&i| Ok(i == 3)) + .unwrap()); + assert!(convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .any(|_| Err(())) + .is_err()); +} + +#[test] +fn chain() { + let a = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, ()>)); + let b = convert(vec![4, 5, 6, 7].into_iter().map(Ok::<u32, ()>)); + let it = a.chain(b); + + assert_eq!(it.collect::<Vec<_>>().unwrap(), [0, 1, 2, 3, 4, 5, 6, 7]); + + let a = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, ()>)); + let b = convert(vec![4, 5, 6, 7].into_iter().map(Ok::<u32, ()>)); + let it = a.chain(b).rev(); + + assert_eq!(it.collect::<Vec<_>>().unwrap(), [7, 6, 5, 4, 3, 2, 1, 0]); +} + +#[test] +fn count() { + assert_eq!( + convert([0, 1, 2, 3].iter().map(Ok::<&u32, ()>)) + .count() + .unwrap(), + 4 + ); + + let it = Some(Ok(1)).into_iter().chain(iter::repeat(Err(()))); + assert!(convert(it).count().is_err()); +} + +#[test] +fn enumerate() { + let it = convert(vec![5, 6, 7, 8].into_iter().map(Ok::<u32, ()>)).enumerate(); + + assert_eq!( + it.collect::<Vec<_>>().unwrap(), + [(0, 5), (1, 6), (2, 7), (3, 8)] + ); +} + +#[test] +fn filter() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, u32>)); + let it = it.filter(|&x| if x % 2 == 0 { Ok(x % 3 == 0) } else { Err(x) }); + + assert_eq!(it.clone().collect::<Vec<_>>(), Err(1)); + assert_eq!(it.rev().collect::<Vec<_>>(), Err(3)); + + let it = convert(vec![0, 2, 4, 6].into_iter().map(Ok::<u32, u32>)); + let it = it.filter(|&x| if x % 2 == 0 { Ok(x % 3 == 0) } else { Err(x) }); + + assert_eq!(it.clone().collect::<Vec<_>>(), Ok(vec![0, 6])); + assert_eq!(it.rev().collect::<Vec<_>>(), Ok(vec![6, 0])) +} + +#[test] +fn filter_map() { + fn twos_and_threes(x: u32) -> Result<Option<u32>, u32> { + if x % 2 == 0 { + Ok(Some(x + 10)) + } else if x % 3 == 0 { + Ok(None) + } else { + Err(x) + } + } + + let it = convert(vec![0, 1, 2, 3, 4, 5, 6].into_iter().map(Ok::<u32, u32>)) + .filter_map(twos_and_threes); + + assert_eq!(it.clone().collect::<Vec<_>>(), Err(1)); + assert_eq!(it.rev().collect::<Vec<_>>(), Err(5)); + + let it = + convert(vec![0, 2, 3, 4, 6].into_iter().map(Ok::<u32, u32>)).filter_map(twos_and_threes); + + assert_eq!(it.clone().collect::<Vec<_>>(), Ok(vec![10, 12, 14, 16])); + assert_eq!(it.rev().collect::<Vec<_>>(), Ok(vec![16, 14, 12, 10])); +} + +#[test] +fn find() { + let mut it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, u32>)); + + assert_eq!(it.find(|x| Ok(x % 2 == 1)), Ok(Some(1))); + assert_eq!(it.next(), Ok(Some(2))); + + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, u32>)); + assert_eq!( + it.clone() + .find(|&x| if x == 2 { Err(29) } else { Ok(false) }), + Err(29) + ); + assert_eq!( + it.clone() + .find(|&x| if x == 2 { Err(29) } else { Ok(true) }), + Ok(Some(0)) + ); + assert_eq!( + it.clone() + .rev() + .find(|&x| if x == 2 { Err(29) } else { Ok(false) }), + Err(29) + ); + assert_eq!( + it.rev().find(|&x| if x == 2 { Err(29) } else { Ok(true) }), + Ok(Some(3)) + ); +} + +#[test] +fn fold() { + fn add_smol(a: u32, b: u32) -> Result<u32, u32> { + if b <= 2 { + Ok(a + b) + } else { + Err(b) + } + } + + let it = convert(vec![0, 1, 3, 2].into_iter().map(Ok::<u32, u32>)); + assert_eq!(it.fold(0, add_smol), Err(3)); + + let it = convert(vec![0, 1, 2, 1].into_iter().map(Ok::<u32, u32>)); + assert_eq!(it.fold(0, add_smol), Ok(4)); +} + +#[test] +fn for_each() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, ()>)); + + let mut acc = vec![]; + it.for_each(|n| { + acc.push(n); + Ok(()) + }) + .unwrap(); + assert_eq!(acc, vec![0, 1, 2, 3]); +} + +#[test] +fn iterator() { + let it = convert( + "ab cd" + .chars() + .map(|c| if c.is_whitespace() { Err(()) } else { Ok(c) }), + ); + + assert!(it.clone().count().is_err()); + assert!(it.clone().rev().count().is_err()); + assert_eq!(it.clone().iterator().count(), 5); + assert_eq!(it.clone().iterator().rev().count(), 5); +} + +#[test] +fn last() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<u32, ()>)); + assert_eq!(it.last().unwrap(), Some(3)); +} + +#[test] +fn map() { + let it = convert(vec![0, 1, 2, 3, 4].into_iter().map(Ok::<u32, ()>)).map(|n| Ok(n * 2)); + assert_eq!(it.clone().collect::<Vec<_>>().unwrap(), [0, 2, 4, 6, 8]); + assert_eq!(it.rev().collect::<Vec<_>>().unwrap(), [8, 6, 4, 2, 0]); + + let it = convert(vec![0, 1, 2, 3, 4].into_iter().map(Ok::<u32, ()>)).map(|n| { + if n == 2 { + Err(()) + } else { + Ok(n * 2) + } + }); + + { + let mut it = it.clone(); + assert_eq!(it.next(), Ok(Some(0))); + assert_eq!(it.next(), Ok(Some(2))); + assert_eq!(it.next(), Err(())); + } + + { + let mut it = it.rev(); + assert_eq!(it.next(), Ok(Some(8))); + assert_eq!(it.next(), Ok(Some(6))); + assert_eq!(it.next(), Err(())); + } +} + +#[test] +fn map_err() { + let it = convert( + vec![0, 1, 2, 3] + .into_iter() + .map(|n| if n % 2 == 0 { Ok(n) } else { Err(n) }), + ); + + assert_eq!(it.clone().collect::<Vec<_>>(), Err(1)); + assert_eq!(it.rev().collect::<Vec<_>>(), Err(3)); +} + +#[test] +fn max() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.max().unwrap(), Some(3)); +} + +#[test] +fn max_by_key() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::<i32, i32>)); + assert_eq!(it.clone().max_by_key(|&i| Ok(-i)), Ok(Some(-10))); + // Exercise failure both on the first item, and later. + assert_eq!(it.clone().max_by_key(|&i| Err::<i32, _>(i)), Err(0)); + assert_eq!( + it.clone() + .max_by_key(|&i| if i > 0 { Err(i) } else { Ok(-i) }), + Err(3) + ); +} + +#[test] +fn max_by() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.max_by(|a, b| Ok(b.cmp(a))), Ok(Some(-10))); +} + +#[test] +fn min() { + let it = convert(vec![0, 3, -10, 1].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.min().unwrap(), Some(-10)); +} + +#[test] +fn min_by_key() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::<i32, i32>)); + assert_eq!(it.clone().min_by_key(|&i| Ok(-i)), Ok(Some(3))); + // Exercise failure both on the first item, and later. + assert_eq!(it.clone().min_by_key(|&i| Err::<i32, _>(i)), Err(0)); + assert_eq!( + it.clone() + .min_by_key(|&i| if i > 0 { Err(i) } else { Ok(-i) }), + Err(3) + ); +} + +#[test] +fn min_by() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.min_by(|a, b| Ok(b.cmp(a))), Ok(Some(3))); +} + +#[test] +fn nth() { + let mut it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.nth(1).unwrap(), Some(1)); + assert_eq!(it.nth(0).unwrap(), Some(2)); + assert_eq!(it.nth(2).unwrap(), None); +} + +#[test] +fn peekable() { + let mut it = convert(vec![0, 1].into_iter().map(Ok::<i32, ()>)).peekable(); + assert_eq!(it.peek().unwrap(), Some(&0)); + assert_eq!(it.peek().unwrap(), Some(&0)); + assert_eq!(it.next().unwrap(), Some(0)); + assert_eq!(it.next().unwrap(), Some(1)); + assert_eq!(it.peek().unwrap(), None); + assert_eq!(it.next().unwrap(), None); +} + +#[test] +fn position() { + let mut it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.position(|n| Ok(n == 2)).unwrap(), Some(1)); + assert_eq!(it.position(|n| Ok(n == 3)).unwrap(), Some(0)); + assert_eq!(it.position(|n| Ok(n == 5)).unwrap(), None); + + let it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::<i32, i32>)); + assert_eq!( + it.clone() + .position(|n| if n == 3 { Err(42) } else { Ok(n == 2) }), + Ok(Some(1)) + ); + assert_eq!( + it.clone() + .position(|n| if n == 3 { Err(42) } else { Ok(n == 4) }), + Err(42) + ); +} + +#[test] +fn scan() { + let it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::<i32, ()>)).scan(0, |st, v| { + if v > 3 { + Ok(None) + } else { + *st += v; + Ok(Some(-*st)) + } + }); + assert_eq!(it.collect::<Vec<_>>(), Ok(vec![-1, -3, -6])); +} + +#[test] +fn skip() { + let it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::<i32, ()>)); + assert_eq!(it.clone().skip(0).collect::<Vec<_>>(), Ok(vec![1, 2, 3, 4])); + assert_eq!(it.clone().skip(2).collect::<Vec<_>>(), Ok(vec![3, 4])); + assert_eq!(it.clone().skip(4).collect::<Vec<_>>(), Ok(vec![])); +} + +#[test] +fn skip_while() { + let it = convert(vec![1, 2, 3, 4, 1].into_iter().map(Ok::<i32, ()>)); + assert_eq!( + it.clone().skip_while(|x| Ok(*x < 1)).collect::<Vec<_>>(), + Ok(vec![1, 2, 3, 4, 1]) + ); + assert_eq!( + it.clone().skip_while(|x| Ok(*x < 3)).collect::<Vec<_>>(), + Ok(vec![3, 4, 1]) + ); + assert_eq!( + it.clone().skip_while(|x| Ok(*x < 5)).collect::<Vec<_>>(), + Ok(vec![]) + ); +} + +#[test] +fn step_by() { + let it = convert( + vec![0, 1, 2, 3, 4, 5, 6, 7, 8] + .into_iter() + .map(Ok::<i32, ()>), + ) + .step_by(3); + assert_eq!(it.collect::<Vec<_>>(), Ok(vec![0, 3, 6])); +} + +#[test] +fn take() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<i32, ()>)).take(2); + assert_eq!(it.collect::<Vec<_>>().unwrap(), [0, 1]); +} + +#[test] +fn take_while() { + let it = convert(vec![0, 1, 2, 3, 0].into_iter().map(Ok::<i32, ()>)); + assert_eq!( + it.clone().take_while(|x| Ok(*x < 0)).collect::<Vec<_>>(), + Ok(vec![]) + ); + assert_eq!( + it.clone().take_while(|x| Ok(*x < 2)).collect::<Vec<_>>(), + Ok(vec![0, 1]) + ); + assert_eq!( + it.clone().take_while(|x| Ok(*x < 4)).collect::<Vec<_>>(), + Ok(vec![0, 1, 2, 3, 0]) + ); +} + +#[test] +fn flat_map() { + let it = convert(vec![0..1, 0..0, 1..5].into_iter().map(Ok::<Range<i32>, ()>)) + .flat_map(|r| Ok(convert(r.map(Ok::<i32, ()>)))); + assert_eq!(it.collect::<Vec<_>>(), Ok(vec![0, 1, 2, 3, 4])); +} + +#[test] +fn flatten() { + let it = convert( + vec![0..1, 0..0, 1..5] + .into_iter() + .map(|r| convert(r.map(Ok::<i32, ()>))) + .map(Ok::<_, ()>), + ) + .flatten(); + assert_eq!(it.collect::<Vec<_>>(), Ok(vec![0, 1, 2, 3, 4])); +} + +#[test] +fn inspect() { + let mut buf = vec![]; + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<i32, ()>)).inspect(|v| Ok(buf.push(*v))); + it.count().unwrap(); + assert_eq!(buf, vec![0, 1, 2, 3]); +} + +#[test] +fn partition() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<i32, ()>)); + let (even, odd): (Vec<i32>, Vec<i32>) = it.partition(|i| Ok(*i % 2 == 0)).unwrap(); + assert_eq!(even, vec![0, 2]); + assert_eq!(odd, vec![1, 3]); +} + +#[test] +fn find_map() { + let mut it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<i32, ()>)); + assert_eq!( + it.find_map(|v| match v { + 2 => Ok(Some("hi")), + _ => Ok(None), + }), + Ok(Some("hi")) + ); +} + +#[test] +fn unzip() { + let it = convert( + vec![(0, 0), (1, -1), (2, -2), (3, -3)] + .into_iter() + .map(Ok::<_, ()>), + ); + let (pos, neg): (Vec<i32>, Vec<i32>) = it.unzip().unwrap(); + assert_eq!(pos, vec![0, 1, 2, 3]); + assert_eq!(neg, vec![0, -1, -2, -3]); +} + +#[test] +fn cycle() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::<i32, ()>)).cycle(); + assert_eq!(it.take(6).clone().collect::<Vec<_>>(), Ok(vec![0, 1, 2, 3, 0, 1])); +} |