├── .clippy.toml ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── fmt.yml │ ├── linter.yml │ ├── coverage.yml │ ├── msrv.yml │ └── test.yml ├── bors.toml ├── .gitignore ├── Cargo.toml ├── LICENSE-MIT ├── CHANGELOG.md ├── README.md ├── LICENSE-APACHE └── src └── lib.rs /.clippy.toml: -------------------------------------------------------------------------------- 1 | msrv = "1.40" 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ["foresterre"] 2 | buy_me_a_coffee: "foresterre" 3 | thanks_dev: "u/gh/foresterre" 4 | -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "fmt", 3 | "linter", 4 | "msrv", 5 | "test (ubuntu-stable)", 6 | "test (macos-stable)", 7 | "test (win-gnu-stable)", 8 | "test (win-msvc-stable)", 9 | "test (ubuntu-beta)", 10 | ] 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | 5 | # rustdoc 6 | doc 7 | 8 | # sometimes easier to create a small program than using lldb, 9 | # especially since with no_std, we can't use dbg! conveniently. 10 | src/bin/ 11 | 12 | # editors 13 | .idea/ 14 | .vscode/ -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | reviewers: 9 | - foresterre 10 | labels: 11 | - C-dependency-update 12 | allow: 13 | - dependency-type: direct 14 | - dependency-type: indirect -------------------------------------------------------------------------------- /.github/workflows/fmt.yml: -------------------------------------------------------------------------------- 1 | name: "ci-fmt" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - staging # for Bors 9 | - trying # for Bors 10 | jobs: 11 | fmt: 12 | name: fmt 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: checkout_repository 16 | uses: actions/checkout@v3 17 | 18 | - name: install_rust 19 | uses: dtolnay/rust-toolchain@stable 20 | with: 21 | components: rustfmt 22 | 23 | - name: check_formatting 24 | run: | 25 | cargo fmt -- --check 26 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: "ci-linter" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - staging # for Bors 9 | - trying # for Bors 10 | jobs: 11 | linter: 12 | name: linter 13 | runs-on: ubuntu-latest 14 | continue-on-error: true 15 | steps: 16 | - name: checkout_repo 17 | uses: actions/checkout@v3 18 | 19 | - name: install_rust 20 | uses: dtolnay/rust-toolchain@stable 21 | with: 22 | components: clippy 23 | 24 | - name: check_clippy 25 | uses: actions-rs/clippy-check@v1 26 | with: 27 | token: ${{ secrets.GITHUB_TOKEN }} 28 | args: --all-features --all-targets --workspace 29 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "peekmore" 3 | version = "1.3.0" 4 | authors = ["Martijn Gribnau "] 5 | description = "Iterator adapter like Peekable, but for peeking forward multiple elements" 6 | edition = "2018" 7 | repository = "https://github.com/foresterre/peekmore" 8 | license = "MIT OR Apache-2.0" 9 | documentation = "https://docs.rs/peekmore" 10 | readme = "README.md" 11 | exclude = [ 12 | ".idea/*", 13 | ".vscode/*", 14 | "*.iml", 15 | ] 16 | keywords = ["peek", "lookahead", "iterator", "peekable", "multipeek"] 17 | categories = ["no-std"] 18 | 19 | [package.metadata] 20 | msrv = "1.40.0" 21 | 22 | [package.metadata.release] 23 | tag-name = "v{{version}}" 24 | 25 | [features] 26 | default = [] 27 | 28 | [dependencies.smallvec] 29 | version = "1.5.1" 30 | optional = true 31 | default-features = false 32 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: "ci-coverage" 2 | on: 3 | pull_request: 4 | jobs: 5 | coverage: 6 | name: coverage 7 | runs-on: ubuntu-latest 8 | env: 9 | CARGO_TERM_COLOR: always 10 | steps: 11 | - name: checkout_repository 12 | uses: actions/checkout@v3 13 | 14 | - name: install_rust_nightly 15 | uses: dtolnay/rust-toolchain@nightly 16 | 17 | - name: install_code_coverage_tool 18 | uses: taiki-e/install-action@cargo-llvm-cov 19 | 20 | - name: generate_code_coverage 21 | # `--lib` ensures we only run unit tests, no integration tests. 22 | run: cargo llvm-cov --all-features --locked --lcov --output-path lcov.info --lib 23 | 24 | - name: upload_code_coverage 25 | uses: codecov/codecov-action@v3 26 | with: 27 | files: lcov.info 28 | -------------------------------------------------------------------------------- /.github/workflows/msrv.yml: -------------------------------------------------------------------------------- 1 | name: "ci-msrv" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - staging # for Bors 9 | - trying # for Bors 10 | schedule: 11 | - cron: '00 06 * * *' 12 | jobs: 13 | msrv: 14 | name: msrv 15 | runs-on: ubuntu-latest 16 | continue-on-error: true 17 | steps: 18 | - name: checkout_repo 19 | uses: actions/checkout@v3 20 | - name: install_rust 21 | uses: dtolnay/rust-toolchain@stable 22 | - name: install_cargo_msrv 23 | run: cargo install cargo-msrv --no-default-features 24 | - name: version_of_cargo_msrv 25 | run: cargo msrv --version 26 | - name: run_cargo_msrv 27 | run: cargo msrv --output-format json verify -- cargo check 28 | - name: run_cargo_msrv_on_verify_failure 29 | if: ${{ failure() }} 30 | run: cargo msrv --output-format json -- cargo check 31 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 foresterre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | This is the changelog for [peekmore](https://github.com/foresterre/peekmore), a multi-peek variant of Rust's 4 | [Peekable](https://doc.rust-lang.org/std/iter/struct.Peekable.html) iterator adapter. 5 | 6 | If you found an issue, have a suggestion or want to provide feedback or insights, please feel free to open an issue on 7 | the [issue tracker](https://github.com/foresterre/peekmore/issues). 8 | 9 | ## [Unreleased] 10 | 11 | 12 | 13 | [Unreleased]: https://github.com/foresterre/cargo-msrv 14 | 15 | ## [1.3.0] - 2023-06-05 16 | 17 | ### Added 18 | 19 | * Added `PeekMoreIterator::next_if` and `PeekMoreIterator::next_if_eq` #74 #75 20 | 21 | [1.3.0]: https://github.com/foresterre/peekmore/releases/tag/v1.3.0 22 | 23 | ## [1.2.1] - 2023-04-11 24 | 25 | ### Fixed 26 | 27 | * Fix issue with `advance_cursor_while`, where cursor would incorrectly be decremented #72 #73 28 | 29 | [1.2.1]: https://github.com/foresterre/peekmore/releases/tag/v1.2.1 30 | 31 | ## [1.2.0] - 2022-03-16 32 | 33 | ### Added 34 | 35 | * Added `PeekMoreIterator::cursor` method #69 #71 36 | 37 | [1.2.0]: https://github.com/foresterre/peekmore/releases/tag/v1.2.0 38 | 39 | ## [1.1.0] - 2022-02-18 40 | 41 | ### Added 42 | 43 | * Added `PeekMoreIterator::peek_first` method #61 44 | 45 | ### Fixed 46 | 47 | * Fix `PeekMoreIterator::truncate_iterator_to_cursor` #65 48 | 49 | [1.1.0]: https://github.com/foresterre/peekmore/releases/tag/v1.1.0 50 | 51 | ## [1.0.0] - 2020-12-30 52 | 53 | ### Changed 54 | 55 | * Rename peek_n to peek_amount 56 | * Updated smallvec to 1.5.0 57 | * Disable smallvec by default, can still be used by opting in with --feature smallvec 58 | 59 | [1.0.0]: https://github.com/foresterre/peekmore/releases/tag/v1.0.0 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # peekmore 2 | 3 | This crate introduces a multi-peekable iterator. 4 | The iterator is similar to [core::iterator::Peekable](https://doc.rust-lang.org/core/iter/struct.Peekable.html). 5 | The main difference is that Peekable only allows you to peek at the next element and no further. 6 | This crate aims to take that limitation away. 7 | 8 | The documentation and more extensive example usage can be found at [docs.rs/peekmore](https://docs.rs/peekmore/). 9 | 10 | ### Usage example: 11 | 12 | ```rust 13 | use peekmore::PeekMore; 14 | 15 | fn main() { 16 | let range10 = 0..11; 17 | let mut peekable = range10.peekmore(); 18 | 19 | // Peek at the first element 20 | let peek_first = peekable.peek(); 21 | assert_eq!(*peek_first.unwrap(), 0); 22 | 23 | let peek_first_redux = peekable.peek_nth(0); 24 | assert_eq!(*peek_first_redux.unwrap(), 0); 25 | 26 | // Peek at the 10th (index) element 27 | let peek_tenth = peekable.peek_nth(10); 28 | assert_eq!(*peek_tenth.unwrap(), 10); 29 | 30 | // Consume the 10th element 31 | let tenth = peekable.nth(10); 32 | assert_eq!(tenth.unwrap(), 10); 33 | 34 | // Show that there are no more elements 35 | assert_eq!(peekable.peek(), None); 36 | assert_eq!(peekable.next(), None); 37 | } 38 | 39 | ``` 40 | 41 | ### License 42 | 43 | Licensed under either of 44 | 45 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 46 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 47 | 48 | at your option. 49 | 50 | #### Contribution 51 | 52 | Unless you explicitly state otherwise, any contribution intentionally 53 | submitted for inclusion in the work by you, as defined in the Apache-2.0 54 | license, shall be dual licensed as above, without any additional terms or 55 | conditions. -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "ci-test" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - staging # for Bors 9 | - trying # for Bors 10 | schedule: 11 | - cron: '00 05 * * *' 12 | jobs: 13 | test: 14 | name: test 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | build: [ubuntu-stable, macos-stable, win-gnu-stable, win-msvc-stable, ubuntu-beta, ubuntu-nightly] 20 | include: 21 | - build: ubuntu-stable 22 | os: ubuntu-latest 23 | rust: stable 24 | 25 | - build: macos-stable 26 | os: macOS-latest 27 | rust: stable 28 | 29 | - build: win-gnu-stable 30 | os: windows-latest 31 | rust: stable-x86_64-gnu 32 | 33 | - build: win-msvc-stable 34 | os: windows-latest 35 | rust: stable 36 | 37 | - build: ubuntu-beta 38 | os: ubuntu-latest 39 | rust: beta 40 | 41 | - build: ubuntu-nightly 42 | os: ubuntu-latest 43 | rust: nightly 44 | steps: 45 | - name: checkout_repository 46 | uses: actions/checkout@v3 47 | 48 | # We would prefer to use `dtolnay/rust-toolchain@master with toolchain=${{ matrix.rust }}` or `rustup update ${{ matrix.rust }}`. 49 | # However, when using either we run into a linking issue: 50 | # `error: could not create link from 'C:\\Users\\runneradmin\\.cargo\\bin\\rustup.exe' to 'C:\\Users\\runneradmin\\.cargo\\bin\\cargo.exe'\n" })', tests\find_msrv.rs:156:39` 51 | # I find the message odd, because we only need to install the toolchain, not set it as the default, and replace the 52 | # binary; so what is meant by "link" in the above error? 53 | - name: install_rust 54 | uses: actions-rs/toolchain@v1 55 | with: 56 | toolchain: ${{ matrix.rust }} 57 | override: true 58 | profile: minimal 59 | 60 | - name: fetch 61 | run: cargo fetch --verbose 62 | 63 | - name: build 64 | run: cargo build --verbose 65 | 66 | - name: test_all_features 67 | run: cargo test --verbose --all --all-features 68 | 69 | - name: test_no_default_features 70 | run: cargo test --verbose --all --no-default-features 71 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(missing_docs)] 3 | #![deny(clippy::all)] 4 | 5 | //! **Synopsis:** 6 | //! 7 | //! This crate introduces a multi-peekable iterator. 8 | //! The iterator is similar to [`Peekable`]. The main difference is that [`Peekable`] only 9 | //! allows you to peek at the next element and no further. When using `PeekMore` however, 10 | //! you can peek at as many elements as you want. 11 | //! 12 | //! **A peek at how it works:** 13 | //! 14 | //! To enable peeking at multiple elements ahead of consuming a next element, the iterator uses a 15 | //! traversable queue which holds the elements which you can peek at, but have not been 16 | //! consumed (yet). 17 | //! The underlying data structure of this queue can be a `Vec`, or a `SmallVec` from the smallvec crate. 18 | //! By default, the `SmallVec` is used. SmallVec uses the stack for a limited amount of elements and 19 | //! will only allocate on the heap if this maximum amount of elements is reached. 20 | //! 21 | //! 22 | //! **Illustrated example:** 23 | //! 24 | //! An illustrated example can be found at the [`PeekMoreIterator::peek`] documentation. 25 | //! 26 | //! 27 | //! **Usage example:** 28 | //! 29 | //! ```rust 30 | //! use peekmore::PeekMore; 31 | //! 32 | //! let iterable = [1, 2, 3, 4]; 33 | //! let mut iter = iterable.iter().peekmore(); 34 | //! 35 | //! // Peek at the first element. 36 | //! let v1 = iter.peek(); 37 | //! assert_eq!(v1, Some(&&1)); 38 | //! 39 | //! // Consume the first element. 40 | //! let v1c = iter.next(); 41 | //! assert_eq!(v1c, Some(&1)); 42 | //! 43 | //! // Peek at the second element (the element our cursor points at also moved to the second element, 44 | //! // since the first element was consumed.) 45 | //! let v2 = iter.peek(); 46 | //! assert_eq!(v2, Some(&&2)); 47 | //! 48 | //! // Advance the cursor. The cursor will now point to the third element. 49 | //! let _ = iter.advance_cursor(); 50 | //! 51 | //! // Check that it is indeed at the third element. 52 | //! let v3 = iter.peek(); 53 | //! assert_eq!(v3, Some(&&3)); 54 | //! 55 | //! // Reset the position the cursor points at. The cursor will point to the first unconsumed element 56 | //! // again. 57 | //! iter.reset_cursor(); 58 | //! 59 | //! // Check that we are indeed at the second element again. 60 | //! let v2 = iter.peek(); 61 | //! assert_eq!(v2, Some(&&2)); 62 | //! 63 | //! // Shift the position of the cursor to the right twice by chaining the advance_view method. 64 | //! let _ = iter.advance_cursor().advance_cursor(); 65 | //! 66 | //! // Verify that the cursor indeed points at the fourth element. 67 | //! let v4 = iter.peek(); 68 | //! assert_eq!(v4, Some(&&4)); 69 | //! 70 | //! // Reset the position which the cursor points at again. 71 | //! iter.reset_cursor(); 72 | //! 73 | //! // We can also advance the cursor and peek with a single operation. 74 | //! let v3 = iter.peek_next(); 75 | //! assert_eq!(v3, Some(&&3)); 76 | //! ``` 77 | //! 78 | //! 79 | //! [`Peekable`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html 80 | //! [`PeekMoreIterator::peek`]: struct.PeekMoreIterator.html#method.peek 81 | //! [requires]: https://github.com/servo/rust-smallvec/issues/160 82 | 83 | /// We need to allocate elements which haven't been consumed by the PeekMore iterator. 84 | extern crate alloc; 85 | 86 | /// Import std only when running doc tests without errors. Std will not be included outside of 87 | /// doctest based binaries. 88 | /// 89 | /// See [rust#54010](https://github.com/rust-lang/rust/issues/54010) for the error thrown by `doctest` 90 | /// if no allocator is present (e.g. with just core/alloc). 91 | /// Note that `cfg(doctest)` requires Rust 1.40 ([tracking issue](https://github.com/rust-lang/rust/issues/62210)). 92 | /// As a result of the above, `doctest` is disabled on the CI for Rust versions below `1.40`. 93 | #[cfg(doctest)] 94 | extern crate std; 95 | 96 | /// Use the system allocator when running doc tests. 97 | /// 98 | /// See [rust#54010](https://github.com/rust-lang/rust/issues/54010) for the error thrown by `doctest` 99 | /// if no allocator is present (e.g. with just core/alloc). 100 | /// Note that `cfg(doctest)` requires Rust 1.40 ([tracking issue](https://github.com/rust-lang/rust/issues/62210)). 101 | /// As a result of the above, `doctest` is disabled on the CI for Rust versions below `1.40`. 102 | #[cfg(doctest)] 103 | #[global_allocator] 104 | static A: std::alloc::System = std::alloc::System; 105 | 106 | use core::iter::FusedIterator; 107 | 108 | /// Use a `Vec` to queue iterator elements if the `smallvec` feature is disabled. 109 | #[cfg(not(feature = "smallvec"))] 110 | use alloc::vec::Vec; 111 | 112 | /// Use a SmallVec to queue iterator elements instead of a Vec, if the `smallvec` feature is enabled 113 | /// (default). 114 | #[cfg(feature = "smallvec")] 115 | use smallvec::SmallVec; 116 | 117 | /// Trait which allows you to create the multi-peek iterator. 118 | /// It allows you to peek at any unconsumed element. 119 | /// Elements can be consumed using the [`next`] method defined on any [`Iterator`]. 120 | /// 121 | /// [`next`]: https://doc.rust-lang.org/core/iter/trait.Iterator.html#tymethod.next 122 | /// [`Iterator`]: https://doc.rust-lang.org/core/iter/trait.Iterator.html 123 | pub trait PeekMore: Iterator + Sized { 124 | /// Create a multi-peek iterator where we can peek forward multiple times from an existing iterator. 125 | fn peekmore(self) -> PeekMoreIterator; 126 | } 127 | 128 | impl PeekMore for I { 129 | fn peekmore(self) -> PeekMoreIterator { 130 | PeekMoreIterator { 131 | iterator: self, 132 | 133 | #[cfg(not(feature = "smallvec"))] 134 | queue: Vec::new(), 135 | 136 | #[cfg(feature = "smallvec")] 137 | queue: SmallVec::new(), 138 | 139 | cursor: 0usize, 140 | } 141 | } 142 | } 143 | 144 | /// Default stack size for SmallVec. 145 | /// Admittedly the current size is chosen quite arbitrarily. 146 | #[cfg(feature = "smallvec")] 147 | const DEFAULT_STACK_SIZE: usize = 8; 148 | 149 | /// This iterator makes it possible to peek multiple times without consuming a value. 150 | /// In reality the underlying iterator will be consumed, but the values will be stored in a queue. 151 | /// This queue allows us to peek at unconsumed elements (as far as the multi-peek iterator is concerned). 152 | /// When the iterator [consumes] an element, the element at the front of the queue will be dequeued, 153 | /// and will no longer be peekable. 154 | /// 155 | /// [consumes]: https://doc.rust-lang.org/core/iter/trait.Iterator.html#tymethod.next 156 | #[derive(Clone, Debug)] 157 | pub struct PeekMoreIterator { 158 | /// The underlying iterator. Consumption of this inner iterator does not represent consumption of the 159 | /// `PeekMoreIterator`. 160 | iterator: I, 161 | 162 | /// The queue represents the items of our iterator which have not been consumed, but can be peeked 163 | /// at without consuming them. Once an element has been consumed by the iterator, the element will 164 | /// be dequeued and it will no longer be possible to peek at this element. 165 | #[cfg(not(feature = "smallvec"))] 166 | queue: Vec>, 167 | #[cfg(feature = "smallvec")] 168 | queue: SmallVec<[Option; DEFAULT_STACK_SIZE]>, 169 | 170 | /// The cursor points to the element we are currently peeking at. 171 | /// 172 | /// The cursor will point to the first unconsumed element if the value is `0`, the second if it is 173 | /// `1`, and so forth. Peeking at the 0th cursor element is equivalent to peeking with 174 | /// [`core::iter::Peekable::peek`]. 175 | /// 176 | /// [`core::iter::Peekable::peek`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html#method.peek 177 | cursor: usize, 178 | } 179 | 180 | impl PeekMoreIterator { 181 | /// Get a reference to the element where the cursor currently points to. If no such element exists, 182 | /// return `None` will be returned. 183 | /// 184 | /// If we haven't advanced our cursor, it will point to the same element as `Iterator::next()` would 185 | /// return. 186 | /// Note that the cursor can't point to an element before the first unconsumed element within 187 | /// the iterator. In a sense the cursor moves independently within the iterator. 188 | /// But it can only point to unconsumed elements. 189 | /// 190 | /// The following illustration aims to show how `peek()` behaves. `i` represents the position 191 | /// of the iterator (i.e. the next value that will be returned if `next()` is called) and `j` 192 | /// represents the position of the cursor (i.e. the current element referenced if 193 | /// `peek()` is called). 194 | /// In example code next to the illustrations, the first element `1` is analogous to `A`, 195 | /// `2` to `B`, etc. 196 | /// 197 | /// The example below primarily uses `advance_cursor()` to move the cursor and `peek()` to 198 | /// peek at the element the cursor points to, but many often more convenient methods exist to 199 | /// change the element cursor points at, or to peek at those elements. 200 | /// 201 | /// * Let's start: 202 | /// 203 | /// ```rust 204 | /// use peekmore::PeekMore; 205 | /// 206 | /// // Initialize our iterator. 207 | /// let iterable = [1, 2, 3, 4]; 208 | /// let mut iterator = iterable.iter().peekmore(); 209 | /// ``` 210 | /// 211 | /// ```txt 212 | /// ----- ----- ----- ----- 213 | /// | A | --> | B | --> | C | --> | D | --> None --> None --> ... 214 | /// ----- ----- ----- ----- 215 | /// ^ 216 | /// i, j 217 | /// ``` 218 | /// 219 | /// * Call `peek()`: 220 | /// 221 | /// ```rust 222 | /// # use peekmore::PeekMore; 223 | /// # let iterable = [1, 2, 3, 4]; 224 | /// # let mut iterator = iterable.iter().peekmore(); 225 | /// let j = iterator.peek(); 226 | /// assert_eq!(j, Some(&&1)); 227 | /// ``` 228 | /// 229 | /// ```txt 230 | /// ----- ----- ----- ----- 231 | /// | A | --> | B | --> | C | --> | D | --> None --> None --> ... 232 | /// ----- ----- ----- ----- 233 | /// ^ 234 | /// i, j 235 | /// returns Some(&A) 236 | /// 237 | /// ``` 238 | /// 239 | /// * Call `advance_cursor()` 240 | /// 241 | /// ```rust 242 | /// # use peekmore::PeekMore; 243 | /// # let iterable = [1, 2, 3, 4]; 244 | /// # let mut iterator = iterable.iter().peekmore(); 245 | /// let iter = iterator.advance_cursor(); 246 | /// ``` 247 | /// 248 | /// ```txt 249 | /// ----- ----- ----- ----- 250 | /// | A | --> | B | --> | C | --> | D | --> None --> None --> ... 251 | /// ----- ----- ----- ----- 252 | /// ^ ^ 253 | /// i j 254 | /// ``` 255 | /// 256 | /// * Call `peek()` 257 | /// 258 | /// The reference returned by `peek()` will not change, similar to the behaviour of 259 | /// [`core::iter::Peekable::peek`]. In order to move to the next peekable element, we need to 260 | /// advance the cursor. 261 | /// 262 | /// ```rust 263 | /// # use peekmore::PeekMore; 264 | /// # let iterable = [1, 2, 3, 4]; 265 | /// # let mut iterator = iterable.iter().peekmore(); 266 | /// # let iter = iterator.advance_cursor(); 267 | /// let j = iterator.peek(); 268 | /// assert_eq!(j, Some(&&2)); 269 | /// 270 | /// // Calling `peek()` multiple times doesn't shift the position of the cursor; 271 | /// // a reference to the same element will be returned each call. 272 | /// assert_eq!(iterator.peek(), Some(&&2)); 273 | /// assert_eq!(iterator.peek(), Some(&&2)); 274 | /// ``` 275 | /// 276 | /// ```txt 277 | /// ----- ----- ----- ----- 278 | /// | A | --> | B | --> | C | --> | D | --> None --> None --> ... 279 | /// ----- ----- ----- ----- 280 | /// ^ ^ 281 | /// i j 282 | /// returns Some(&B) 283 | /// ``` 284 | /// 285 | /// 286 | /// * Call `next()` 287 | /// 288 | /// By calling next, the underlying iterator will be advanced andthe element represented by `A` 289 | /// will be consumed. It won't be possible to peek at `A` anymore. 290 | /// 291 | /// ```rust 292 | /// # use peekmore::PeekMore; 293 | /// # let iterable = [1, 2, 3, 4]; 294 | /// # let mut iterator = iterable.iter().peekmore(); 295 | /// # let iter = iterator.advance_cursor(); 296 | /// let i = iterator.next(); 297 | /// assert_eq!(i, Some(&1)); 298 | /// ``` 299 | /// 300 | /// ```txt 301 | /// ----- ----- ----- ----- 302 | /// | A | | B | --> | C | --> | D | --> None --> None --> ... 303 | /// ----- ----- ----- ----- 304 | /// ^ 305 | /// i, j 306 | /// returns Some(A) 307 | /// ``` 308 | /// 309 | /// * Call `next()`. 310 | /// 311 | /// The underlying iterator is advanced again. 312 | /// As a result, the cursor position also shifts to the next iterator position, which happens if 313 | /// the underlying iterator consumed an element where our cursor pointed at (that is if `j < i`). 314 | /// 315 | /// 316 | /// ```rust 317 | /// # use peekmore::PeekMore; 318 | /// # let iterable = [1, 2, 3, 4]; 319 | /// # let mut iterator = iterable.iter().peekmore(); 320 | /// # let iter = iterator.advance_cursor(); 321 | /// # let _ = iterator.next(); 322 | /// // Show that the cursor still points at the second element. 323 | /// let j = iterator.peek(); 324 | /// assert_eq!(j, Some(&&2)); 325 | /// 326 | /// // Consume the second element. 327 | /// let i = iterator.next(); 328 | /// assert_eq!(i, Some(&2)); 329 | /// 330 | /// // Our cursor previously pointed at the element represented by B. Since that element has 331 | /// // been consumed, the cursor shifts to the next unconsumed element: C. 332 | /// let j = iterator.peek(); 333 | /// assert_eq!(j, Some(&&3)); 334 | /// 335 | /// 336 | /// ``` 337 | /// 338 | /// ```txt 339 | /// ----- ----- ----- ----- 340 | /// | A | | B | | C | --> | D | --> None --> None --> ... 341 | /// ----- ----- ----- ----- 342 | /// ^ 343 | /// i, j 344 | /// returns Some(B) 345 | /// ``` 346 | /// 347 | /// * Consume more elements by calling `next()` until we reach `None`: 348 | /// 349 | /// ```rust 350 | /// # use peekmore::PeekMore; 351 | /// # let iterable = [1, 2, 3, 4]; 352 | /// # let mut iterator = iterable.iter().peekmore(); 353 | /// # let iter = iterator.advance_cursor(); 354 | /// # let _ = iterator.next(); 355 | /// # let j = iterator.peek(); 356 | /// # assert_eq!(j, Some(&&2)); 357 | /// # let i = iterator.next(); 358 | /// # assert_eq!(i, Some(&2)); 359 | /// # let j = iterator.peek(); 360 | /// # assert_eq!(j, Some(&&3)); 361 | /// let i = iterator.next(); 362 | /// assert_eq!(i, Some(&3)); 363 | /// 364 | /// let j = iterator.peek(); 365 | /// assert_eq!(j, Some(&&4)); 366 | /// 367 | /// let i = iterator.next(); 368 | /// assert_eq!(i, Some(&4)); 369 | /// 370 | /// let j = iterator.peek(); 371 | /// assert_eq!(j, None); 372 | /// 373 | /// let i = iterator.next(); 374 | /// assert_eq!(i, None); 375 | /// ``` 376 | /// [`core::iter::Peekable::peek`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html#method.peek 377 | #[inline] 378 | pub fn peek(&mut self) -> Option<&I::Item> { 379 | self.fill_queue(self.cursor); 380 | self.queue.get(self.cursor).and_then(|v| v.as_ref()) 381 | } 382 | 383 | /// Peeks at the first unconsumed element, regardless of where the cursor currently is. 384 | #[inline] 385 | pub fn peek_first(&mut self) -> Option<&I::Item> { 386 | self.peek_nth(0) 387 | } 388 | 389 | // Convenient as we don't have to re-assign our mutable borrow on the 'user' side. 390 | /// Advance the cursor to the next element and return a reference to that value. 391 | #[inline] 392 | pub fn peek_next(&mut self) -> Option<&I::Item> { 393 | let this = self.advance_cursor(); 394 | this.peek() 395 | } 396 | 397 | /// Try to peek at a previous element. If no such element exists, an `Err` result containing a 398 | /// [`PeekMoreError::ElementHasBeenConsumed`] will be returned. 399 | /// 400 | /// If a previous element does exist, an option wrapped in an `Ok` result will be returned. 401 | /// 402 | /// [`PeekMoreError::ElementHasBeenConsumed`]: enum.PeekMoreError.html#variant.ElementHasBeenConsumed 403 | #[inline] 404 | pub fn peek_previous(&mut self) -> Result, PeekMoreError> { 405 | if self.cursor >= 1 { 406 | self.move_cursor_back().map(|iter| iter.peek()) 407 | } else { 408 | Err(PeekMoreError::ElementHasBeenConsumed) 409 | } 410 | } 411 | 412 | /// Move the cursor `n` steps forward and peek at the element the cursor then points to. 413 | #[inline] 414 | pub fn peek_forward(&mut self, n: usize) -> Option<&I::Item> { 415 | let this = self.advance_cursor_by(n); 416 | this.peek() 417 | } 418 | 419 | /// Move the cursor `n` steps backward and peek at the element the cursor then points to. 420 | /// 421 | /// If there aren't `n` elements prior to the element the cursor currently points at, a 422 | /// [`PeekMoreError::ElementHasBeenConsumed`] is returned instead. 423 | /// The cursor will then stay at the position it was prior to calling this method. 424 | /// 425 | /// If you want to peek at the first unconsumed element instead of returning with an error, you 426 | /// can use the [`peek_backward_or_first`] method instead. 427 | /// 428 | /// [`PeekMoreError::ElementHasBeenConsumed`]: enum.PeekMoreError.html#variant.ElementHasBeenConsumed 429 | /// [`peek_backward_or_first`]: struct.PeekMoreIterator.html#method.peek_backward_or_first 430 | #[inline] 431 | pub fn peek_backward(&mut self, n: usize) -> Result, PeekMoreError> { 432 | let _ = self.move_cursor_back_by(n)?; 433 | 434 | Ok(self.peek()) 435 | } 436 | 437 | /// Move the cursor `n` steps backward and peek at the element the cursor then points to, or 438 | /// if there aren't `n` elements prior to the element the cursor currently points to, peek at 439 | /// the first unconsumed element instead. 440 | #[inline] 441 | pub fn peek_backward_or_first(&mut self, n: usize) -> Option<&I::Item> { 442 | if self.move_cursor_back_by(n).is_err() { 443 | self.reset_cursor(); 444 | } 445 | 446 | self.peek() 447 | } 448 | 449 | /// Peek at the nth element without moving the cursor. 450 | #[inline] 451 | pub fn peek_nth(&mut self, n: usize) -> Option<&I::Item> { 452 | self.fill_queue(n); 453 | self.queue.get(n).and_then(|v| v.as_ref()) 454 | } 455 | 456 | /// Advance the cursor to the next peekable element. 457 | /// 458 | /// This method does not advance the iterator itself. To advance the iterator, call [`next()`] 459 | /// instead. 460 | /// 461 | /// A mutable reference to the iterator is returned, which allows the operation to be chained. 462 | /// 463 | /// [`next()`]: struct.PeekMoreIterator.html#impl-Iterator 464 | #[inline] 465 | pub fn advance_cursor(&mut self) -> &mut PeekMoreIterator { 466 | self.increment_cursor(); 467 | self 468 | } 469 | 470 | /// Advance the cursor `n` elements forward. 471 | /// 472 | /// This does not advance the iterator itself. To advance the iterator, call [`next()`] instead. 473 | /// 474 | /// [`next()`]: struct.PeekMoreIterator.html#impl-Iterator 475 | #[inline] 476 | pub fn advance_cursor_by(&mut self, n: usize) -> &mut PeekMoreIterator { 477 | self.cursor += n; 478 | self 479 | } 480 | 481 | /// Moves the cursor forward until the predicate is no longer `true`. 482 | /// 483 | /// After this method returns, the cursor points to the first element that fails `predicate`. If no peeked elements 484 | /// pass `predicate` then the cursor will remain unchanged. 485 | /// 486 | /// This does not advance the iterator itself. To advance the iterator, call [`next()`] instead. 487 | /// 488 | /// [`next()`]: struct.PeekMoreIterator.html#impl-Iterator 489 | #[inline] 490 | pub fn advance_cursor_while) -> bool>( 491 | &mut self, 492 | predicate: P, 493 | ) -> &mut PeekMoreIterator { 494 | let view = self.peek(); 495 | 496 | if predicate(view) { 497 | self.increment_cursor(); 498 | self.advance_cursor_while(predicate) 499 | } else { 500 | self 501 | } 502 | } 503 | 504 | /// Move the cursor to the previous peekable element. 505 | /// If such an element doesn't exist, a [`PeekMoreError::ElementHasBeenConsumed`] will be 506 | /// returned. 507 | /// 508 | /// If we can move to a previous element, a mutable reference to the iterator, 509 | /// wrapped in the `Ok` variant of `Result` will be returned. 510 | /// 511 | /// [`PeekMoreError::ElementHasBeenConsumed`]: enum.PeekMoreError.html#variant.ElementHasBeenConsumed 512 | #[inline] 513 | pub fn move_cursor_back(&mut self) -> Result<&mut PeekMoreIterator, PeekMoreError> { 514 | if self.cursor >= 1 { 515 | self.decrement_cursor(); 516 | Ok(self) 517 | } else { 518 | Err(PeekMoreError::ElementHasBeenConsumed) 519 | } 520 | } 521 | 522 | /// Move the cursor `n` elements backward. If there aren't `n` unconsumed elements prior to the 523 | /// cursor, an error will be returned instead. In case of an error, the cursor will stay at the position 524 | /// it pointed at prior to calling this method. 525 | /// 526 | /// If you want to reset the cursor to the first unconsumed element even if there aren't `n` 527 | /// unconsumed elements before the cursor position, the [`move_backward_or_reset`] method can be 528 | /// used. 529 | /// 530 | /// [`move_backward_or_reset`]: struct.PeekMoreIterator.html#method.move_backward_or_reset 531 | #[inline] 532 | pub fn move_cursor_back_by( 533 | &mut self, 534 | n: usize, 535 | ) -> Result<&mut PeekMoreIterator, PeekMoreError> { 536 | if self.cursor < n { 537 | Err(PeekMoreError::ElementHasBeenConsumed) 538 | } else { 539 | self.cursor -= n; 540 | Ok(self) 541 | } 542 | } 543 | 544 | /// Move the cursor `n` elements backward, or reset its position to the first non-consumed element. 545 | /// The latter happens when the cursor position is smaller than the elements it has to move 546 | /// backwards by. 547 | #[inline] 548 | pub fn move_cursor_back_or_reset(&mut self, n: usize) -> &mut PeekMoreIterator { 549 | if self.cursor < n { 550 | self.reset_cursor(); 551 | } else { 552 | self.cursor -= n; 553 | } 554 | 555 | self 556 | } 557 | 558 | /// Move the cursor to the n-th element of the queue. 559 | #[inline] 560 | pub fn move_nth(&mut self, n: usize) -> &mut PeekMoreIterator { 561 | self.cursor = n; 562 | self 563 | } 564 | 565 | /// Deprecated: use [`reset_cursor`] instead. 566 | /// 567 | /// [`reset_cursor`]: struct.PeekMoreIterator.html#method.reset_cursor 568 | #[deprecated] 569 | #[inline] 570 | pub fn reset_view(&mut self) { 571 | self.reset_cursor() 572 | } 573 | 574 | /// Reset the position of the cursor. 575 | /// 576 | /// If [`peek`] is called just after a reset, it will return a reference to the first element. 577 | /// 578 | /// [`peek`]: struct.PeekMoreIterator.html#method.peek 579 | #[inline] 580 | pub fn reset_cursor(&mut self) { 581 | self.cursor = 0; 582 | } 583 | 584 | /// Return the current cursor position. 585 | /// This is intended for use by code that more finely controls where the iterator resets to. 586 | #[inline] 587 | pub fn cursor(&self) -> usize { 588 | self.cursor 589 | } 590 | 591 | /// Fills the queue up to (including) the cursor. 592 | #[inline] 593 | fn fill_queue(&mut self, required_elements: usize) { 594 | let stored_elements = self.queue.len(); 595 | 596 | if stored_elements <= required_elements { 597 | for _ in stored_elements..=required_elements { 598 | self.push_next_to_queue() 599 | } 600 | } 601 | } 602 | 603 | /// Consume the underlying iterator and push an element to the queue. 604 | #[inline] 605 | fn push_next_to_queue(&mut self) { 606 | let item = self.iterator.next(); 607 | self.queue.push(item); 608 | } 609 | 610 | /// Increment the cursor which points to the current peekable item. 611 | /// Note: if the cursor is [core::usize::MAX], it will not increment any further. 612 | /// 613 | /// [core::usize::MAX]: https://doc.rust-lang.org/core/usize/constant.MAX.html 614 | #[inline] 615 | fn increment_cursor(&mut self) { 616 | // do not overflow 617 | self.cursor = self.cursor.saturating_add(1); 618 | } 619 | 620 | /// Decrement the cursor which points to the current peekable item. 621 | /// Note: if the cursor is [core::usize::MIN], it will not decrement any further. 622 | /// 623 | /// [core::usize::MIN]: https://doc.rust-lang.org/core/usize/constant.MIN.html 624 | #[inline] 625 | fn decrement_cursor(&mut self) { 626 | if self.cursor > core::usize::MIN { 627 | self.cursor -= 1; 628 | } 629 | } 630 | 631 | /// Remove all elements from the start of the iterator until reaching the same 632 | /// position as the cursor by calling `Iterator::next()`. 633 | /// 634 | /// After calling this method, `iter.peek() == iter.next().as_ref()`. 635 | /// 636 | ///```rust 637 | /// use peekmore::PeekMore; 638 | /// 639 | /// let iterable = [1, 2, 3, 4]; 640 | /// let mut iter = iterable.iter().peekmore(); 641 | /// 642 | /// iter.advance_cursor_by(2); 643 | /// assert_eq!(iter.peek(), Some(&&3)); 644 | /// assert_eq!(iter.next(), Some(&1)); 645 | /// iter.truncate_iterator_to_cursor(); 646 | /// assert_eq!(iter.peek(), Some(&&3)); 647 | /// assert_eq!(iter.next(), Some(&3)); 648 | ///``` 649 | pub fn truncate_iterator_to_cursor(&mut self) { 650 | if self.cursor < self.queue.len() { 651 | self.queue.drain(0..self.cursor); 652 | } else { 653 | // if the cursor is greater than the queue length, 654 | // we want to remove the overflow from the iterator 655 | for _ in 0..self.cursor.saturating_sub(self.queue.len()) { 656 | let _ = self.iterator.next(); 657 | } 658 | self.queue.clear(); 659 | } 660 | 661 | self.cursor = 0; 662 | } 663 | 664 | /// Returns a view into the next `start` (inclusive) to `end` (exclusive) elements. 665 | /// 666 | /// **Note:** `start` and `end` represent indices and start at `0`. These indices always start 667 | /// at the beginning of the queue (the unconsumed iterator) and don't take the position of the cursor 668 | /// into account. 669 | /// 670 | /// # Panics 671 | /// 672 | /// **Panics** if `start > end`, in which case the range would be negative. 673 | /// 674 | /// ``` 675 | /// use peekmore::PeekMore; 676 | /// 677 | /// let iterable = [1, 2, 3, 4]; 678 | /// let mut iter = iterable.iter().peekmore(); 679 | /// 680 | /// match iter.peek_range(1, 3) { 681 | /// [Some(2), Some(p)] => println!("Yay! we found number {} after number 2", p), 682 | /// _ => println!("Oh noes!"), 683 | /// } 684 | /// ``` 685 | // implementation choice: 686 | // why not `core::ops::RangeBound`? it adds unnecessary complexity since we would need to define what 687 | // unbounded bounds mean (e.g. for end whether it would be the end of the queue or the unconsumed iterator 688 | // elements until None or that it won't be allowed, or some other definition), we would need to map 689 | // the range Inclusive and Exclusive and Unbound-ed elements to usize, and we would need to verify 690 | // that T would be an unsigned integer. Using RangeBound would not be all negative though since we 691 | // could then use the standard Rust range syntax options such as 0..4 or 0..=3, which clearly 692 | // tell a user what kind of bounds are used (inclusive, exclusive, etc.) 693 | // For now however, for the reason of not adding unnecessary complexity, I've decided 694 | // that the simplicity of concrete start and end types is the better choice. 695 | pub fn peek_range(&mut self, start: usize, end: usize) -> &[Option] { 696 | assert!( 697 | start <= end, 698 | "range of the peeked view [start, end] should be positive (i.e. start <= end)" 699 | ); 700 | 701 | // fill the queue if we don't have enough elements 702 | if end > self.queue.len() { 703 | self.fill_queue(end); 704 | } 705 | 706 | // return a view of the selected range 707 | 708 | &self.queue.as_slice()[start..end] 709 | } 710 | 711 | /// Returns a view into the next `n` unconsumed elements of the iterator. 712 | /// 713 | /// Here, `n` represents the amount of elements as counted from the start of the unconsumed iterator. 714 | /// 715 | /// For example, if we created a (peekmore) iterator from the array `[1, 2, 3]` and consume the first 716 | /// element by calling the regular `Iterator::next` method, and then call `peek_amount(3)`, the iterator will 717 | /// return `&[Some(2), Some(3), None]`. Here `Some(2)` and `Some(3)` are queued elements which 718 | /// we can peek at, and are not consumed by the iterator yet. `None` is the last element returned by 719 | /// our view, since our original iterator is sized and doesn't contain more elements. Thus in the absence 720 | /// of additional elements, we return `None`. This method is a variation on [`peek_range`]. 721 | /// You could instead have called `peek_range(0, n)` (note that `peek_range` takes indices as arguments 722 | /// instead of an amount). 723 | /// 724 | /// **Note:** This method does not use or modify the position of the cursor. 725 | /// 726 | /// # Example: 727 | /// 728 | /// ``` 729 | /// use peekmore::PeekMore; 730 | /// 731 | /// let iterable = [1, 2, 3]; 732 | /// let mut iter = iterable.iter().peekmore(); 733 | /// 734 | /// match iter.peek_amount(4) { // -> &[Option(&1), Option(&2), Option(&3), None] 735 | /// [Some(a), Some(b), Some(c), None] => println!("Found a match ({}, {}, {}) ", a, b, c), 736 | /// _ => eprintln!("Expected (just) 3 more values"), 737 | /// } 738 | /// ``` 739 | /// 740 | /// [`peek_range`]: struct.PeekMoreIterator.html#method.peek_range 741 | #[inline] 742 | pub fn peek_amount(&mut self, n: usize) -> &[Option] { 743 | self.peek_range(0, n) 744 | } 745 | 746 | /// Consumes and returns the next item of this iterator if a condition is true. 747 | /// 748 | /// If `func` returns `true` for the next item of this iterator, consume and return it. 749 | /// Otherwise, return `None`. 750 | /// 751 | /// Note: This function always uses the next item of the iterator and it is independent of 752 | /// the cursor location. 753 | /// 754 | /// # Example: 755 | /// Consume items one-by-one. 756 | /// ``` 757 | /// use peekmore::PeekMore; 758 | /// 759 | /// let mut iter = (1..5).peekmore(); 760 | /// 761 | /// assert_eq!(iter.next_if(|&x| x == 1), Some(1)); 762 | /// 763 | /// // next_eq does not care about the cursor position 764 | /// let mut iter = iter.advance_cursor(); 765 | /// assert_eq!(iter.peek(), Some(&3)); 766 | /// assert_eq!(iter.next_if(|&x| x == 2), Some(2)); 767 | /// ``` 768 | /// Consume a range of items. 769 | /// ``` 770 | /// use peekmore::PeekMore; 771 | /// 772 | /// let mut iter = (1..15).peekmore(); 773 | /// 774 | /// while iter.next_if(|&x| x <= 10).is_some() {} 775 | /// assert_eq!(iter.next(), Some(11)); 776 | /// ``` 777 | #[inline] 778 | pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { 779 | match self.peek_first() { 780 | Some(matched) if func(matched) => self.next(), 781 | _ => None, 782 | } 783 | } 784 | 785 | /// Consumes and returns the next item if it is equal to `expected`. 786 | /// 787 | /// Uses [`next_eq`] underneath. 788 | /// 789 | /// [`next_eq`]: struct.PeekMoreIterator.html#method.next_if 790 | #[inline] 791 | pub fn next_if_eq(&mut self, expected: &T) -> Option 792 | where 793 | T: ?Sized, 794 | I::Item: PartialEq, 795 | { 796 | self.next_if(|next| next == expected) 797 | } 798 | } 799 | 800 | impl Iterator for PeekMoreIterator { 801 | type Item = I::Item; 802 | 803 | fn next(&mut self) -> Option { 804 | let res = if self.queue.is_empty() { 805 | self.iterator.next() 806 | } else { 807 | self.queue.remove(0) 808 | }; 809 | 810 | self.decrement_cursor(); 811 | 812 | res 813 | } 814 | } 815 | 816 | /// Uses [`ExactSizeIterator`] default implementation. 817 | /// 818 | /// [`ExactSizeIterator`]: https://doc.rust-lang.org/core/iter/trait.ExactSizeIterator.html 819 | impl ExactSizeIterator for PeekMoreIterator {} 820 | 821 | /// Uses [`FusedIterator`] default implementation. 822 | /// 823 | /// [`FusedIterator`]: https://doc.rust-lang.org/core/iter/trait.FusedIterator.html 824 | impl FusedIterator for PeekMoreIterator {} 825 | 826 | /// This enumeration provides errors which represent lack of success of the [`PeekMoreIterator`]. 827 | /// 828 | /// [`PeekMoreIterator`]: struct.PeekMoreIterator.html 829 | #[derive(Debug, Eq, PartialEq)] 830 | pub enum PeekMoreError { 831 | /// This error case will be returned if we try to move to an element, but it has already been 832 | /// consumed by the iterator. 833 | /// We can only peek at elements which haven't been consumed. 834 | ElementHasBeenConsumed, 835 | } 836 | 837 | #[cfg(test)] 838 | mod tests { 839 | use super::*; 840 | 841 | #[test] 842 | fn readme_example() { 843 | let range10 = 0..11; 844 | let mut peekable = range10.peekmore(); 845 | 846 | // Peek at the first element 847 | let peek_first = peekable.peek(); 848 | assert_eq!(*peek_first.unwrap(), 0); 849 | 850 | let peek_first_redux = peekable.peek_nth(0); 851 | assert_eq!(*peek_first_redux.unwrap(), 0); 852 | 853 | // Peek at the 10th (index) element 854 | let peek_tenth = peekable.peek_nth(10); 855 | assert_eq!(*peek_tenth.unwrap(), 10); 856 | 857 | // Consume the 10th element 858 | let tenth = peekable.nth(10); 859 | assert_eq!(tenth.unwrap(), 10); 860 | 861 | // Show that there are no more elements 862 | assert_eq!(peekable.peek(), None); 863 | assert_eq!(peekable.next(), None); 864 | } 865 | 866 | #[test] 867 | fn peek_forward_with_reassignment() { 868 | let iterable = [1, 2, 3, 4]; 869 | 870 | let mut peek = iterable.iter().peekmore(); 871 | 872 | assert_eq!(peek.peek(), Some(&&1)); 873 | 874 | let peek = peek.advance_cursor(); 875 | assert_eq!(peek.peek(), Some(&&2)); 876 | 877 | let peek = peek.advance_cursor(); 878 | assert_eq!(peek.peek(), Some(&&3)); 879 | 880 | let peek = peek.advance_cursor(); 881 | assert_eq!(peek.peek(), Some(&&4)); 882 | 883 | let peek = peek.advance_cursor(); 884 | assert_eq!(peek.peek(), None); 885 | } 886 | 887 | #[test] 888 | fn peek_forward_without_reassignment_separately_advance_and_peek() { 889 | let iterable = [1, 2, 3, 4]; 890 | 891 | let mut iter = iterable.iter().peekmore(); 892 | 893 | assert_eq!(iter.peek(), Some(&&1)); 894 | 895 | let v2 = iter.advance_cursor().peek(); 896 | assert_eq!(v2, Some(&&2)); 897 | 898 | let v3 = iter.advance_cursor().peek(); 899 | assert_eq!(v3, Some(&&3)); 900 | 901 | let v4 = iter.advance_cursor().peek(); 902 | assert_eq!(v4, Some(&&4)); 903 | 904 | let v5 = iter.advance_cursor().peek(); 905 | assert_eq!(v5, None); 906 | } 907 | 908 | #[test] 909 | fn peek_forward_without_reassignment_advance_and_peek_combined() { 910 | let iterable = [1, 2, 3, 4]; 911 | 912 | let mut iter = iterable.iter().peekmore(); 913 | 914 | let v1 = iter.peek(); 915 | assert_eq!(v1, Some(&&1)); 916 | 917 | let v2 = iter.peek_next(); 918 | assert_eq!(v2, Some(&&2)); 919 | 920 | let v3 = iter.peek_next(); 921 | assert_eq!(v3, Some(&&3)); 922 | 923 | let v4 = iter.peek_next(); 924 | assert_eq!(v4, Some(&&4)); 925 | 926 | let v5 = iter.peek_next(); 927 | assert_eq!(v5, None); 928 | } 929 | 930 | #[test] 931 | fn peek_forward_without_reassignment_advance_and_peek_combined_and_reset_view() { 932 | let iterable = [1, 2, 3, 4]; 933 | 934 | let mut iter = iterable.iter().peekmore(); 935 | 936 | let v1 = iter.peek(); 937 | assert_eq!(v1, Some(&&1)); 938 | 939 | let v2 = iter.peek_next(); 940 | assert_eq!(v2, Some(&&2)); 941 | 942 | iter.reset_cursor(); 943 | let v1again = iter.peek(); 944 | assert_eq!(v1again, Some(&&1)); 945 | 946 | let v2again = iter.peek_next(); 947 | assert_eq!(v2again, Some(&&2)); 948 | 949 | let v3 = iter.peek_next(); 950 | assert_eq!(v3, Some(&&3)); 951 | 952 | let v4 = iter.peek_next(); 953 | assert_eq!(v4, Some(&&4)); 954 | 955 | let v5 = iter.peek_next(); 956 | assert_eq!(v5, None); 957 | } 958 | 959 | #[test] 960 | fn empty() { 961 | let iterable: [i32; 0] = []; 962 | 963 | let mut iter = iterable.iter().peekmore(); 964 | 965 | assert_eq!(iter.peek(), None); 966 | 967 | let none = iter.peek_next(); 968 | assert_eq!(none, None); 969 | 970 | let iter = iter.advance_cursor(); 971 | assert_eq!(iter.peek(), None); 972 | assert_eq!(iter.peek_next(), None); 973 | } 974 | 975 | #[test] 976 | fn test_with_consume() { 977 | let iterable = "123".chars(); 978 | 979 | let mut iter = iterable.peekmore(); 980 | assert_eq!(iter.peek(), Some(&core::char::from_digit(1, 10).unwrap())); 981 | assert_eq!( 982 | iter.peek_next(), 983 | Some(&core::char::from_digit(2, 10).unwrap()) 984 | ); 985 | assert_eq!( 986 | iter.peek_next(), 987 | Some(&core::char::from_digit(3, 10).unwrap()) 988 | ); 989 | assert_eq!(iter.peek_next(), None); 990 | assert_eq!(iter.next(), Some(core::char::from_digit(1, 10).unwrap())); 991 | assert_eq!(iter.peek(), None); 992 | assert_eq!(iter.peek_next(), None); 993 | assert_eq!(iter.next(), Some(core::char::from_digit(2, 10).unwrap())); 994 | assert_eq!(iter.peek(), None); 995 | assert_eq!(iter.peek_next(), None); 996 | assert_eq!(iter.next(), Some(core::char::from_digit(3, 10).unwrap())); 997 | assert_eq!(iter.next(), None); 998 | assert_eq!(iter.peek_next(), None); 999 | } 1000 | 1001 | #[test] 1002 | fn test_with_consume_and_reset() { 1003 | let iterable = "456".chars(); 1004 | 1005 | let mut iter = iterable.peekmore(); 1006 | assert_eq!(iter.peek(), Some(&core::char::from_digit(4, 10).unwrap())); 1007 | assert_eq!( 1008 | iter.peek_next(), 1009 | Some(&core::char::from_digit(5, 10).unwrap()) 1010 | ); 1011 | assert_eq!( 1012 | iter.peek_next(), 1013 | Some(&core::char::from_digit(6, 10).unwrap()) 1014 | ); 1015 | assert_eq!(iter.peek_next(), None); 1016 | assert_eq!(iter.next(), Some(core::char::from_digit(4, 10).unwrap())); 1017 | iter.reset_cursor(); 1018 | 1019 | assert_eq!(iter.peek(), Some(&core::char::from_digit(5, 10).unwrap())); 1020 | assert_eq!( 1021 | iter.peek_next(), 1022 | Some(&core::char::from_digit(6, 10).unwrap()) 1023 | ); 1024 | 1025 | assert_eq!(iter.next(), Some(core::char::from_digit(5, 10).unwrap())); 1026 | assert_eq!(iter.next(), Some(core::char::from_digit(6, 10).unwrap())); 1027 | assert_eq!(iter.next(), None); 1028 | assert_eq!(iter.peek_next(), None); 1029 | } 1030 | 1031 | #[test] 1032 | fn check_peek_window_moves_with_consume() { 1033 | let iterable = [1, 2, 3, 4]; 1034 | 1035 | let mut iter = iterable.iter().peekmore(); 1036 | 1037 | let v1 = iter.peek(); 1038 | assert_eq!(v1, Some(&&1)); 1039 | 1040 | let v1c = iter.next(); 1041 | assert_eq!(v1c, Some(&1)); 1042 | 1043 | let v2 = iter.peek(); 1044 | assert_eq!(v2, Some(&&2)); 1045 | 1046 | let v2c = iter.next(); 1047 | assert_eq!(v2c, Some(&2)); 1048 | 1049 | let v3 = iter.peek(); 1050 | assert_eq!(v3, Some(&&3)); 1051 | 1052 | iter.reset_cursor(); 1053 | 1054 | let v3 = iter.peek(); 1055 | assert_eq!(v3, Some(&&3)); 1056 | 1057 | let v3c = iter.next(); 1058 | assert_eq!(v3c, Some(&3)); 1059 | 1060 | let v4c = iter.next(); 1061 | assert_eq!(v4c, Some(&4)); 1062 | 1063 | let v5 = iter.peek(); 1064 | assert_eq!(v5, None); 1065 | 1066 | let v5c = iter.next(); 1067 | assert_eq!(v5c, None); 1068 | } 1069 | 1070 | #[test] 1071 | fn check_advance_separately() { 1072 | let iterable = [1, 2, 3, 4]; 1073 | 1074 | let mut iter = iterable.iter().peekmore(); // j -> 1 1075 | 1076 | assert_eq!(iter.cursor(), 0); 1077 | assert_eq!(iter.peek(), Some(&&1)); 1078 | 1079 | iter.advance_cursor(); // j -> 2 1080 | assert_eq!(iter.cursor(), 1); 1081 | 1082 | iter.advance_cursor(); // j -> 3 1083 | assert_eq!(iter.cursor(), 2); 1084 | 1085 | iter.advance_cursor(); // j -> 4 1086 | assert_eq!(iter.cursor(), 3); 1087 | 1088 | let v4 = iter.peek(); 1089 | assert_eq!(v4, Some(&&4)); 1090 | } 1091 | 1092 | #[test] 1093 | fn check_advance_chain() { 1094 | let iterable = [1, 2, 3, 4]; 1095 | 1096 | let mut iter = iterable.iter().peekmore(); // j -> 1 1097 | 1098 | assert_eq!(iter.cursor(), 0); 1099 | 1100 | iter.advance_cursor() // j -> 2 1101 | .advance_cursor() // j -> 3 1102 | .advance_cursor(); // j -> 4 1103 | 1104 | let v4 = iter.peek(); 1105 | assert_eq!(v4, Some(&&4)); 1106 | } 1107 | 1108 | #[test] 1109 | fn check_move_previous() { 1110 | let iterable = [1, 2, 3, 4]; 1111 | 1112 | let mut iter = iterable.iter().peekmore(); // j -> 1 1113 | 1114 | assert_eq!(iter.cursor(), 0); 1115 | assert_eq!(iter.peek(), Some(&&1)); 1116 | 1117 | iter.advance_cursor(); // j -> 2 1118 | assert_eq!(iter.cursor(), 1); 1119 | 1120 | let _ = iter.move_cursor_back(); // j -> 1 1121 | assert_eq!(iter.cursor(), 0); 1122 | 1123 | iter.advance_cursor(); // j -> 2 1124 | assert_eq!(iter.cursor(), 1); 1125 | 1126 | let _ = iter.move_cursor_back(); // j -> 1 1127 | assert_eq!(iter.cursor(), 0); 1128 | 1129 | iter.advance_cursor(); // j -> 2 1130 | assert_eq!(iter.cursor(), 1); 1131 | 1132 | iter.advance_cursor() // j -> 3 1133 | .advance_cursor(); // j -> 4 1134 | 1135 | assert_eq!(iter.cursor(), 3); 1136 | 1137 | let v4 = iter.peek(); 1138 | assert_eq!(v4, Some(&&4)); 1139 | 1140 | let _ = iter.move_cursor_back().and_then(|it| { 1141 | it.move_cursor_back() // j -> 3 1142 | .and_then(|it| { 1143 | it.move_cursor_back() // j -> 2 1144 | .and_then(|it| it.move_cursor_back()) 1145 | }) 1146 | }); // j -> 1 1147 | 1148 | let v1 = iter.peek(); 1149 | assert_eq!(v1, Some(&&1)); 1150 | 1151 | let prev = iter.move_cursor_back(); 1152 | assert!(prev.is_err()); 1153 | 1154 | let v1 = iter.peek(); 1155 | assert_eq!(v1, Some(&&1)); 1156 | } 1157 | 1158 | #[test] 1159 | fn test_with_inherited_feature_count() { 1160 | let iterable = [1, 2, 3]; 1161 | let mut iter = iterable.iter().peekmore(); 1162 | 1163 | iter.advance_cursor(); 1164 | let second = iter.peek().unwrap(); 1165 | assert_eq!(second, &&2); 1166 | 1167 | let consume_first = iter.next().unwrap(); 1168 | assert_eq!(consume_first, &1); 1169 | 1170 | let count = iter.count(); 1171 | assert_eq!(count, 2); 1172 | } 1173 | 1174 | #[test] 1175 | fn peek_previous() { 1176 | let iterable = [1, 2, 3]; 1177 | let mut iter = iterable.iter().peekmore(); // j = 1 1178 | 1179 | iter.advance_cursor(); // j = 2 1180 | iter.advance_cursor(); // j = 3 1181 | let value = iter.peek().unwrap(); // 3 1182 | assert_eq!(value, &&3); 1183 | 1184 | let peek = iter.peek_previous(); // 2 1185 | assert_eq!(peek.unwrap(), Some(&&2)); 1186 | assert_eq!(iter.cursor(), 1); 1187 | 1188 | let peek = iter.peek_previous(); // 1 1189 | assert_eq!(peek.unwrap(), Some(&&1)); 1190 | assert_eq!(iter.cursor(), 0); 1191 | 1192 | let peek = iter.peek_previous(); 1193 | assert_eq!(peek, Err(PeekMoreError::ElementHasBeenConsumed)); 1194 | assert_eq!(iter.cursor(), 0); 1195 | } 1196 | 1197 | #[test] 1198 | fn peek_previous_beyond_none() { 1199 | let iterable = [1]; 1200 | let mut iter = iterable.iter().peekmore(); // j = 1 1201 | assert_eq!(iter.cursor(), 0); 1202 | 1203 | iter.advance_cursor(); // j = None (1) 1204 | let peek = iter.peek(); 1205 | assert_eq!(peek, None); 1206 | assert_eq!(iter.cursor(), 1); 1207 | 1208 | iter.advance_cursor(); // j = None (2) 1209 | let peek = iter.peek(); 1210 | assert_eq!(peek, None); 1211 | assert_eq!(iter.cursor(), 2); 1212 | 1213 | iter.advance_cursor(); // j = None (3) 1214 | let peek = iter.peek(); // current 1215 | assert_eq!(peek, None); 1216 | assert_eq!(iter.cursor(), 3); 1217 | 1218 | let peek = iter.peek_previous(); // None (2) 1219 | assert_eq!(peek.unwrap(), None); 1220 | assert_eq!(iter.cursor(), 2); 1221 | 1222 | let peek = iter.peek_previous(); // None (1) 1223 | assert_eq!(peek.unwrap(), None); 1224 | assert_eq!(iter.cursor(), 1); 1225 | 1226 | let peek = iter.peek_previous(); // 1 1227 | assert_eq!(peek.unwrap(), Some(&&1)); 1228 | assert_eq!(iter.cursor(), 0); 1229 | 1230 | let peek = iter.peek_previous(); 1231 | assert_eq!(peek, Err(PeekMoreError::ElementHasBeenConsumed)); 1232 | assert_eq!(iter.cursor(), 0); 1233 | 1234 | let peek = iter.peek_previous(); 1235 | assert_eq!(peek, Err(PeekMoreError::ElementHasBeenConsumed)); 1236 | assert_eq!(iter.cursor(), 0); 1237 | } 1238 | 1239 | #[test] 1240 | fn check_move_forward() { 1241 | let iterable = [1, 2, 3, 4]; 1242 | let mut iter = iterable.iter().peekmore(); 1243 | 1244 | let _ = iter.advance_cursor_by(3); 1245 | 1246 | let peek = iter.peek(); 1247 | assert_eq!(peek, Some(&&4)); 1248 | assert_eq!(iter.cursor(), 3); 1249 | 1250 | let _ = iter.advance_cursor_by(3); 1251 | let peek = iter.peek(); 1252 | assert_eq!(peek, None); 1253 | assert_eq!(iter.cursor(), 6); 1254 | } 1255 | 1256 | #[test] 1257 | fn check_move_backward() { 1258 | let iterable = [1, 2, 3, 4]; 1259 | let mut iter = iterable.iter().peekmore(); 1260 | 1261 | let _ = iter.advance_cursor_by(3); 1262 | 1263 | let peek = iter.peek(); 1264 | assert_eq!(peek, Some(&&4)); 1265 | assert_eq!(iter.cursor(), 3); 1266 | 1267 | let result = iter.move_cursor_back_by(2); 1268 | assert!(result.is_ok()); 1269 | let peek = iter.peek(); 1270 | assert_eq!(peek, Some(&&2)); 1271 | assert_eq!(iter.cursor(), 1); 1272 | 1273 | let result = iter.move_cursor_back_by(1); 1274 | assert!(result.is_ok()); 1275 | let peek = iter.peek(); 1276 | assert_eq!(peek, Some(&&1)); 1277 | assert_eq!(iter.cursor(), 0); 1278 | 1279 | let result = iter.move_cursor_back_by(1); 1280 | assert!(result.is_err()); 1281 | let peek = iter.peek(); 1282 | assert_eq!(peek, Some(&&1)); 1283 | assert_eq!(iter.cursor(), 0); 1284 | } 1285 | 1286 | #[test] 1287 | fn check_move_backward_beyond_consumed_verify_cursor_position() { 1288 | let iterable = [1, 2, 3, 4]; 1289 | let mut iter = iterable.iter().peekmore(); 1290 | 1291 | let _ = iter.advance_cursor_by(3); 1292 | 1293 | let peek = iter.peek(); 1294 | assert_eq!(peek, Some(&&4)); 1295 | assert_eq!(iter.cursor(), 3); 1296 | 1297 | let result = iter.move_cursor_back_by(5); 1298 | assert!(result.is_err()); 1299 | let peek = iter.peek(); 1300 | assert_eq!(peek, Some(&&4)); 1301 | assert_eq!(iter.cursor(), 3); 1302 | } 1303 | 1304 | #[test] 1305 | fn check_move_backward_or_reset() { 1306 | let iterable = [1, 2, 3, 4]; 1307 | let mut iter = iterable.iter().peekmore(); 1308 | 1309 | let _ = iter.advance_cursor_by(3); 1310 | 1311 | let peek = iter.peek(); 1312 | assert_eq!(peek, Some(&&4)); 1313 | assert_eq!(iter.cursor(), 3); 1314 | 1315 | let _ = iter.move_cursor_back_or_reset(2); 1316 | let peek = iter.peek(); 1317 | assert_eq!(peek, Some(&&2)); 1318 | assert_eq!(iter.cursor(), 1); 1319 | 1320 | let _ = iter.move_cursor_back_or_reset(1); 1321 | let peek = iter.peek(); 1322 | assert_eq!(peek, Some(&&1)); 1323 | assert_eq!(iter.cursor(), 0); 1324 | 1325 | let _ = iter.move_cursor_back_or_reset(1); 1326 | let peek = iter.peek(); 1327 | assert_eq!(peek, Some(&&1)); 1328 | assert_eq!(iter.cursor(), 0); 1329 | } 1330 | 1331 | #[test] 1332 | fn check_move_backward_or_reset_beyond_consumed_verify_cursor_position() { 1333 | let iterable = [1, 2, 3, 4]; 1334 | let mut iter = iterable.iter().peekmore(); 1335 | 1336 | let _ = iter.advance_cursor_by(3); 1337 | 1338 | let peek = iter.peek(); 1339 | assert_eq!(peek, Some(&&4)); 1340 | assert_eq!(iter.cursor(), 3); 1341 | 1342 | let _ = iter.move_cursor_back_or_reset(5); 1343 | let peek = iter.peek(); 1344 | assert_eq!(peek, Some(&&1)); 1345 | assert_eq!(iter.cursor(), 0); 1346 | } 1347 | 1348 | #[test] 1349 | fn check_move_backward_or_reset_empty() { 1350 | let iterable = "".chars(); 1351 | 1352 | let mut iter = iterable.peekmore(); 1353 | 1354 | assert_eq!(iter.peek(), None); 1355 | assert_eq!(iter.cursor(), 0); 1356 | 1357 | let _ = iter.move_cursor_back_or_reset(5); 1358 | 1359 | assert_eq!(iter.peek(), None); 1360 | assert_eq!(iter.cursor(), 0); 1361 | } 1362 | 1363 | #[test] 1364 | fn check_peek_forward() { 1365 | let iterable = [1, 2, 3, 4]; 1366 | let mut iter = iterable.iter().peekmore(); 1367 | 1368 | let peek = iter.peek_forward(3); 1369 | 1370 | assert_eq!(peek, Some(&&4)); 1371 | assert_eq!(iter.cursor(), 3); 1372 | 1373 | let peek = iter.peek_forward(3); 1374 | assert_eq!(peek, None); 1375 | assert_eq!(iter.cursor(), 6); 1376 | } 1377 | 1378 | #[test] 1379 | fn check_peek_backward() { 1380 | let iterable = [1, 2, 3, 4]; 1381 | let mut iter = iterable.iter().peekmore(); 1382 | 1383 | let _ = iter.advance_cursor_by(3); 1384 | 1385 | let peek = iter.peek(); 1386 | assert_eq!(peek, Some(&&4)); 1387 | assert_eq!(iter.cursor(), 3); 1388 | 1389 | let result = iter.peek_backward(2); 1390 | assert!(result.is_ok()); 1391 | assert_eq!(result.unwrap(), Some(&&2)); 1392 | assert_eq!(iter.cursor(), 1); 1393 | 1394 | let result = iter.peek_backward(1); 1395 | assert!(result.is_ok()); 1396 | assert_eq!(result.unwrap(), Some(&&1)); 1397 | assert_eq!(iter.cursor(), 0); 1398 | 1399 | let result = iter.peek_backward(1); 1400 | assert!(result.is_err()); 1401 | let peek = iter.peek(); 1402 | assert_eq!(peek, Some(&&1)); 1403 | assert_eq!(iter.cursor(), 0); 1404 | } 1405 | 1406 | #[test] 1407 | fn check_peek_backward_beyond_consumed_verify_cursor_position() { 1408 | let iterable = [1, 2, 3, 4]; 1409 | let mut iter = iterable.iter().peekmore(); 1410 | 1411 | let _ = iter.advance_cursor_by(3); 1412 | 1413 | let peek = iter.peek(); 1414 | assert_eq!(peek, Some(&&4)); 1415 | assert_eq!(iter.cursor(), 3); 1416 | 1417 | let result = iter.peek_backward(5); 1418 | assert!(result.is_err()); 1419 | let peek = iter.peek(); 1420 | assert_eq!(peek, Some(&&4)); 1421 | assert_eq!(iter.cursor(), 3); 1422 | } 1423 | 1424 | #[test] 1425 | fn check_peek_backward_or_first_beyond_consumed_verify_cursor_position() { 1426 | let iterable = [1, 2, 3, 4]; 1427 | let mut iter = iterable.iter().peekmore(); 1428 | 1429 | let _ = iter.advance_cursor_by(3); 1430 | 1431 | let peek = iter.peek(); 1432 | assert_eq!(peek, Some(&&4)); 1433 | assert_eq!(iter.cursor(), 3); 1434 | 1435 | let peek = iter.peek_backward_or_first(5); 1436 | assert_eq!(peek, Some(&&1)); 1437 | assert_eq!(iter.cursor(), 0); 1438 | } 1439 | 1440 | #[test] 1441 | fn check_peek_backward_or_first_empty() { 1442 | let iterable = "".chars(); 1443 | 1444 | let mut iter = iterable.peekmore(); 1445 | 1446 | assert_eq!(iter.peek(), None); 1447 | assert_eq!(iter.cursor(), 0); 1448 | 1449 | let peek = iter.peek_backward_or_first(5); 1450 | 1451 | assert_eq!(peek, None); 1452 | assert_eq!(iter.cursor(), 0); 1453 | } 1454 | 1455 | #[test] 1456 | fn check_move_forward_while() { 1457 | let iterable = [1, 2, 3, 4]; 1458 | let mut iter = iterable.iter().peekmore(); 1459 | 1460 | let _ = iter.advance_cursor_while(|i| **i.unwrap() != 3); 1461 | 1462 | let peek = iter.peek(); 1463 | assert_eq!(peek, Some(&&3)); 1464 | assert_eq!(iter.cursor(), 2); 1465 | } 1466 | 1467 | #[test] 1468 | fn check_move_forward_while_empty() { 1469 | let iterable: [i32; 0] = []; 1470 | let mut iter = iterable.iter().peekmore(); 1471 | 1472 | let _ = iter.advance_cursor_while(|i| if let Some(i) = i { **i != 3 } else { false }); 1473 | 1474 | let peek = iter.peek(); 1475 | assert_eq!(peek, None); 1476 | assert_eq!(iter.cursor(), 0); 1477 | } 1478 | 1479 | #[test] 1480 | fn check_move_forward_while_some() { 1481 | let iterable = [1, 2, 3, 4]; 1482 | let mut iter = iterable.iter().peekmore(); 1483 | 1484 | let _ = iter.advance_cursor_while(|i| i.is_some()); 1485 | 1486 | let peek = iter.peek(); 1487 | assert_eq!(peek, None); 1488 | assert_eq!(iter.cursor(), 4); 1489 | } 1490 | 1491 | #[test] 1492 | fn check_move_forward_while_fast_fail() { 1493 | let iterable = [1, 2, 3, 4]; 1494 | let mut iter = iterable.iter().peekmore(); 1495 | 1496 | iter.advance_cursor_by(2); 1497 | 1498 | let _ = iter.advance_cursor_while(|i| **i.unwrap() > 3); 1499 | 1500 | let peek = iter.peek(); 1501 | assert_eq!(peek, Some(&&3)); 1502 | assert_eq!(iter.cursor(), 2); 1503 | } 1504 | 1505 | #[test] 1506 | fn check_peek_nth() { 1507 | let iterable = [1, 2, 3, 4]; 1508 | 1509 | let mut iter = iterable.iter().peekmore(); 1510 | 1511 | assert_eq!(iter.peek_nth(0), Some(&&1)); 1512 | assert_eq!(iter.cursor(), 0); 1513 | assert_eq!(iter.peek_nth(1), Some(&&2)); 1514 | assert_eq!(iter.cursor(), 0); 1515 | assert_eq!(iter.peek_nth(2), Some(&&3)); 1516 | assert_eq!(iter.cursor(), 0); 1517 | assert_eq!(iter.peek_nth(3), Some(&&4)); 1518 | assert_eq!(iter.cursor(), 0); 1519 | assert_eq!(iter.peek_nth(4), None); 1520 | assert_eq!(iter.cursor(), 0); 1521 | } 1522 | 1523 | #[test] 1524 | fn check_peek_first() { 1525 | let iterable = [1, 2, 3, 4]; 1526 | let mut iter = iterable.iter().peekmore(); 1527 | 1528 | // testing to make sure no matter where the cursor is, we always point 1529 | // to the initial first element. 1530 | assert_eq!(iter.peek_first(), Some(&&1)); 1531 | assert_eq!(iter.cursor(), 0); 1532 | iter.increment_cursor(); 1533 | assert_eq!(iter.peek_first(), Some(&&1)); 1534 | assert_eq!(iter.cursor(), 1); 1535 | iter.increment_cursor(); 1536 | assert_eq!(iter.peek_first(), Some(&&1)); 1537 | assert_eq!(iter.cursor(), 2); 1538 | iter.increment_cursor(); 1539 | assert_eq!(iter.peek_first(), Some(&&1)); 1540 | assert_eq!(iter.cursor(), 3); 1541 | iter.increment_cursor(); // try moving past the end too 1542 | assert_eq!(iter.peek_first(), Some(&&1)); 1543 | 1544 | // testing to ensure that it's the first *unconsumed* element of the iterator 1545 | // and not the first of the iterable. 1546 | iter.next(); 1547 | assert_eq!(iter.peek_first(), Some(&&2)); 1548 | iter.increment_cursor(); 1549 | assert_eq!(iter.peek_first(), Some(&&2)); 1550 | 1551 | // testing at the end boundary of the iterable. 1552 | iter.next(); // consume 2 1553 | iter.next(); // consume 3 1554 | assert_eq!(iter.peek_first(), Some(&&4)); 1555 | 1556 | // test that if there's no unconsumed elements, it reports None. 1557 | iter.next(); 1558 | assert_eq!(iter.peek_first(), None); 1559 | } 1560 | 1561 | #[test] 1562 | fn check_peek_nth_empty() { 1563 | let iterable: [i32; 0] = []; 1564 | 1565 | let mut iter = iterable.iter().peekmore(); 1566 | 1567 | assert_eq!(iter.peek_nth(0), None); 1568 | assert_eq!(iter.cursor(), 0); 1569 | assert_eq!(iter.peek_nth(1), None); 1570 | assert_eq!(iter.cursor(), 0); 1571 | } 1572 | 1573 | #[test] 1574 | fn check_move_nth() { 1575 | let iterable = [1, 2, 3, 4]; 1576 | 1577 | let mut iter = iterable.iter().peekmore(); 1578 | 1579 | iter.move_nth(20); 1580 | assert_eq!(iter.peek_nth(0), Some(&&1)); 1581 | assert_eq!(iter.cursor(), 20); 1582 | assert_eq!(iter.peek(), None); 1583 | 1584 | iter.move_nth(0); 1585 | assert_eq!(iter.peek(), Some(&&1)); 1586 | 1587 | iter.move_nth(3); 1588 | assert_eq!(iter.peek(), Some(&&4)); 1589 | } 1590 | 1591 | #[test] 1592 | fn check_move_nth_empty() { 1593 | let iterable: [i32; 0] = []; 1594 | 1595 | let mut iter = iterable.iter().peekmore(); 1596 | 1597 | iter.move_nth(0); 1598 | assert_eq!(iter.cursor(), 0); 1599 | 1600 | iter.move_nth(10); 1601 | assert_eq!(iter.cursor(), 10); 1602 | } 1603 | 1604 | #[test] 1605 | fn truncate_iterator_to_cursor_is_noop_when_queue_is_empty_from_no_peeking() { 1606 | let iterable = [1, 2, 3, 4]; 1607 | 1608 | let mut iter = iterable.iter().peekmore(); 1609 | 1610 | assert!(iter.queue.is_empty()); 1611 | 1612 | iter.truncate_iterator_to_cursor(); 1613 | 1614 | assert!(iter.queue.is_empty()); 1615 | assert_eq!(iter.peek(), Some(&&1)); 1616 | assert!(!iter.queue.is_empty()); 1617 | } 1618 | 1619 | #[test] 1620 | fn truncate_iterator_to_cursor_is_noop_when_queue_is_empty_from_iteration() { 1621 | let iterable = [1, 2, 3, 4]; 1622 | 1623 | let mut iter = iterable.iter().peekmore(); 1624 | 1625 | assert!(iter.queue.is_empty()); 1626 | 1627 | iter.peek_forward(2); 1628 | iter.next(); 1629 | iter.next(); 1630 | iter.next(); 1631 | 1632 | assert!(iter.queue.is_empty()); 1633 | 1634 | iter.truncate_iterator_to_cursor(); 1635 | 1636 | assert!(iter.queue.is_empty()); 1637 | assert_eq!(iter.peek(), Some(&&4)); 1638 | assert!(!iter.queue.is_empty()); 1639 | } 1640 | 1641 | #[test] 1642 | fn truncate_to_iterator_fill_queue() { 1643 | let mut iter = [0, 1, 2, 3].iter().peekmore(); 1644 | iter.advance_cursor(); 1645 | iter.truncate_iterator_to_cursor(); 1646 | 1647 | let value = **iter.peek().unwrap(); 1648 | 1649 | assert_eq!(value, 1); 1650 | } 1651 | 1652 | #[test] 1653 | fn truncate_to_iterator_on_empty_collection() { 1654 | let mut iter = core::iter::empty::().peekmore(); 1655 | iter.advance_cursor(); 1656 | assert_eq!(iter.cursor, 1); 1657 | 1658 | iter.truncate_iterator_to_cursor(); 1659 | assert_eq!(iter.cursor, 0); 1660 | 1661 | assert!(iter.peek().is_none()); 1662 | } 1663 | 1664 | #[test] 1665 | fn truncate_to_iterator_on_single_element_collection() { 1666 | let mut iter = core::iter::once(0).peekmore(); 1667 | assert_eq!(*iter.peek().unwrap(), 0); 1668 | assert_eq!(iter.cursor, 0); 1669 | 1670 | iter.advance_cursor(); // starts at 0, so now is 1 (i.e. second element so None) 1671 | assert_eq!(iter.cursor, 1); 1672 | assert!(iter.peek().is_none()); 1673 | 1674 | iter.truncate_iterator_to_cursor(); 1675 | assert_eq!(iter.cursor, 0); 1676 | 1677 | assert!(iter.peek().is_none()); 1678 | } 1679 | 1680 | #[test] 1681 | fn truncate_to_iterator_cursor_and_queue_equal_length() { 1682 | let mut iter = [0, 1, 2, 3].iter().peekmore(); 1683 | iter.peek(); 1684 | iter.advance_cursor(); 1685 | iter.truncate_iterator_to_cursor(); 1686 | 1687 | assert_eq!(iter.next(), Some(&1)); 1688 | assert_eq!(iter.next(), Some(&2)); 1689 | assert_eq!(iter.next(), Some(&3)); 1690 | assert_eq!(iter.next(), None); 1691 | } 1692 | 1693 | #[test] 1694 | fn truncate_to_iterator_cursor_less_than_queue_length() { 1695 | let mut iter = [0, 1, 2, 3].iter().peekmore(); 1696 | iter.peek_nth(2); 1697 | iter.truncate_iterator_to_cursor(); 1698 | 1699 | assert_eq!(iter.next(), Some(&0)); 1700 | assert_eq!(iter.next(), Some(&1)); 1701 | assert_eq!(iter.next(), Some(&2)); 1702 | assert_eq!(iter.next(), Some(&3)); 1703 | assert_eq!(iter.next(), None); 1704 | 1705 | let mut iter = [0, 1, 2, 3].iter().peekmore(); 1706 | iter.peek_nth(3); 1707 | iter.advance_cursor(); 1708 | iter.truncate_iterator_to_cursor(); 1709 | 1710 | assert_eq!(iter.next(), Some(&1)); 1711 | assert_eq!(iter.next(), Some(&2)); 1712 | assert_eq!(iter.next(), Some(&3)); 1713 | assert_eq!(iter.next(), None); 1714 | } 1715 | 1716 | #[test] 1717 | fn peek_range_from_start_smaller_than_input_len() { 1718 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1719 | let view = peeking_queue.peek_range(0, 2); 1720 | 1721 | assert_eq!(view[0], Some(&0)); 1722 | assert_eq!(view[1], Some(&1)); 1723 | assert_eq!(view.len(), 2); 1724 | } 1725 | 1726 | #[test] 1727 | fn peek_range_from_start_eq_to_input_len() { 1728 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1729 | let view = peeking_queue.peek_range(0, 4); 1730 | 1731 | assert_eq!(view[0], Some(&0)); 1732 | assert_eq!(view[1], Some(&1)); 1733 | assert_eq!(view[2], Some(&2)); 1734 | assert_eq!(view[3], Some(&3)); 1735 | assert_eq!(view.len(), 4); 1736 | } 1737 | 1738 | #[test] 1739 | fn peek_range_from_start_bigger_than_input_len() { 1740 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1741 | let view = peeking_queue.peek_range(0, 6); 1742 | 1743 | assert_eq!(view[0], Some(&0)); 1744 | assert_eq!(view[1], Some(&1)); 1745 | assert_eq!(view[2], Some(&2)); 1746 | assert_eq!(view[3], Some(&3)); 1747 | assert_eq!(view[4], None); 1748 | assert_eq!(view[5], None); 1749 | assert_eq!(view.len(), 6); 1750 | } 1751 | 1752 | #[test] 1753 | fn peek_range_from_middle() { 1754 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1755 | let view = peeking_queue.peek_range(2, 5); 1756 | 1757 | assert_eq!(view[0], Some(&2)); 1758 | assert_eq!(view[1], Some(&3)); 1759 | assert_eq!(view[2], None); 1760 | assert_eq!(view.len(), 3); 1761 | } 1762 | 1763 | #[test] 1764 | fn peek_range_out_of_bounds() { 1765 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1766 | let view = peeking_queue.peek_range(5, 6); 1767 | 1768 | assert_eq!(view[0], None); 1769 | assert_eq!(view.len(), 1); 1770 | } 1771 | 1772 | #[test] 1773 | fn peek_range_empty() { 1774 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1775 | let view = peeking_queue.peek_range(0, 0); 1776 | 1777 | assert_eq!(view.len(), 0); 1778 | } 1779 | 1780 | #[test] 1781 | fn peek_range_match() { 1782 | let mut peeking_queue = ["call", "f", "1"].iter().peekmore(); 1783 | let view = peeking_queue.peek_range(1, 3); 1784 | 1785 | let value = match view { 1786 | [Some(&"f"), Some(arg)] => arg, 1787 | _ => panic!("test case peek_range_match failed"), 1788 | }; 1789 | 1790 | assert_eq!(**value, "1"); 1791 | assert_eq!(view.len(), 2); 1792 | } 1793 | 1794 | #[test] 1795 | #[should_panic] 1796 | fn peek_range_panic_on_invalid_range() { 1797 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1798 | let _ = peeking_queue.peek_range(2, 1); 1799 | } 1800 | 1801 | #[test] 1802 | fn peek_amount_from_start_smaller_than_input_len() { 1803 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1804 | let view = peeking_queue.peek_amount(2); 1805 | 1806 | assert_eq!(view[0], Some(&0)); 1807 | assert_eq!(view[1], Some(&1)); 1808 | assert_eq!(view.len(), 2); 1809 | } 1810 | 1811 | #[test] 1812 | fn peek_amount_from_start_eq_to_input_len() { 1813 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1814 | let view = peeking_queue.peek_amount(4); 1815 | 1816 | assert_eq!(view[0], Some(&0)); 1817 | assert_eq!(view[1], Some(&1)); 1818 | assert_eq!(view[2], Some(&2)); 1819 | assert_eq!(view[3], Some(&3)); 1820 | assert_eq!(view.len(), 4); 1821 | } 1822 | 1823 | #[test] 1824 | fn peek_amount_from_start_bigger_than_input_len() { 1825 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1826 | let view = peeking_queue.peek_amount(6); 1827 | 1828 | assert_eq!(view[0], Some(&0)); 1829 | assert_eq!(view[1], Some(&1)); 1830 | assert_eq!(view[2], Some(&2)); 1831 | assert_eq!(view[3], Some(&3)); 1832 | assert_eq!(view[4], None); 1833 | assert_eq!(view[5], None); 1834 | assert_eq!(view.len(), 6); 1835 | } 1836 | 1837 | #[test] 1838 | fn peek_amount_empty() { 1839 | let empty: [u32; 0] = []; 1840 | let mut peeking_queue = empty.iter().peekmore(); 1841 | let view = peeking_queue.peek_amount(3); 1842 | 1843 | assert_eq!(view[0], None); 1844 | assert_eq!(view[0], None); 1845 | assert_eq!(view[0], None); 1846 | assert_eq!(view.len(), 3); 1847 | } 1848 | 1849 | #[test] 1850 | fn peek_amount_zero() { 1851 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1852 | let view = peeking_queue.peek_amount(0); 1853 | 1854 | assert_eq!(view.len(), 0); 1855 | } 1856 | 1857 | #[test] 1858 | fn peek_amount_match() { 1859 | let mut peeking_queue = ["call", "f", "1"].iter().peekmore(); 1860 | let view = peeking_queue.peek_amount(4); 1861 | 1862 | let value = match view { 1863 | [Some(&"call"), Some(&"f"), Some(arg), None] => arg, 1864 | _ => panic!("test case peek_n_match failed"), 1865 | }; 1866 | 1867 | assert_eq!(**value, "1"); 1868 | assert_eq!(view.len(), 4); 1869 | } 1870 | 1871 | #[test] 1872 | fn peek_amount_renewed_view() { 1873 | let mut peeking_queue = [0, 1, 2, 3].iter().peekmore(); 1874 | let view = peeking_queue.peek_amount(2); 1875 | 1876 | assert_eq!(view[0], Some(&0)); 1877 | assert_eq!(view[1], Some(&1)); 1878 | 1879 | let _removed = peeking_queue.next(); 1880 | 1881 | let view = peeking_queue.peek_amount(2); 1882 | 1883 | assert_eq!(view[0], Some(&1)); 1884 | assert_eq!(view[1], Some(&2)); 1885 | } 1886 | 1887 | #[test] 1888 | fn next_if_works() { 1889 | let iterable = [1, 2, 3, 4]; 1890 | 1891 | let mut iter = iterable.iter().peekmore(); 1892 | 1893 | assert_eq!(iter.next_if(|&x| *x == 1), Some(&1)); 1894 | 1895 | assert_eq!(iter.peek(), Some(&&2)); 1896 | assert_eq!(iter.next_if(|&x| *x < 4), Some(&2)); 1897 | assert_eq!(iter.peek(), Some(&&3)); 1898 | 1899 | assert_eq!(iter.peek(), Some(&&3)); 1900 | assert_eq!(iter.next_if(|&x| *x != 3), None); 1901 | assert_eq!(iter.peek(), Some(&&3)); 1902 | 1903 | assert_eq!(iter.next(), Some(&3)); 1904 | assert_eq!(iter.next_if(|&_x| true), Some(&4)); 1905 | } 1906 | 1907 | #[test] 1908 | fn next_if_exhausted() { 1909 | let iterable = [1, 2]; 1910 | 1911 | let mut iter = iterable.iter().peekmore(); 1912 | 1913 | assert_eq!(iter.next_if(|&x| *x == 1), Some(&1)); 1914 | assert_eq!(iter.next_if(|&x| *x == 2), Some(&2)); 1915 | 1916 | assert_eq!(iter.next_if(|&x| *x == 2), None); 1917 | } 1918 | 1919 | #[test] 1920 | fn next_if_loop() { 1921 | let iterable = 1..15; 1922 | 1923 | let mut iter = iterable.peekmore(); 1924 | 1925 | while iter.next_if(|&x| x < 10).is_some() {} 1926 | assert_eq!(iter.next(), Some(10)); 1927 | } 1928 | 1929 | #[test] 1930 | fn next_if_with_advanced_cursor() { 1931 | let iterable = [1, 2, 3, 4]; 1932 | 1933 | let mut iter = iterable.iter().peekmore(); 1934 | 1935 | assert_eq!(iter.peek(), Some(&&1)); 1936 | let iter = iter.advance_cursor(); 1937 | let iter = iter.advance_cursor(); 1938 | assert_eq!(iter.peek(), Some(&&3)); 1939 | assert_eq!(iter.next_if(|&x| *x == 1), Some(&1)); 1940 | assert_eq!(iter.peek(), Some(&&3)); 1941 | assert_eq!(iter.next_if(|&x| *x == 2), Some(&2)); 1942 | } 1943 | 1944 | #[test] 1945 | fn next_if_eq_works() { 1946 | let iterable = [1, 2, 3, 4]; 1947 | 1948 | let mut iter = iterable.iter().peekmore(); 1949 | 1950 | assert_eq!(iter.next_if_eq(&&1), Some(&1)); 1951 | 1952 | assert_eq!(iter.peek(), Some(&&2)); 1953 | assert_eq!(iter.next_if_eq(&&2), Some(&2)); 1954 | assert_eq!(iter.peek(), Some(&&3)); 1955 | 1956 | assert_eq!(iter.peek(), Some(&&3)); 1957 | assert_eq!(iter.next_if_eq(&&0), None); 1958 | assert_eq!(iter.peek(), Some(&&3)); 1959 | 1960 | assert_eq!(iter.next_if_eq(&&3), Some(&3)); 1961 | assert_eq!(iter.next_if_eq(&&4), Some(&4)); 1962 | 1963 | assert_eq!(iter.next_if_eq(&&5), None); 1964 | } 1965 | } 1966 | --------------------------------------------------------------------------------