[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [orxfun]\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# Updated workflow (based on .github/workflows/ci.yml at ref d04ad7abce0c67776a7189001f706535e3e5c402)\nname: Rust\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\nenv:\n  CARGO_TERM_COLOR: always\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        toolchain: [\"stable\"]\n        features: [\"\", \"--all-features\", \"--no-default-features\"]\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Cache cargo registry & target\n      uses: actions/cache@v4\n      with:\n        path: |\n          ~/.cargo/registry\n          ~/.cargo/git\n          target\n        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-stable-${{ matrix.features || 'default' }}\n\n    - name: Install toolchain\n      uses: dtolnay/rust-toolchain@master\n      with:\n        toolchain: ${{ matrix.toolchain }}\n\n    - name: Install 32bit target (for builds if needed)\n      run: rustup target add i686-unknown-linux-musl\n\n    - name: Install wasm target\n      run: rustup target add wasm32-unknown-unknown\n\n    - name: Install miri\n      run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu miri\n\n    - name: Install no-std-check\n      run: cargo install cargo-no-std-check\n\n    - name: Build\n      run: cargo build --verbose ${{ matrix.features }}\n\n    - name: Build-wasm\n      run: cargo build --verbose --target wasm32-unknown-unknown ${{ matrix.features }}\n\n    - name: Test\n      run: cargo test --verbose ${{ matrix.features }}\n\n    - name: Check-wasm\n      run: cargo check --verbose --target wasm32-unknown-unknown ${{ matrix.features }}\n\n    - name: Clippy\n      run: cargo clippy ${{ matrix.features }} -- -D warnings --verbose\n\n    - name: Miri\n      run: cargo +nightly miri test --lib --bins --tests --verbose ${{ matrix.features }}\n\n\n  test-32:\n    name: Test (i686)\n    runs-on: ubuntu-latest\n    needs: build\n    env:\n      CARGO_TERM_COLOR: always\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Cache cargo registry & target\n        uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cargo/registry\n            ~/.cargo/git\n            target\n          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-stable-i686\n\n      - name: Install Rust toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Set up QEMU for multi-arch Docker\n        uses: docker/setup-qemu-action@v2\n\n      - name: Install Docker Buildx\n        uses: docker/setup-buildx-action@v2\n\n      - name: Install cross\n        run: cargo install --locked cross || true\n\n      - name: Run tests for i686 target via cross\n        run: |\n          # Run unit tests under QEMU inside Docker so i686 test binaries are executed reliably.\n          # Uses the glibc i686 target by default. Change to i686-unknown-linux-musl if you require musl.\n          cross test --target i686-unknown-linux-gnu --verbose\n"
  },
  {
    "path": ".gitignore",
    "content": "# Generated by Cargo\n# will have compiled files and executables\ndebug/\ntarget/\n.vscode/\n\n# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries\n# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html\nCargo.lock\n\n# These are backup files generated by rustfmt\n**/*.rs.bk\n\n# MSVC Windows builds of rustc generate these, which store debugging information\n*.pdb\n\nbenches/results/*.txt\n"
  },
  {
    "path": ".scripts/run_benchmark.sh",
    "content": "original_bench=find_iter_into_par\nbench=$1\n\nsed -i \"s/$original_bench/$bench/g\" Cargo.toml\n\nrm -f benches/results/$bench.txt\n\ncargo bench --all-features >> benches/results/$bench.txt\n\nsed -i \"s/$bench/$original_bench/g\" Cargo.toml\n"
  },
  {
    "path": ".scripts/run_benchmarks.sh",
    "content": "allBenches=(\n    chain_collect_map\n    chain3_collect_map\n    chain4_collect_map\n    collect_filter\n    collect_filtermap\n    collect_flatmap\n    collect_iter_into_par\n    collect_long_chain\n    collect_map_filter_hash_set\n    collect_map_filter\n    collect_map\n    count_filtermap\n    count_flatmap\n    count_map_filter\n    count_map\n    drain_vec_collect_map_filter\n    find_any\n    find_flatmap\n    find_iter_into_par\n    find_map_filter\n    find\n    mut_for_each_iter\n    mut_for_each_slice\n    reduce_iter_into_par\n    reduce_long_chain\n    reduce_map_filter\n    reduce_map\n    reduce\n    result_collect_map\n    result_reduce_map\n    sum_filtermap\n    sum_flatmap\n    sum_map_filter\n    sum\n    vec_deque_collect_map_filter\n    vec_deque_collect_map_filter_owned\n)\n\ncounter = 0\n\nfor t in ${allBenches[@]}; do\n    counter=$((counter+1))\n    echo -e \"\\n\\n\"\n    echo ------------- $counter : $t ----------------------------------\n    ./.scripts/run_benchmark.sh $t\ndone\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"orx-parallel\"\nversion = \"3.4.0\"\nedition = \"2024\"\nauthors = [\"orxfun <orx.ugur.arikan@gmail.com>\"]\nreadme = \"README.md\"\ndescription = \"High performance, configurable and expressive parallel computation library.\"\nlicense = \"MIT OR Apache-2.0\"\nrepository = \"https://github.com/orxfun/orx-parallel/\"\nkeywords = [\"parallel\", \"concurrency\", \"performance\", \"thread\", \"iterator\"]\ncategories = [\"concurrency\", \"algorithms\"]\n\n[dependencies]\norx-pinned-vec = { version = \"3.21.0\", default-features = false }\norx-fixed-vec = { version = \"3.22.0\", default-features = false }\norx-split-vec = { version = \"3.22.0\", default-features = false }\norx-concurrent-iter = { version = \"3.3.0\", default-features = false }\norx-concurrent-bag = { version = \"3.4.0\", default-features = false }\norx-concurrent-ordered-bag = { version = \"3.4.0\", default-features = false }\norx-pinned-concurrent-col = { version = \"2.18.0\", default-features = false }\norx-iterable = { version = \"1.3.0\", default-features = false }\norx-priority-queue = { version = \"1.7.0\", default-features = false }\norx-pseudo-default = { version = \"2.1.0\", default-features = false }\norx-concurrent-recursive-iter = { version = \"2.0.0\", default-features = false }\n\n# optional: generic iterator\nrayon = { version = \"1.11.0\", optional = true, default-features = false }\n\n# optional: thread pool\npond = { version = \"0.3.1\", optional = true, default-features = false }\npoolite = { version = \"0.7.1\", optional = true, default-features = false }\nrayon-core = { version = \"1.13.0\", optional = true, default-features = false }\nscoped-pool = { version = \"1.0.0\", optional = true, default-features = false }\nscoped_threadpool = { version = \"0.1.9\", optional = true, default-features = false }\nyastl = { version = \"0.1.2\", optional = true, default-features = false }\n\n[dev-dependencies]\nchrono = \"0.4.42\"\nclap = { version = \"4.5.50\", features = [\"derive\"] }\ncriterion = { version = \"0.8\", features = [\"html_reports\"] }\norx-concurrent-option = { version = \"1.5.0\", default-features = false }\norx-concurrent-vec = \"3.10.0\"\nrand = \"0.9.2\"\nrand_chacha = \"0.9\"\nrayon = \"1.11.0\"\ntest-case = \"3.3.1\"\norx-criterion = { git = \"https://github.com/orxfun/orx-criterion\" }\n\n[[bench]]\nname = \"find_iter_into_par\"\nharness = false\n\n[package.metadata.docs.rs]\nall-features = true\n\n[features]\ndefault = [\"std\"]\nstd = []\ngeneric_iterator = [\"rayon\"]\nexperiment = []\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "                              Apache License\n                        Version 2.0, January 2004\n                     http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n   \"License\" shall mean the terms and conditions for use, reproduction,\n   and distribution as defined by Sections 1 through 9 of this document.\n\n   \"Licensor\" shall mean the copyright owner or entity authorized by\n   the copyright owner that is granting the License.\n\n   \"Legal Entity\" shall mean the union of the acting entity and all\n   other entities that control, are controlled by, or are under common\n   control with that entity. For the purposes of this definition,\n   \"control\" means (i) the power, direct or indirect, to cause the\n   direction or management of such entity, whether by contract or\n   otherwise, or (ii) ownership of fifty percent (50%) or more of the\n   outstanding shares, or (iii) beneficial ownership of such entity.\n\n   \"You\" (or \"Your\") shall mean an individual or Legal Entity\n   exercising permissions granted by this License.\n\n   \"Source\" form shall mean the preferred form for making modifications,\n   including but not limited to software source code, documentation\n   source, and configuration files.\n\n   \"Object\" form shall mean any form resulting from mechanical\n   transformation or translation of a Source form, including but\n   not limited to compiled object code, generated documentation,\n   and conversions to other media types.\n\n   \"Work\" shall mean the work of authorship, whether in Source or\n   Object form, made available under the License, as indicated by a\n   copyright notice that is included in or attached to the work\n   (an example is provided in the Appendix below).\n\n   \"Derivative Works\" shall mean any work, whether in Source or Object\n   form, that is based on (or derived from) the Work and for which the\n   editorial revisions, annotations, elaborations, or other modifications\n   represent, as a whole, an original work of authorship. For the purposes\n   of this License, Derivative Works shall not include works that remain\n   separable from, or merely link (or bind by name) to the interfaces of,\n   the Work and Derivative Works thereof.\n\n   \"Contribution\" shall mean any work of authorship, including\n   the original version of the Work and any modifications or additions\n   to that Work or Derivative Works thereof, that is intentionally\n   submitted to Licensor for inclusion in the Work by the copyright owner\n   or by an individual or Legal Entity authorized to submit on behalf of\n   the copyright owner. For the purposes of this definition, \"submitted\"\n   means any form of electronic, verbal, or written communication sent\n   to the Licensor or its representatives, including but not limited to\n   communication on electronic mailing lists, source code control systems,\n   and issue tracking systems that are managed by, or on behalf of, the\n   Licensor for the purpose of discussing and improving the Work, but\n   excluding communication that is conspicuously marked or otherwise\n   designated in writing by the copyright owner as \"Not a Contribution.\"\n\n   \"Contributor\" shall mean Licensor and any individual or Legal Entity\n   on behalf of whom a Contribution has been received by Licensor and\n   subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   copyright license to reproduce, prepare Derivative Works of,\n   publicly display, publicly perform, sublicense, and distribute the\n   Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   (except as stated in this section) patent license to make, have made,\n   use, offer to sell, sell, import, and otherwise transfer the Work,\n   where such license applies only to those patent claims licensable\n   by such Contributor that are necessarily infringed by their\n   Contribution(s) alone or by combination of their Contribution(s)\n   with the Work to which such Contribution(s) was submitted. If You\n   institute patent litigation against any entity (including a\n   cross-claim or counterclaim in a lawsuit) alleging that the Work\n   or a Contribution incorporated within the Work constitutes direct\n   or contributory patent infringement, then any patent licenses\n   granted to You under this License for that Work shall terminate\n   as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n   Work or Derivative Works thereof in any medium, with or without\n   modifications, and in Source or Object form, provided that You\n   meet the following conditions:\n\n   (a) You must give any other recipients of the Work or\n       Derivative Works a copy of this License; and\n\n   (b) You must cause any modified files to carry prominent notices\n       stating that You changed the files; and\n\n   (c) You must retain, in the Source form of any Derivative Works\n       that You distribute, all copyright, patent, trademark, and\n       attribution notices from the Source form of the Work,\n       excluding those notices that do not pertain to any part of\n       the Derivative Works; and\n\n   (d) If the Work includes a \"NOTICE\" text file as part of its\n       distribution, then any Derivative Works that You distribute must\n       include a readable copy of the attribution notices contained\n       within such NOTICE file, excluding those notices that do not\n       pertain to any part of the Derivative Works, in at least one\n       of the following places: within a NOTICE text file distributed\n       as part of the Derivative Works; within the Source form or\n       documentation, if provided along with the Derivative Works; or,\n       within a display generated by the Derivative Works, if and\n       wherever such third-party notices normally appear. The contents\n       of the NOTICE file are for informational purposes only and\n       do not modify the License. You may add Your own attribution\n       notices within Derivative Works that You distribute, alongside\n       or as an addendum to the NOTICE text from the Work, provided\n       that such additional attribution notices cannot be construed\n       as modifying the License.\n\n   You may add Your own copyright statement to Your modifications and\n   may provide additional or different license terms and conditions\n   for use, reproduction, or distribution of Your modifications, or\n   for any such Derivative Works as a whole, provided Your use,\n   reproduction, and distribution of the Work otherwise complies with\n   the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n   any Contribution intentionally submitted for inclusion in the Work\n   by You to the Licensor shall be under the terms and conditions of\n   this License, without any additional terms or conditions.\n   Notwithstanding the above, nothing herein shall supersede or modify\n   the terms of any separate license agreement you may have executed\n   with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n   names, trademarks, service marks, or product names of the Licensor,\n   except as required for reasonable and customary use in describing the\n   origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n   agreed to in writing, Licensor provides the Work (and each\n   Contributor provides its Contributions) on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n   implied, including, without limitation, any warranties or conditions\n   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n   PARTICULAR PURPOSE. You are solely responsible for determining the\n   appropriateness of using or redistributing the Work and assume any\n   risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n   whether in tort (including negligence), contract, or otherwise,\n   unless required by applicable law (such as deliberate and grossly\n   negligent acts) or agreed to in writing, shall any Contributor be\n   liable to You for damages, including any direct, indirect, special,\n   incidental, or consequential damages of any character arising as a\n   result of this License or out of the use or inability to use the\n   Work (including but not limited to damages for loss of goodwill,\n   work stoppage, computer failure or malfunction, or any and all\n   other commercial damages or losses), even if such Contributor\n   has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n   the Work or Derivative Works thereof, You may choose to offer,\n   and charge a fee for, acceptance of support, warranty, indemnity,\n   or other liability obligations and/or rights consistent with this\n   License. However, in accepting such obligations, You may act only\n   on Your own behalf and on Your sole responsibility, not on behalf\n   of any other Contributor, and only if You agree to indemnify,\n   defend, and hold each Contributor harmless for any liability\n   incurred by, or claims asserted against, such Contributor by reason\n   of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "MIT License\n\nCopyright (c) 2024 Ugur Arikan\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n"
  },
  {
    "path": "README.md",
    "content": "# orx-parallel\n\n[![orx-parallel crate](https://img.shields.io/crates/v/orx-parallel.svg)](https://crates.io/crates/orx-parallel)\n[![orx-parallel crate](https://img.shields.io/crates/d/orx-parallel.svg)](https://crates.io/crates/orx-parallel)\n[![orx-parallel documentation](https://docs.rs/orx-parallel/badge.svg)](https://docs.rs/orx-parallel)\n\n[High performance](#performance-and-benchmarks), [configurable](#configurable) and [expressive](#parallel-computation-by-iterators) parallel computation library.\n\n* [Parallel Computation by Iterators](#parallel-computation-by-iterators)\n* [Parallelizable Collections](#parallelizable-collections)\n* [Parallelization over Nonlinear Data Structures](#parallelization-over-nonlinear-data-structures)\n* [Performance and Benchmarks](#performance-and-benchmarks)\n* [Fallible Parallel Iterators](#fallible-parallel-iterators)\n* [Using Mutable Variables](#using-mutable-variables)\n* [Configurations](#configurations)\n* [Runner: Pools and Executors](#runner-pools-and-executors)\n* [Contributing](#contributing)\n\n## Parallel Computation by Iterators\n\nParallel computation is defined using the parallel iterator trait [`ParIter`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html).\n\nThe goal is to convert an expressive sequential program into an efficient parallel program only by replacing `iter` with `par`; and `into_iter` with `into_par`.\n\nThe following is a naive [traveling salesperson](https://en.wikipedia.org/wiki/Travelling_salesman_problem) algorithm which randomly generates sequences and picks the one with the minimum duration as the best tour. The example demonstrates chaining of very common and useful `map`, `filter` and `reduce` (`min_by_key`) operations. Notice that the only difference between the sequential and parallel programs is the `par()` call.\n\n```rust\nuse orx_parallel::*;\nuse rand::prelude::*;\n\nstruct Tour(Vec<usize>);\n\nimpl Tour {\n    fn random(n: usize) -> Self {\n        let mut cities: Vec<_> = (0..n).collect();\n        cities.shuffle(&mut rand::rng());\n        Self(cities)\n    }\n\n    fn not_in_standard_order(&self) -> bool {\n        self.0.iter().enumerate().any(|(i, c)| i != *c)\n    }\n\n    fn duration(&self) -> usize {\n        let mut total = 0;\n        let links = self.0.iter().zip(self.0.iter().skip(1));\n        for (a, b) in links {\n            total += (*a as i64 - *b as i64).abs() as usize;\n        }\n        total\n    }\n}\n\nlet num_tours = 1_000_000;\nlet num_cities = 10;\n\n// sequential\nlet best_tour = (0..num_tours)\n    .map(|_| Tour::random(num_cities))\n    .filter(|t| t.not_in_standard_order())\n    .min_by_key(|t| t.duration())\n    .unwrap();\n\n// parallel\nlet best_tour = (0..num_tours)\n    .par() // parallelized !!\n    .map(|_| Tour::random(num_cities))\n    .filter(|t| t.not_in_standard_order())\n    .min_by_key(|t| t.duration())\n    .unwrap();\n```\n\n## Parallelizable Collections\n\nInputs that can be used in parallel computations can be categorized in three groups:\n\n* i. directly parallelizable collections\n* ii. parallelization of any iterator\n* iii. parallelization of any collection\n\n### i. Directly Parallelizable Collections\n\nThese are collections which are parallelized by utilizing their specific structure to achieve high performance.\n\nThis crate provides direct implementations of std collections; the table below lists the most recent table of direct implementations.\n\n\n| Type | Over References<br>`&T` | Over Mut References <br>`&mut T>` | Over Owned Values<br>` T` |\n|:--|:-:|:-:|:-:|\n| `v: Vec<T>` | `v.par()` | `v.par_mut()` | `v.into_par()` |\n| `v: VecDeque<T>` | `v.par()` | | `v.into_par()` |\n| `s: &[T]` | `s.par()`<br>`s.into_par()` | | |\n| `s: &mut [T]` | | `s.into_par()` | |\n| `r: Range<usize>`| | | `r.par()`<br>`r.into_par()` |\n\nImplementations of custom collections belong to their respective crates as they most likely require access to internals. Currently, the following collections are known to allow parallel computation using this crate:\n\n│ [SplitVec](https://crates.io/crates/orx-split-vec) │ [FixedVec](https://crates.io/crates/orx-fixed-vec) │ [LinkedList](https://crates.io/crates/orx-linked-list) │ [Tree](https://crates.io/crates/orx-tree) │ [ImpVec](https://crates.io/crates/orx-imp-vec) │\n\nSince these implementations are particularly optimized for the collection type, it is preferable to start defining parallel computation from the collection whenever available. In other words, for a direclty parallelizable collection `col`,\n\n* `col.par().map(_).filter(_).reduce(_)` is a better approach than\n* `col.iter().iter_into_par().map(_).filter(_).reduce(_)`, which will be explained in the next subsection.\n\n> **extensibility**: Note that any input collection or generator that implements [`IntoConcurrentIter`](https://docs.rs/orx-concurrent-iter/latest/orx_concurrent_iter/trait.IntoConcurrentIter.html) automatically implements [`IntoParIter`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.IntoParIter.html). Therefore, a new collection can be parallelized provided that its concurrent iterator is implemented.\n\nIn addition, there exist the following special parallel iterators that can be directly created from the collection.\n\n| Type | Method | Definition |\n|---|---|---|\n| `v: Vec<T>` | [`v.par_drain(range)`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParallelDrainableOverSlice.html) | Parallel counterpart of `v.drain(range)` |\n\n### ii. Parallelization of Any Iterator\n\nAny arbitrary sequential [Iterator](https://doc.rust-lang.org/std/iter/trait.Iterator.html) implements [`IterIntoParIter`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.IterIntoParIter.html) trait and can be converted into a parallel iterator using the `iter_into_par` method.\n\nAs demonstrated below, item type of the Iterator can as well be a mutable reference.\n\n```rust\nuse orx_parallel::*;\nuse std::collections::HashMap;\n\nlet mut map: HashMap<_, _> = (0..1024).map(|x| (x.to_string(), x)).collect();\n\nlet par = map.values_mut().iter_into_par(); // mutable parallel iterator from Iterator\npar.filter(|x| **x != 42).for_each(|x| *x *= 0);\n\nassert_eq!(map.values().iter_into_par().sum(), 42); // parallel iterator from Iterator\n```\n\nThis is powerful since it allows to parallelize all iterables, including pretty much every collection and more.\n\nOn the other hand, due to being a generic implementation without collection specific optimizations, parallelized computation might underperform its sequential counterpart if the work to be done on each input element is insignificant. For instance, `i` being an arbitrary iterator of numbers, `i.sum()` will most likely be faster than `i.iter_into_par().sum()`.\n\nThis being said, `ParIter` takes advantage of certain optimizations, such as buffering and chunk size optimization, in order to improve performance. Therefore, whenever the computation on the iterator elements is more involved than just returning them or adding numbers, we can benefit from parallelization. The respective section of [benchmarks](#parallelization-of-arbitrary-iterators) present significant improvements achieved consistently.\n\n### iii. Parallelization of Any Collection\n\nLastly, consider a collection which does not provide a direct concurrent iterator implementation. This might be our custom collection, say `MyCollection`; or an external collection without a concurrent iterator implementation, such as the `HashSet<T>`.\n\nThere are two methods to parallelize computations over such collections:\n* (ii) parallelize using the collection's iterator, or\n* (i) collect the elements in a vector and then parallelize work over the vector.\n\nThe following table demonstrates these methods for the `HashSet`; however, they are applicable to any collection with `iter` and `into_iter` methods.\n\n| Type | Method | Over References<br>`&T` | Over Owned Values<br>`T` |\n|:--|:-:|---|---|\n| `h: HashSet<T>` | ii | `h.iter()`<br>&nbsp;&nbsp;`.iter_into_par()` | `h.into_iter()`<br>&nbsp;&nbsp;`.iter_into_par()` |\n|                 | i  | `h.iter()`<br>&nbsp;&nbsp;`.collect::<Vec<_>>()`<br>&nbsp;&nbsp;`.par()` | `h.into_iter()`<br>&nbsp;&nbsp;`.collect::<Vec<_>>()`<br>&nbsp;&nbsp;`.into_par()` |\n\nNote that each approach can be more efficient in different scenarios. For large elements, (ii) might be preferred to avoid allocation of the vector. For insignificant tasks to be performed on each element, (i) might be preferred to take full benefit of vector-specific optimizations.\n\n## Parallelization over Nonlinear Data Structures\n\n[IntoParIterRec](https://docs.rs/orx-parallel/latest/orx_parallel/trait.IntoParIterRec.html) trait can be used to create a **parallel recursive iterator** over an initial set of elements which is useful when working with non-linear data structures such as **trees** and **graphs**.\n\nConsider, for instance, a tree which is defined by the following node struct:\n\n```rust ignore\npub struct Node<T> {\n    pub data: T,\n    pub children: Vec<Node<T>>,\n}\n```\n\nAssume that we want to map all the data with `map: impl Fn(T) -> u64` and compute the sum of mapped values of all nodes descending from a `root: &Node`.\n\nWe can express this computation and execute in parallel with the following:\n\n```rust ignore\nfn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n    queue.extend(&node.children);\n}\n\n[root].into_par_rec(extend).map(map).sum()\n```\n\nInstead of `into_par`, we use `into_par_rec` and provide `extend` function as its argument. This function defines the recursive extension of the parallel iterator such that every time we process a `node` we first add its children to the `queue`. [`Queue`](https://docs.rs/orx-concurrent-recursive-iter/latest/orx_concurrent_recursive_iter/struct.Queue.html) is the queue of elements to be processed and it exposes two growth methods to define the recursive extension: `push` and `extend`.\n\nAlthough we create the parallel iterator differently, we get a `ParIter`. Therefore, we have access to all features of a regular parallel iterator.\n\nFor instance, assume we want to filter nodes first. Further, instead of summing up the mapped values, we need to collect them in a vector. We can express this computation just as we would do on a linear data structure:\n\n```rust ignore\n[root].into_par_rec(extend).filter(filter).map(map).collect()\n```\n\nFor more details, you may see the [parallelization_on_tree](https://github.com/orxfun/orx-parallel/blob/main/examples/parallelization_on_tree) example.\n\n## Performance and Benchmarks\n\n*Please also see [impact of ChunkSize on performance](#impact-of-chunksize-on-performance) section.*\n\nYou may find some sample parallel programs in [examples](https://github.com/orxfun/orx-parallel/blob/main/examples) directory. These examples allow to express parallel computations as iterator method compositions and run quick experiments with different approaches. Examples use `GenericIterator`. As the name suggests, it is a generalization of sequential iterator, rayon's parallel iterator and orx-parallel's parallel iterator, and hence, allows for convenient experiments. You may play with the code, update the tested computations and run these examples by including **generic_iterator** feature, such as:\n\n`cargo run --release --features generic_iterator --example benchmark_collect -- --len 123456 --num-repetitions 10`\n\nActual benchmark files are located in [benches](https://github.com/orxfun/orx-parallel/blob/main/benches) directory. Tables below report average execution times in microseconds. The numbers in parentheses represent the ratio of execution time to that of sequential computation which is used as the baseline (1.00). Parallelized executions of all benchmarks are carried out with default settings. \n\nComputations are separated into three categories with respect to how the iterator is consumed: collect, reduce and early-exit. Further, two additional categories are created to test parallelization of arbitrary iterators ([ii](#ii-parallelization-of-any-iterator)) and flexibility in composition of computations.\n\n### Collect\n\nIn this group of benchmarks, outputs of parallel computations are collected into vectors. Details of the iterator chains and tested functions can be found in the respective benchmark files (you may use the link in the **file** column).\n\n> **(s)** Outputs can also be collected into a [`SplitVec`](https://crates.io/crates/orx-split-vec), which can provide further improvements by avoiding memory copies. Note that a split vector provides constant time random access; and despite the fact that it is split to fragments, it asymptotically inherits advantages of contiguous vectors.\n\n|file|computation|sequential|rayon|orx-parallel|orx-parallel (s)|\n|---|---|---:|---:|---:|---:|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_filter.rs)|`.filter(_).collect()`|2.74 (1.00)|12.14 (4.43)|**1.80 (0.66)**|1.87 (0.68)|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_filtermap.rs)|`.filter_map(_).collect()`|6.96 (1.00)|13.28 (1.91)|3.51 (0.50)|**3.35 (0.48)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_flatmap.rs)|`.flat_map(_).collect()`|77.93 (1.00)|239.83 (3.08)|31.73 (0.41)|**23.79 (0.31)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_map_filter.rs)|`.map(_).filter(_).collect()`|19.24 (1.00)|9.99 (0.52)|6.21 (0.32)|**5.98 (0.31)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_map.rs)|`.map(_).collect()`|18.08 (1.00)|7.98 (0.44)|**5.28 (0.29)**|6.09 (0.34)|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/drain_vec_collect_map_filter.rs)|`.map(_).filter(_).collect()` [☆][draining_iterator]|19.41 (1.00)|7.54 (0.39)|5.90 (0.30)|**5.77 (0.30)**|\n\n[draining_iterator]: ## \"parallel draining iterator\"\n\n\n### Reduce\n\nIn this group, instead of collecting outputs, the results are reduced to a single value. Some common reductions are `sum`, `count`, `min`, etc.\n\n|file|computation|sequential|rayon|orx-parallel|\n|---|---|---:|---:|---:|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/reduce_map_filter.rs)|`.map(_).filter(_).reduce(_)`|14.15 (1.00)|7.55 (0.53)|**3.86 (0.27)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/reduce_map.rs)|`.map(_).reduce(_)`|13.81 (1.00)|6.25 (0.45)|**4.15 (0.30)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/reduce.rs)|`.reduce(_)`|0.97 (1.00)|10.58 (10.91)|**0.90 (0.93)**|\n\n\n### Find\n\nHere, computations that allow for *early exit* or *short-circuit* are investigated. As an example, experiments on `find` method are presented; methods such as `find_any`, `any` or `all` lead to similar results.\n\n|file|computation|sequential|rayon|orx-parallel|\n|---|---|---:|---:|---:|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/)|`.flat_map(_).find(_)`|160.24 (1.00)|127.37 (0.79)|**27.66 (0.17)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/)|`.map(_).filter(_).find(_)`|43.01 (1.00)|11.14 (0.26)|**8.61 (0.20)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/)|`.find(_)`|2.94 (1.00)|12.85 (4.37)|**1.54 (0.52)**|\n\n\n### Parallelization of Arbitrary Iterators\n\nAs discussed in [ii](#ii-parallelization-of-any-iterator), parallelization of regular iterators is a powerful feature. The benchmarks in this category demonstrate that improvements can be achieved provided that the computation on elements is not insignificant.\n\n|file|computation|sequential|rayon|orx-parallel|\n|---|---|---:|---:|---:|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_long_chain.rs)|`…long_chain.collect()`|19.72 (1.00)|32.54 (1.65)|**6.12 (0.31)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/reduce_iter_into_par.rs)|`.map(_).filter(_).reduce(_)`|15.17 (1.00)|118.28 (7.80)|**4.98 (0.33)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/)|`.map(_).filter(_).find(_)`|42.58 (1.00)|63.60 (1.49)|**7.98 (0.19)**|\n\n### Parallel Mutable Iterators\n\nIn this group, we investigate the performance of parallel computation which mutates the input elements. In the benchmarks, we filter elements and update the ones which satisfy the given criterion within the `for_each` call.\n\n|file|computation|sequential|rayon|orx-parallel|\n|---|---|---:|---:|---:|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/mut_for_each_slice.rs)|`slice.par_mut().filter(_).for_each(_)`|62.61 (1.00)|14.08 (0.22)|**8.45 (0.13)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/mut_for_each_iter.rs)|`iter.iter_into_par().filter(_).for_each(_)`|77.63 (1.00)|78.69 (1.01)|**10.03 (0.13)**|\n\n\n### Composition\n\nIn the final category of benchmarks, impact of long chains of transformations on computation time is tested. You may see such example long chains in the benchmark computations below, where `long_chain` is a shorthand for `.map(map1).filter(filter1).map(map2).filter(filter2).map(map3).map(map4).filter(filter4)`. Notice that the caller can actually shorten the chains by composing some of them. An obvious one is the `.map(map3).map(map4)` call which could have been one call like `map(map3-then-map4)`. However, this is not always possible as the computation might be conditionally built up in stages. Further, breaking transformations into smaller pieces help in achieving more descriptive computation definitions.\n\nThe results suggest that the functions are efficiently composed by the parallel iterator.\n\n|file|computation|sequential|rayon|orx-parallel|\n|---|---|---:|---:|---:|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_long_chain.rs)|`…long_chain.collect()`|14.27 (1.00)|6.33 (0.44)|**3.80 (0.27)**|\n|[⇨](https://github.com/orxfun/orx-parallel/blob/main/benches/reduce_long_chain.rs)|`…long_chain.reduce(_)`|15.08 (1.00)|6.10 (0.40)|**4.03 (0.27)**|\n\n## Fallible Parallel Iterators\n\nWe enjoy rust's [`?`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator) operator when working with fallible computations. It allows us to focus on and code only the success path. Failure at any step of the computation leads to a short-circuit and immediately returns from the function.\n\n```rust\nfn try_to_parse() -> Result<i32, std::num::ParseIntError> {\n    let x: i32 = \"123\".parse()?; // x = 123\n    let y: i32 = \"24a\".parse()?; // returns an Err() immediately\n    Ok(x + y)                    // Doesn't run.\n}\n```\n\nHowever, we do not have this convenience while working with iterators.\n\n`collect` is the only exception. Normally, it allows us to pick the container to collect the items into.\n\n```rust\nlet into_vec: Vec<usize> = (0..10).collect();\nlet into_set: std::collections::HashSet<usize> = (0..10).collect();\n```\n\nBut it also does something exceptional when the item type is a result:\n* The first computation below is similar to above, it simply collects each element to the container which is defined as a vector.\n* The second computation; however, is fundamentally different. It collects elements iff all elements are of the Ok variant. Further, it short-circuits the computation as soon as an Err is observed. This is exactly how the `?` operator behaves.\n\n```rust\nlet into_vec_of_results: Vec<Result<usize, char>> = (0..10).map(|x| Ok(x)).collect();\nlet into_result_of_vec: Result<Vec<usize>, char> = (0..10).map(|x| Ok(x)).collect();\n```\n\nAlthough convenient, change in the behavior of the collect computation might be considered *unexpected*, at least for me.\n\nFurther, we do have not short-circuiting methods for computations other than collect. For instance, it is not as convenient to compute the sum of numbers of an iterator provided that all elements are of the Ok variant, and receive the error otherwise.\n\nIn general, the requirement to early exit in fallible computation is common and important both for performance and convenience reasons.\n\nFor parallel computation, this crate proposes to explicitly transform an iterator with fallible elements into a fallible parallel iterator.\n\n```rust\nuse orx_parallel::*;\nuse std::num::ParseIntError;\n\nlet collect: Result<Vec<i32>, ParseIntError> = vec![\"7\", \"2\", \"34\"]\n    .into_par()\n    .map(|x| x.parse::<i32>())\n    .into_fallible_result() // <-- explicit transformation to fallible iterator\n    .collect();\n```\n\nCurrently, there exist two fallible parallel iterators [`ParIterResult`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIterResult.html) and [`ParIterOption`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIterOption.html). The transformation is as follows:\n\n| Regular Iterator | Transformation  Method| Fallible Iterator |\n| --- | --- | --- |\n| `ParIter<Item=Result<T, E>>` | `into_fallible_result()` | `ParIterResult<Item=T, Error=E>` |\n| `ParIter<Item=Option<T>>` | `into_fallible_option()` | `ParIterOption<Item=T>` |\n\nAfter converting into a fallible iterator, each chaining transformation is based on the success item type. Similar to `?` operator, this allows us to focus on the success path while any error case will be handled by early returning from the iterator with the error.\n\n```rust\nuse orx_parallel::*;\nuse std::num::ParseIntError;\n\nlet sum: Result<i32, ParseIntError> = vec![\"7\", \"2\", \"34\"]\n    .into_par()\n    .map(|x| x.parse::<i32>()) // Item = Result<i32, ParseIntError>\n    .into_fallible_result() // we are only working with success type after this point\n    .map(|x| x + 1)\n    .filter(|x| x % 2 == 0)\n    .flat_map(|x| [x, x + 1, x + 2])\n    .sum(); // returns Result, rather than i32\nassert_eq!(sum, Ok(27));\n\nlet sum: Result<i32, ParseIntError> = vec![\"7\", \"!!!\", \"34\"]\n    .into_par()\n    .map(|x| x.parse::<i32>())\n    .into_fallible_result()\n    .map(|x| x + 1)\n    .filter(|x| x % 2 == 0)\n    .flat_map(|x| [x, x + 1, x + 2])\n    .sum();\nassert!(sum.is_err());\n```\n\nAs demonstrated above, not only `collect` but all computation methods return a `Result`.\n\nTo summarize:\n* We can use all iterator methods with fallible iterators as well.\n* The transformations are based on the success type. All computations return a `Result`:\n  * if all computations succeed, it is `Ok` of the value that an infallible iterator would return;\n  * it is the first discovered `Err` if any of the computations fails.\n* Finally, all computations immediately return in case of an error.\n\nOptional fallible iterator behaves exactly the same, except that `None` is treated as the failure case.\n\n## Using Mutable Variables\n\nIterator methods allow us to define expressive computations using closures. These closures are often `FnMut` for sequential iterators allowing to mutably capture variables from the scope. It is clear that this is not possible for parallel iterators as it would lead to race condition when multiple threads simultaneously try to access the captured mutable variable. Therefore, parallel counterpart of the iterator methods often accept closures implementing `Fn`.\n\nHowever, it is necessary to have mutable variables for certain programs. A very common example is computations requiring random number generators which are stateful and can create random numbers only with a mutable reference.\n\n**using** transformation aims to provide a general and safe solution to this problem as follows:\n* One mutable variable per thread; hence, no race conditions.\n* The mutable variable is explicitly and mutably available to all iterator methods.\n\nThe following two examples demonstrate the idea and usage:\n\n* [`using`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.using) takes a closure with thread index as the argument, describing how the mutable variable should be created for each thread.\n* [`using_clone`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.using_clone), on the other hand, takes the value to be used as the mutable variable and shares a clone of it with each thread (just a shorthand for `using(|_| sender.clone())`).\n\nIn either case, there will exactly be `n` mutable variables created provided that the parallel computation uses `n` threads.\n\n```rust ignore\ninput\n    .into_par()\n    .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64)) // <-- explicit using\n    .map(|_, i| fibonacci((i % 50) + 1) % 10)       // rng: &mut ChaCha20Rng\n    .filter(|rng, _: &u64| rng.random_bool(0.4))    // is accessible for\n    .map(|rng, i: u64| rng.random_range(0..i))      // all iterator methods\n    .sum()\n\nlet (sender, receiver) = channel();\n```\n\n```rust ignore\nlet (sender, receiver) = channel();\n(0..5)\n    .into_par()\n    .using_clone(sender)\n    .for_each(|s, x| s.send(x).unwrap());\n\nlet mut res: Vec<_> = receiver.iter().collect();\n```\n\nFurther details can be found in [using.md](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n\n## Configurations\n\n### Configuration per Computation\n\nEach parallel computation is governed by two main straightforward parameters.\n\n[`NumThreads`](https://docs.rs/orx-parallel/latest/orx_parallel/enum.NumThreads.html) is the degree of parallelization. This is a *capacity parameter* used to limit the resources that can be used by the computation.\n* `Auto`: All available threads can be used, but not necessarily.\n* `Max(n)`: The computation can spawn at most n threads.\n* `Max(1)`: Falls back to sequential execution on the main thread.\n\n[`ChunkSize`](https://docs.rs/orx-parallel/latest/orx_parallel/enum.ChunkSize.html) represents the number of elements a parallel worker will pull and process every time it becomes idle. This is an *optimization parameter* that can be tuned to balance the overhead of parallelization and cost of heterogeneity of tasks.\n* `Auto`: Let the parallel executor dynamically decide, achieves high performance in general and can be used unless we have useful computation specific knowledge.\n* `Exact(c)`: Chunks will have c elements; gives complete control to the caller. Useful when we have a very good knowledge or want to tune the computation for certain data.\n* `Min(c)`: Every chunk will have at least c elements. Parallel executor; however, might decide to pull more if each computation is handled very fast.\n\nSee also the last parameter [`IterationOrder`](https://docs.rs/orx-parallel/latest/orx_parallel/enum.IterationOrder.html) with variants `Ordered` (default) and `Arbitrary` which is another useful optimization parameter for specific use cases.\n\nWhen omitted, `NumThreads::Auto` and `ChunkSize::Auto` will be used. Configuring parallel computation is **straightforward** and **specific to computation** rather than through a global setting.\n\n```rust\nuse orx_parallel::*;\nuse std::num::NonZeroUsize;\n\nlet n = 1024;\n\n_ = (0..n).par().sum(); // NumThreads::Auto & ChunkSize::Auto\n\n_ = (0..n).par().num_threads(4).sum(); // <= 4 threads\n_ = (0..n).par().num_threads(1).sum(); // sequential\n_ = (0..n).par().num_threads(0).sum(); // shorthand for NumThreads::Auto\n\n_ = (0..n).par().chunk_size(64).sum(); // chunks of exactly 64 elements\nlet c = ChunkSize::Min(NonZeroUsize::new(16).unwrap());\n_ = (0..n).par().chunk_size(c).sum(); // chunks of at least 16 elements\n\n_ = (0..n).par().num_threads(4).chunk_size(16).sum(); // set both params\n```\n\nNote that `NumThreads::Max(1)` executes the computation sequentially.\n\nThis gives the consumer, who actually executes the defined computation, complete control to:\n\n* execute in parallel with the given configuration, or\n* execute sequentially, or\n* execute in parallel with any number of threads that it decides.\n\nThis is guaranteed by the fact that both consuming computation calls and configuration methods require ownership (`self`) of the iterator.\n\n### Global Configuration\n\nAdditionally, maximum number of threads that can be used by parallel computations can be globally bounded by the environment variable `ORX_PARALLEL_MAX_NUM_THREADS`. Please see the corresponding [example](https://github.com/orxfun/orx-parallel/blob/main/examples/max_num_threads_config.rs) for details.\n\n### Impact of `ChunkSize` on Performance\n\nThe impact of the chunk size on performance might be significant.\n\nOur objective is to minimize the sum of two computational costs:\n* parallelization overhead => it gets smaller as chunk size gets greater\n* cost of heterogeneity => it gets larger as chunk size gets greater\n\nParallelization overhead can further be divided into two:\n* concurrent state update: This often corresponds to one atomic update per chunk. It may be significant if our computation is very small such as `input.par().sum()`. Otherwise, cost of atomic update could be negligible.\n* false sharing: This is relevant only if we are writing results. For instance, when we are one-to-one mapping an input and collecting the results such as `input.par().map(|x| x.to_string()).collect()`, or if are writing with mut references such as `input.par().for_each(|x| *x += 1)`. Here, the performance might suffer from false sharing when the `chunk size × size of output item` is not large enough. You may also see [false sharing](https://docs.rs/orx-concurrent-bag/latest/orx_concurrent_bag/#false-sharing) section for `ConcurrentBag`.\n\nIn either case, when computation on each item is sufficiently long, parallelization overhead is negligible. Here, we want to make sure that we do not have heterogeneity cost. Therefore, a safe chunk size choice would be one, `par.chunk_size(1)`.\n\nOtherwise, our choice depends on the use case. As a rule of thumb, we want a chunk size that is **just large enough** to mitigate the parallelization overhead but not larger so that we do not suffer from heterogeneity.\n\nThe default configuration `par.chunk_size(ChunkSize::Auto)` or `par.chunk_size(0)` uses a heuristic to solve this tradeoff. A difficult case for the current version is when the tasks are significantly heterogeneous (see the [discussion](https://github.com/orxfun/orx-parallel/discussions/26) for future improvements).\n\nAs described above, the **best way to deal with heterogeneity** is to have `par.chunk_size(1)`. You may of course test larger chunk sizes to optimize the computation for your data.\n\n\n## Runner: Pools and Executors\n\nThis crate defines parallel computation by combining two basic components.\n\n**Pulling inputs**\n* Pulling inputs in parallel is achieved through [`ConcurrentIter`](https://crates.io/crates/orx-concurrent-iter). Concurrent iterator implementations are lock-free, efficient and support pull-by-chunks optimization to reduce the parallelization overhead. A thread can pull any number of inputs from the concurrent iterator every time it becomes idle. This provides the means to dynamically decide on the chunk sizes.\n* Furthermore, this allows to reduce the overhead of defining creating tasks. To illustrate, provided that the computation will be handled by `n` threads, a closure holding a reference to the input concurrent iterator is defined to represent the computation. This same closure is passed to `n` threads; i.e., `n` spawn calls are made. Each of these threads keep pulling elements from the input until the computation is completed, without requiring to define another task.\n\n**Writing outputs**\n* When we collect results, writing outputs is handled using lock-free containers such as [`ConcurrentBag`](https://crates.io/crates/orx-concurrent-bag) and [`ConcurrentOrderedBag`](https://crates.io/crates/orx-concurrent-ordered-bag) which aim for high performance collection of results.\n\nThere are two main decisions to be taken while executing these components:\n* how many threads do we use?\n* what is the chunk size; i.e., how many input items does a thread pull each time?\n\nA [`ParallelRunner`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParallelRunner) is a combination of a `ParThreadPool` and a `ParallelExecutor` that are responsible for these decisions, respectively.\n\n### ParThreadPool: number of threads\n\n[`ParThreadPool`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParThreadPool) trait generalizes thread pools that can be used for parallel computations. This allows the parallel computation to be generic over thread pools.\n\nWhen not explicitly set, [`DefaultPool`](https://docs.rs/orx-parallel/latest/orx_parallel/type.DefaultPool) is used:\n* When **std** feature is enabled, default pool is the [`StdDefaultPool`](https://docs.rs/orx-parallel/latest/orx_parallel/struct.StdDefaultPool). In other words, all available native threads can be used by the parallel computation. This number can globally bounded by \"ORX_PARALLEL_MAX_NUM_THREADS\" environment variable when set.\n* When working in a **no-std** environment, default pool is the [`SequentialPool`](https://docs.rs/orx-parallel/latest/orx_parallel/struct.SequentialPool). As the name suggests, this pool executes the parallel computation sequentially on the main thread. It can be considered as a placeholder to be overwritten by `with_pool` or `with_runner` methods to achieve parallelism.\n\n*Note that thread pool defines the resource, or upper bound. This upper bound can further be bounded by the [`num_threads`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.num_threads) configuration. Finally, parallel executor might choose not to use all available threads if it decides that the computation is small enough.*\n\nTo overwrite the defaults and explicitly set the thread pool to be used for the computation, [`with_pool`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.with_pool) or [`with_runner`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.with_runner) methods are used.\n\n```rust\nuse orx_parallel::*;\n\nlet inputs: Vec<_> = (0..42).collect();\n\n// uses the DefaultPool\n// assuming \"std\" enabled, StdDefaultPool will be used; i.e., native threads\nlet sum = inputs.par().sum();\n\n// equivalent to:\n#[cfg(feature = \"std\")]\n{\n    let sum2 = inputs.par().with_pool(StdDefaultPool::default()).sum();\n    assert_eq!(sum, sum2);\n}\n\n#[cfg(not(miri))]\n#[cfg(feature = \"scoped_threadpool\")]\n{\n    let mut pool = scoped_threadpool::Pool::new(8);\n    // uses the scoped_threadpool::Pool created with 8 threads\n    let sum2 = inputs.par().with_pool(&mut pool).sum();\n    assert_eq!(sum, sum2);\n}\n\n#[cfg(not(miri))]\n#[cfg(feature = \"rayon-core\")]\n{\n    let pool = rayon_core::ThreadPoolBuilder::new()\n        .num_threads(8)\n        .build()\n        .unwrap();\n    // uses the rayon-core::ThreadPool created with 8 threads\n    let sum2 = inputs.par().with_pool(&pool).sum();\n    assert_eq!(sum, sum2);\n}\n\n#[cfg(not(miri))]\n#[cfg(feature = \"yastl\")]\n{\n    let pool = YastlPool::new(8);\n    // uses the yastl::Pool created with 8 threads\n    let sum2 = inputs.par().with_pool(&pool).sum();\n    assert_eq!(sum, sum2);\n}\n```\n\n`ParThreadPool` implementations of several thread pools are provided in this crate as optional features (see [features](#features) section). Provided that the pool supports scoped computations, it is trivial to implement this trait in most cases (see [implementations](https://github.com/orxfun/orx-parallel/tree/main/src/runner/implementations) for examples).\n\nIn most of the cases, *rayon-core*, *scoped_threadpool* and *scoped_pool* perform better than others, and get close to native threads performance with `StdDefaultPool`.\n\nSince parallel computations are generic over the thread pools, performances can be conveniently compared for specific use cases. Such an example benchmark can be found in [collect_filter_map](https://github.com/orxfun/orx-parallel/blob/main/benches/collect_filter_map.rs) file. To have quick tests, you may also use the example [benchmark_pools](https://github.com/orxfun/orx-parallel/blob/main/examples/benchmark_pools.rs).\n\n### ParallelExecutor: chunk size\n\nOnce thread pool provides the computation resources, it is [`ParallelExecutor`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParallelExecutor)'s task to distribute work to available threads. As mentioned above, all threads receive exactly the same closure. This closure continues to pull elements from the input concurrent iterator and operate on the inputs until all elements are processed.\n\nThe critical decision that parallel executor makes is the chunk size. Depending on the state of the computation, it can dynamically decide on number of elements to pull from the input iterator. The tradeoff it tries to solve is as follows:\n\n* the larger the chunk size,\n  * the smaller the parallelization overhead; but also\n  * the larger the risk of imbalance in cases of heterogeneity.\n\n## Features\n\n* **std**: This is a **no-std** crate while *std* is included as a default feature. Please use `--no-default-features` flag for no-std use cases. **std** feature enables `StdDefaultPool` as the default thread provider which uses native threads.\n* **rayon-core**: This feature enables using `rayon_core::ThreadPool` for parallel computations.\n* **scoped_threadpool**: This feature enables using `scoped_threadpool::Pool`.\n* **scoped-pool**: This feature enables using `scoped-pool::Pool`.\n* **yastl**: This feature enables using `yastl::Pool`.\n* **pond**: This feature enables using `pond::Pool`.\n* **poolite**: This feature enables using `poolite::Pool`.\n\n## Contributing\n\nContributions are welcome! \n\nPlease open an [issue](https://github.com/orxfun/orx-parallel/issues/new) or create a PR,\n\n* if you notice an error,\n* have a question or think something could be improved,\n* have an input collection or generator that needs to be parallelized,\n* want to use a particular thread pool with parallel iterators,\n* having trouble representing a particular parallel computation with parallel iterators,\n* or anything else:)\n\nFinally, feel free to contact [me](mailto:orx.ugur.arikan@gmail.com) if you are interested in optimization of the parallel runner to further improve performance, *by maybe dynamic optimization of chunk size decisions with respect to online collection and analysis of metrics*.\n\n## License\n\nDual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).\n"
  },
  {
    "path": "benches/chain3_collect_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().chain(inputs).chain(inputs).map(map).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .into_par_iter()\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs\n        .into_par()\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs\n        .into_par()\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"chain3_collect_map\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/chain4_collect_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs\n        .iter()\n        .chain(inputs)\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .into_par_iter()\n        .chain(inputs)\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs\n        .into_par()\n        .chain(inputs)\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs\n        .into_par()\n        .chain(inputs)\n        .chain(inputs)\n        .chain(inputs)\n        .map(map)\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"chain4_collect_map\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/chain_collect_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().chain(inputs).map(map).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().chain(inputs).map(map).collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs.into_par().chain(inputs).map(map).collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs.into_par().chain(inputs).map(map).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"chain_collect_map\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &&Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<Output> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .map(|x| to_output(&x))\n        .collect()\n}\n\nfn seq(inputs: &[Output]) -> Vec<&Output> {\n    inputs.iter().filter(filter).collect()\n}\n\nfn rayon(inputs: &[Output]) -> Vec<&Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().filter(filter).collect()\n}\n\nfn orx_into_vec(inputs: &[Output]) -> Vec<&Output> {\n    inputs.into_par().filter(filter).collect()\n}\n\nfn orx_into_split_vec(inputs: &[Output]) -> SplitVec<&Output> {\n    inputs.into_par().filter(filter).collect()\n}\n\n#[allow(dead_code)]\nfn orx_into_vec_with<P: ParThreadPool>(inputs: &[Output], pool: P) -> Vec<&Output> {\n    inputs.into_par().with_pool(pool).filter(filter).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n\n        #[cfg(feature = \"rayon-core\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-vec (rayon-core::ThreadPool)\", n),\n            n,\n            |b, _| {\n                let pool = rayon_core::ThreadPoolBuilder::new()\n                    .num_threads(32)\n                    .build()\n                    .unwrap();\n                assert_eq!(&expected, &orx_into_vec_with(&input, &pool));\n                b.iter(|| orx_into_vec_with(black_box(&input), &pool))\n            },\n        );\n\n        #[cfg(feature = \"scoped-pool\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-vec (scoped-pool::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = scoped_pool::Pool::new(32);\n                assert_eq!(&expected, &orx_into_vec_with(&input, &pool));\n                b.iter(|| orx_into_vec_with(black_box(&input), &pool))\n            },\n        );\n\n        #[cfg(feature = \"scoped_threadpool\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-vec (scoped_threadpool::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = || scoped_threadpool::Pool::new(32);\n                assert_eq!(&expected, &orx_into_vec_with(&input, pool()));\n                b.iter(|| orx_into_vec_with(black_box(&input), pool()))\n            },\n        );\n\n        #[cfg(feature = \"yastl\")]\n        group.bench_with_input(BenchmarkId::new(\"orx-vec (yastl::Pool)\", n), n, |b, _| {\n            let pool = YastlPool::new(32);\n            assert_eq!(&expected, &orx_into_vec_with(&input, &pool));\n            b.iter(|| orx_into_vec_with(black_box(&input), &pool))\n        });\n\n        #[cfg(feature = \"pond\")]\n        group.bench_with_input(BenchmarkId::new(\"orx-vec (pond::Pool)\", n), n, |b, _| {\n            let pool = || PondPool::new_threads_unbounded(32);\n            assert_eq!(&expected, &orx_into_vec_with(&input, pool()));\n            b.iter(|| orx_into_vec_with(black_box(&input), pool()))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_filtermap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn filter_map(idx: &usize) -> Option<Output> {\n    idx.is_multiple_of(3).then(|| to_output(idx))\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().filter_map(filter_map).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().filter_map(filter_map).collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs.into_par().filter_map(filter_map).collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs.into_par().filter_map(filter_map).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_filtermap\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_flatmap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn flat_map(idx: &usize) -> Vec<Output> {\n    (0..4).map(|i| to_output(&(idx + i))).collect::<Vec<_>>()\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().flat_map(flat_map).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().flat_map(flat_map).collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs.into_par().flat_map(flat_map).collect()\n}\n\nfn orx_sorted_into_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs.into_par().flat_map(flat_map).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_flatmap\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_sorted_into_vec(&input));\n            b.iter(|| orx_sorted_into_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_iter_into_par.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::ParallelBridge;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().map(map).filter(filter).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.iter().par_bridge().map(map).filter(filter).collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs\n        .iter()\n        .iter_into_par()\n        .map(map)\n        .filter(filter)\n        .collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs\n        .iter()\n        .iter_into_par()\n        .map(map)\n        .filter(filter)\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_iter_into_par\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            // TODO: for some reason rayon does not return an ordered collection, create an issue\n            // assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_long_chain.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 29;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out1 {\n    name: String,\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out2 {\n    name: String,\n    number: u32,\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out3 {\n    out2: Out2,\n    fib: u32,\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out4 {\n    a: String,\n    b: char,\n    fib: u32,\n}\n\nfn map1(idx: &usize) -> Out1 {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32 % FIB_UPPER_BOUND));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n    Out1 { name }\n}\n\nfn filter1(output: &Out1) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn map2(input: Out1) -> Out2 {\n    let number = (FIB_UPPER_BOUND + input.name.len() as u32).saturating_sub(10);\n    let number = fibonacci(&(number & FIB_UPPER_BOUND));\n    Out2 {\n        name: number.to_string(),\n        number,\n    }\n}\n\nfn filter2(output: &Out2) -> bool {\n    output.number.is_multiple_of(2) || output.name.contains('0')\n}\n\nfn map3(input: Out2) -> Out3 {\n    let fib = fibonacci(&input.number);\n    Out3 { out2: input, fib }\n}\n\nfn map4(input: Out3) -> Out4 {\n    let a = format!(\"{}!\", input.out2.name);\n    let b = input.out2.name.chars().next().unwrap();\n    let fib = fibonacci(&((input.out2.number * 7) % FIB_UPPER_BOUND));\n    Out4 { a, b, fib }\n}\n\nfn filter4(output: &Out4) -> bool {\n    output.a.len() == 5 || output.b == 'x' || output.fib % 2 == 1\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Out4> {\n    inputs\n        .iter()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Out4> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .into_par_iter()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Out4> {\n    inputs\n        .into_par()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Out4> {\n    inputs\n        .into_par()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_long_chain\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().map(map).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs.into_par().map(map).collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs.into_par().map(map).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_map\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Vec<Output> {\n    inputs.iter().map(map).filter(filter).collect()\n}\n\nfn rayon(inputs: &[usize]) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).filter(filter).collect()\n}\n\nfn orx_into_vec(inputs: &[usize]) -> Vec<Output> {\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\nfn orx_into_split_vec(inputs: &[usize]) -> SplitVec<Output> {\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\n#[allow(dead_code)]\nfn orx_into_vec_with<P: ParThreadPool>(inputs: &[usize], pool: P) -> Vec<Output> {\n    inputs\n        .into_par()\n        .with_pool(pool)\n        .map(map)\n        .filter(filter)\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n\n        #[cfg(feature = \"rayon-core\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-into-vec (rayon-core::ThreadPool)\", n),\n            n,\n            |b, _| {\n                let pool = rayon_core::ThreadPoolBuilder::new()\n                    .num_threads(32)\n                    .build()\n                    .unwrap();\n                assert_eq!(&expected, &orx_into_vec_with(&input, &pool));\n                b.iter(|| orx_into_vec_with(black_box(&input), &pool))\n            },\n        );\n\n        #[cfg(feature = \"scoped-pool\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-into-vec (scoped-pool::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = scoped_pool::Pool::new(32);\n                assert_eq!(&expected, &orx_into_vec_with(&input, &pool));\n                b.iter(|| orx_into_vec_with(black_box(&input), &pool))\n            },\n        );\n\n        #[cfg(feature = \"scoped_threadpool\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-into-vec (scoped_threadpool::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = || scoped_threadpool::Pool::new(32);\n                assert_eq!(&expected, &orx_into_vec_with(&input, pool()));\n                b.iter(|| orx_into_vec_with(black_box(&input), pool()))\n            },\n        );\n\n        #[cfg(feature = \"yastl\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-into-vec (yastl::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = YastlPool::new(32);\n                assert_eq!(&expected, &orx_into_vec_with(&input, &pool));\n                b.iter(|| orx_into_vec_with(black_box(&input), &pool))\n            },\n        );\n\n        #[cfg(feature = \"pond\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx-into-vec (pond::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = || PondPool::new_threads_unbounded(32);\n                assert_eq!(&expected, &orx_into_vec_with(&input, pool()));\n                b.iter(|| orx_into_vec_with(black_box(&input), pool()))\n            },\n        );\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/collect_map_filter_hash_set.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::collections::HashSet;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> HashSet<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &HashSet<usize>) -> Vec<Output> {\n    inputs.iter().map(map).filter(filter).collect()\n}\n\nfn rayon(inputs: &HashSet<usize>) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).filter(filter).collect()\n}\n\nfn orx_through_vec(inputs: &HashSet<usize>) -> Vec<Output> {\n    let inputs: Vec<_> = inputs.iter().collect();\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\nfn orx_through_iter(inputs: &HashSet<usize>) -> Vec<Output> {\n    inputs\n        .iter()\n        .iter_into_par()\n        .map(map)\n        .filter(filter)\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_map_filter_hash_set\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-through-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_through_vec(&input));\n            b.iter(|| orx_through_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-through-iter\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_through_iter(&input));\n            b.iter(|| orx_through_iter(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/count_filtermap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn filter_map(idx: &usize) -> Option<Output> {\n    idx.is_multiple_of(3).then(|| to_output(idx))\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> usize {\n    inputs.iter().filter_map(filter_map).count()\n}\n\nfn rayon(inputs: &[usize]) -> usize {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().filter_map(filter_map).count()\n}\n\nfn orx(inputs: &[usize]) -> usize {\n    inputs.into_par().filter_map(filter_map).count()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"count_filtermap\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/count_flatmap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = true;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn flat_map(idx: &usize) -> Vec<Output> {\n    (0..4).map(|i| to_output(&(idx + i))).collect::<Vec<_>>()\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> usize {\n    inputs.iter().flat_map(flat_map).count()\n}\n\nfn rayon(inputs: &[usize]) -> usize {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().flat_map(flat_map).count()\n}\n\nfn orx(inputs: &[usize]) -> usize {\n    inputs.into_par().flat_map(flat_map).count()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"count_flatmap\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/count_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> usize {\n    inputs.iter().map(map).count()\n}\n\nfn rayon(inputs: &[usize]) -> usize {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).count()\n}\n\nfn orx(inputs: &[usize]) -> usize {\n    inputs.into_par().map(map).count()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"count_map\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/count_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = true;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> usize {\n    inputs.iter().map(map).filter(filter).count()\n}\n\nfn rayon(inputs: &[usize]) -> usize {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).filter(filter).count()\n}\n\nfn orx(inputs: &[usize]) -> usize {\n    inputs.into_par().map(map).filter(filter).count()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"count_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/drain_vec_collect_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: usize) -> Output {\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(input: &mut Vec<usize>) -> Vec<Output> {\n    input.drain(..).map(map).filter(filter).collect()\n}\n\nfn rayon(input: &mut Vec<usize>) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    rayon::iter::ParallelDrainRange::par_drain(input, ..)\n        .map(map)\n        .filter(filter)\n        .collect()\n}\n\nfn orx_into_vec(input: &mut Vec<usize>) -> Vec<Output> {\n    input.par_drain(..).map(map).filter(filter).collect()\n}\n\nfn orx_into_split_vec(input: &mut Vec<usize>) -> SplitVec<Output> {\n    input.par_drain(..).map(map).filter(filter).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"drain_vec_collect_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&mut input.clone());\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&mut input.clone()));\n            b.iter(|| seq(black_box(&mut input.clone())))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&mut input.clone()));\n            b.iter(|| rayon(black_box(&mut input.clone())))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&mut input.clone()));\n            b.iter(|| orx_into_vec(black_box(&mut input.clone())))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&mut input.clone()));\n            b.iter(|| orx_into_split_vec(black_box(&mut input.clone())))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/find.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Output { id, name, numbers }\n}\n\nfn get_find(n: usize) -> impl Fn(&Output) -> bool {\n    move |a: &Output| a.id.parse::<usize>().unwrap() == n\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<Output> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .map(|x| to_output(&x))\n        .collect()\n}\n\nfn seq(inputs: &[Output], find: impl Fn(&Output) -> bool) -> Option<&Output> {\n    inputs.iter().find(|x| find(x))\n}\n\nfn rayon(inputs: &[Output], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<&Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().find_first(|x| find(x))\n}\n\nfn orx(inputs: &[Output], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<&Output> {\n    inputs.into_par().find(|x| find(x))\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"find\");\n\n    for n_when in &treatments {\n        let find = get_find(*n_when);\n        let input = inputs(N);\n        let expected = seq(&input, &find);\n\n        let n_when = match *n_when {\n            N_EARLY => \"find-early\",\n            N_MIDDLE => \"find-in-the-middle\",\n            N_LATE => \"find-late\",\n            N_NEVER => \"find-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, &find));\n            b.iter(|| seq(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, &find));\n            b.iter(|| rayon(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, &find));\n            b.iter(|| orx(black_box(&input), &find))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/find_any.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Output { id, name, numbers }\n}\n\nfn get_find(n: usize) -> impl Fn(&Output) -> bool {\n    move |a: &Output| a.id.parse::<usize>().unwrap() == n\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<Output> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .map(|x| to_output(&x))\n        .collect()\n}\n\nfn seq(inputs: &[Output], find: impl Fn(&Output) -> bool) -> Option<&Output> {\n    inputs.iter().find(|x| find(x))\n}\n\nfn rayon(inputs: &[Output], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<&Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().find_any(|x| find(x))\n}\n\nfn orx(inputs: &[Output], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<&Output> {\n    inputs\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .find(|x| find(x))\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"find_any\");\n\n    for n_when in &treatments {\n        let find = get_find(*n_when);\n        let input = inputs(N);\n        let expected = seq(&input, &find);\n\n        let n_when = match *n_when {\n            N_EARLY => \"find-early\",\n            N_MIDDLE => \"find-in-the-middle\",\n            N_LATE => \"find-late\",\n            N_NEVER => \"find-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, &find));\n            b.iter(|| seq(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, &find));\n            b.iter(|| rayon(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, &find));\n            b.iter(|| orx(black_box(&input), &find))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/find_flatmap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn flat_map(idx: &usize) -> Vec<Output> {\n    (0..4).map(|i| to_output(&(idx + i))).collect::<Vec<_>>()\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Output { id, name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn get_find(n: usize) -> impl Fn(&Output) -> bool {\n    move |a: &Output| a.id.parse::<usize>().unwrap() == n\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    inputs.iter().flat_map(flat_map).find(find)\n}\n\nfn rayon(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().flat_map(flat_map).find_first(find)\n}\n\nfn orx(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    inputs.into_par().flat_map(flat_map).find(&find)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"find_flatmap\");\n\n    for n_when in &treatments {\n        let find = get_find(*n_when);\n        let input = inputs(N);\n        let expected = seq(&input, &find);\n\n        let n_when = match *n_when {\n            N_EARLY => \"find-early\",\n            N_MIDDLE => \"find-in-the-middle\",\n            N_LATE => \"find-late\",\n            N_NEVER => \"find-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, &find));\n            b.iter(|| seq(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, &find));\n            b.iter(|| rayon(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, &find));\n            b.iter(|| orx(black_box(&input), &find))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/find_iter_into_par.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::ParallelBridge;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Output { id, name, numbers }\n}\n\nfn get_find(n: usize) -> impl Fn(&Output) -> bool {\n    move |a: &Output| a.id.parse::<usize>().unwrap() == n\n}\n\nfn filter(a: &Output) -> bool {\n    !a.name.ends_with('1')\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize], find: impl Fn(&Output) -> bool) -> Option<Output> {\n    inputs.iter().map(map).filter(filter).find(find)\n}\n\nfn rayon(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .iter()\n        .par_bridge()\n        .map(map)\n        .filter(filter)\n        .find_first(find)\n}\n\nfn orx(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    inputs\n        .iter()\n        .iter_into_par()\n        .map(map)\n        .filter(filter)\n        .find(&find)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"find_iter_into_par\");\n\n    for n_when in &treatments {\n        let find = get_find(*n_when);\n        let input = inputs(N);\n        let expected = seq(&input, &find);\n\n        let n_when = match *n_when {\n            N_EARLY => \"find-early\",\n            N_MIDDLE => \"find-in-the-middle\",\n            N_LATE => \"find-late\",\n            N_NEVER => \"find-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, &find));\n            b.iter(|| seq(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, &find));\n            b.iter(|| rayon(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, &find));\n            b.iter(|| orx(black_box(&input), &find))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/find_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Output { id, name, numbers }\n}\n\nfn get_find(n: usize) -> impl Fn(&Output) -> bool {\n    move |a: &Output| a.id.parse::<usize>().unwrap() == n\n}\n\nfn filter(a: &Output) -> bool {\n    !a.name.ends_with('1')\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize], find: impl Fn(&Output) -> bool) -> Option<Output> {\n    inputs.iter().map(map).filter(filter).find(find)\n}\n\nfn rayon(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .into_par_iter()\n        .map(map)\n        .filter(filter)\n        .find_first(find)\n}\n\nfn orx(inputs: &[usize], find: impl Fn(&Output) -> bool + Send + Sync) -> Option<Output> {\n    inputs.into_par().map(map).filter(filter).find(&find)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"find_map_filter\");\n\n    for n_when in &treatments {\n        let find = get_find(*n_when);\n        let input = inputs(N);\n        let expected = seq(&input, &find);\n\n        let n_when = match *n_when {\n            N_EARLY => \"find-early\",\n            N_MIDDLE => \"find-in-the-middle\",\n            N_LATE => \"find-late\",\n            N_NEVER => \"find-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, &find));\n            b.iter(|| seq(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, &find));\n            b.iter(|| rayon(black_box(&input), &find))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, &find));\n            b.iter(|| orx(black_box(&input), &find))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/mut_for_each_iter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse std::collections::HashMap;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]\nstruct Data {\n    name: String,\n    number: usize,\n}\n\nfn to_output(idx: usize) -> Data {\n    let name = idx.to_string();\n    let number = idx;\n    Data { name, number }\n}\n\nfn inputs(len: usize) -> HashMap<usize, Data> {\n    (0..len).map(|i| (i, to_output(i))).collect()\n}\n\nfn fibonacci(n: usize) -> usize {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn filter(data: &&mut Data) -> bool {\n    !data.name.starts_with('3')\n}\n\nfn update(data: &mut Data) {\n    for _ in 0..50 {\n        let increment = fibonacci(data.number % 100) % 10;\n        data.number += increment\n    }\n}\n\nfn seq<'a>(inputs: impl Iterator<Item = &'a mut Data>) {\n    inputs.filter(filter).for_each(update);\n}\n\nfn rayon<'a>(inputs: impl Iterator<Item = &'a mut Data> + Send) {\n    use rayon::iter::{ParallelBridge, ParallelIterator};\n    inputs.par_bridge().filter(filter).for_each(update);\n}\n\nfn orx<'a>(inputs: impl Iterator<Item = &'a mut Data>) {\n    use orx_parallel::*;\n    inputs.iter_into_par().filter(filter).for_each(update);\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"mut_for_each_iter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let mut expected = input.clone();\n        seq(expected.values_mut());\n        let expected = expected;\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            let mut input = input.clone();\n            seq(input.values_mut());\n            assert_eq!(expected, input);\n            b.iter(|| seq(input.values_mut()))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            let mut input = input.clone();\n            rayon(input.values_mut());\n            assert_eq!(expected, input);\n            b.iter(|| rayon(input.values_mut()))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            let mut input = input.clone();\n            orx(input.values_mut());\n            assert_eq!(expected, input);\n            b.iter(|| orx(input.values_mut()))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/mut_for_each_slice.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse std::hint::black_box;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]\nstruct Data {\n    name: String,\n    number: usize,\n}\n\nfn to_output(idx: usize) -> Data {\n    let name = idx.to_string();\n    let number = idx;\n    Data { name, number }\n}\n\nfn inputs(len: usize) -> Vec<Data> {\n    (0..len).map(to_output).collect()\n}\n\nfn fibonacci(n: usize) -> usize {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn filter(data: &&mut Data) -> bool {\n    !data.name.starts_with('3')\n}\n\nfn update(data: &mut Data) {\n    for _ in 0..50 {\n        let increment = fibonacci(data.number % 100) % 10;\n        data.number += increment\n    }\n}\n\nfn seq(inputs: &mut [Data]) {\n    inputs.iter_mut().filter(filter).for_each(update);\n}\n\nfn rayon(inputs: &mut [Data]) {\n    use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};\n    inputs.par_iter_mut().filter(filter).for_each(update);\n}\n\nfn orx(inputs: &mut [Data]) {\n    use orx_parallel::*;\n    inputs.into_par().filter(filter).for_each(update);\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"mut_for_each_slice\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let mut expected = input.clone();\n        seq(&mut expected);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            let mut input = input.clone();\n            seq(&mut input);\n            assert_eq!(expected, input);\n            b.iter(|| seq(black_box(&mut input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            let mut input = input.clone();\n            seq(&mut input);\n            assert_eq!(expected, input);\n            b.iter(|| rayon(black_box(&mut input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            let mut input = input.clone();\n            seq(&mut input);\n            assert_eq!(expected, input);\n            b.iter(|| orx(black_box(&mut input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/rec_iter_map_collect.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_concurrent_recursive_iter::Queue;\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse std::hint::black_box;\n\nfn fibonacci(n: u64, work: usize) -> u64 {\n    (7..(work + 7))\n        .map(|j| {\n            let n = black_box((n + j as u64) % 100);\n            let mut a = 0;\n            let mut b = 1;\n            for _ in 0..n {\n                let c = a + b;\n                a = b;\n                b = c;\n            }\n            a\n        })\n        .sum()\n}\n\nstruct Node {\n    value: Vec<u64>,\n    children: Vec<Node>,\n}\n\nimpl Node {\n    fn new(mut n: u32, rng: &mut impl Rng) -> Self {\n        let mut children = Vec::new();\n        if n < 5 {\n            for _ in 0..n {\n                children.push(Node::new(0, rng));\n            }\n        } else {\n            while n > 0 {\n                let n2 = rng.random_range(0..=n);\n                children.push(Node::new(n2, rng));\n                n -= n2;\n            }\n        }\n        Self {\n            value: (0..rng.random_range(1..500))\n                .map(|_| rng.random_range(0..40))\n                .collect(),\n            children,\n        }\n    }\n\n    fn seq_num_nodes(&self) -> usize {\n        1 + self\n            .children\n            .iter()\n            .map(|node| node.seq_num_nodes())\n            .sum::<usize>()\n    }\n\n    fn seq(&self, work: usize, numbers: &mut Vec<u64>) {\n        numbers.extend(self.value.iter().map(|x| fibonacci(*x, work)));\n        for c in &self.children {\n            c.seq(work, numbers);\n        }\n    }\n}\n\n// alternatives\n\nfn seq(roots: &[Node], work: usize) -> Vec<u64> {\n    let mut result = vec![];\n    for root in roots {\n        root.seq(work, &mut result);\n    }\n    result\n}\n\nfn orx_lazy_unknown_chunk1024(roots: &[Node], work: usize) -> SplitVec<u64> {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec(extend)\n        .chunk_size(1024)\n        .flat_map(|x| x.value.iter().map(|x| fibonacci(*x, work)))\n        .collect()\n}\n\nfn orx_lazy_exact(roots: &[Node], work: usize, num_nodes: usize) -> SplitVec<u64> {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec_exact(extend, num_nodes)\n        .flat_map(|x| x.value.iter().map(|x| fibonacci(*x, work)))\n        .collect()\n}\n\nfn orx_linearized(roots: &[Node], work: usize) -> SplitVec<u64> {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec(extend)\n        .linearize()\n        .flat_map(|x| x.value.iter().map(|x| fibonacci(*x, work)))\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [1, 10, 25];\n    let mut group = c.benchmark_group(\"rec_iter_map_collect\");\n    let mut rng = ChaCha8Rng::seed_from_u64(42);\n    let roots = vec![\n        Node::new(5000, &mut rng),\n        Node::new(2000, &mut rng),\n        Node::new(4000, &mut rng),\n    ];\n\n    let num_nodes: usize = roots.iter().map(|x| x.seq_num_nodes()).sum();\n\n    for work in &treatments {\n        let mut expected = seq(&roots, *work);\n        expected.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", work), work, |b, _| {\n            let mut result = seq(&roots, *work);\n            result.sort();\n            assert_eq!(&expected, &result);\n            b.iter(|| seq(&roots, *work))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx_lazy_exact\", work), work, |b, _| {\n            let mut result = orx_lazy_exact(&roots, *work, num_nodes).to_vec();\n            result.sort();\n            assert_eq!(&expected, &result);\n            b.iter(|| orx_lazy_exact(&roots, *work, num_nodes))\n        });\n\n        group.bench_with_input(\n            BenchmarkId::new(\"orx_lazy_unknown_chunk1024\", work),\n            work,\n            |b, _| {\n                let mut result = orx_lazy_unknown_chunk1024(&roots, *work).to_vec();\n                result.sort();\n                assert_eq!(&expected, &result);\n                b.iter(|| orx_lazy_unknown_chunk1024(&roots, *work))\n            },\n        );\n\n        group.bench_with_input(BenchmarkId::new(\"orx_linearized\", work), work, |b, _| {\n            let mut result = orx_linearized(&roots, *work).to_vec();\n            result.sort();\n            assert_eq!(&expected, &result);\n            b.iter(|| orx_linearized(&roots, *work))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/rec_iter_map_sum.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_concurrent_recursive_iter::Queue;\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse std::{\n    hint::black_box,\n    sync::atomic::{AtomicU64, Ordering},\n};\n\nfn fibonacci(n: u64, work: usize) -> u64 {\n    (7..(work + 7))\n        .map(|j| {\n            let n = black_box((n + j as u64) % 100);\n            let mut a = 0;\n            let mut b = 1;\n            for _ in 0..n {\n                let c = a + b;\n                a = b;\n                b = c;\n            }\n            a\n        })\n        .sum()\n}\n\nstruct Node {\n    value: Vec<u64>,\n    children: Vec<Node>,\n}\n\nimpl Node {\n    fn new(mut n: u32, rng: &mut impl Rng) -> Self {\n        let mut children = Vec::new();\n        if n < 5 {\n            for _ in 0..n {\n                children.push(Node::new(0, rng));\n            }\n        } else {\n            while n > 0 {\n                let n2 = rng.random_range(0..=n);\n                children.push(Node::new(n2, rng));\n                n -= n2;\n            }\n        }\n        Self {\n            value: (0..rng.random_range(1..500))\n                .map(|_| rng.random_range(0..40))\n                .collect(),\n            children,\n        }\n    }\n\n    fn seq_num_nodes(&self) -> usize {\n        1 + self\n            .children\n            .iter()\n            .map(|node| node.seq_num_nodes())\n            .sum::<usize>()\n    }\n\n    fn seq_sum_fib(&self, work: usize) -> u64 {\n        self.value.iter().map(|x| fibonacci(*x, work)).sum::<u64>()\n            + self\n                .children\n                .iter()\n                .map(|x| x.seq_sum_fib(work))\n                .sum::<u64>()\n    }\n}\n\n// alternatives\n\nfn seq(roots: &[Node], work: usize) -> u64 {\n    roots.iter().map(|x| x.seq_sum_fib(work)).sum()\n}\n\nfn rayon(roots: &[Node], work: usize) -> u64 {\n    use rayon::iter::*;\n    fn process_node<'scope>(\n        work: usize,\n        sum: &'scope AtomicU64,\n        node: &'scope Node,\n        s: &rayon::Scope<'scope>,\n    ) {\n        for child in &node.children {\n            s.spawn(move |s| {\n                process_node(work, sum, child, s);\n            });\n        }\n        let val = node.value.par_iter().map(|x| fibonacci(*x, work)).sum();\n        sum.fetch_add(val, Ordering::Relaxed);\n    }\n\n    let sum = AtomicU64::new(0);\n    rayon::in_place_scope(|s| {\n        for root in roots {\n            process_node(work, &sum, root, s);\n        }\n    });\n    sum.into_inner()\n}\n\nfn orx_lazy_unknown_chunk1024(roots: &[Node], work: usize) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec(extend)\n        .chunk_size(1024)\n        .map(|x| x.value.iter().map(|x| fibonacci(*x, work)).sum::<u64>())\n        .sum()\n}\n\nfn orx_lazy_exact(roots: &[Node], work: usize, num_nodes: usize) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec_exact(extend, num_nodes)\n        .map(|x| x.value.iter().map(|x| fibonacci(*x, work)).sum::<u64>())\n        .sum()\n}\n\nfn orx_lazy_exact_flat_map(roots: &[Node], work: usize, num_nodes: usize) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec_exact(extend, num_nodes)\n        .flat_map(|x| x.value.iter().map(|x| fibonacci(*x, work)))\n        .sum()\n}\n\nfn orx_linearized(roots: &[Node], work: usize) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    roots\n        .into_par_rec(extend)\n        .linearize()\n        .map(|x| x.value.iter().map(|x| fibonacci(*x, work)).sum::<u64>())\n        .sum()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [1, 10, 25];\n    let mut group = c.benchmark_group(\"rec_iter_map_sum\");\n    let mut rng = ChaCha8Rng::seed_from_u64(42);\n    let roots = vec![\n        Node::new(5000, &mut rng),\n        Node::new(2000, &mut rng),\n        Node::new(4000, &mut rng),\n    ];\n\n    let num_nodes: usize = roots.iter().map(|x| x.seq_num_nodes()).sum();\n\n    for work in &treatments {\n        let expected = seq(&roots, *work);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", work), work, |b, _| {\n            assert_eq!(&expected, &seq(&roots, *work));\n            b.iter(|| seq(&roots, *work))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", work), work, |b, _| {\n            assert_eq!(&expected, &rayon(&roots, *work));\n            b.iter(|| rayon(&roots, *work))\n        });\n\n        group.bench_with_input(\n            BenchmarkId::new(\"orx_lazy_unknown_chunk1024\", work),\n            work,\n            |b, _| {\n                assert_eq!(&expected, &orx_lazy_unknown_chunk1024(&roots, *work));\n                b.iter(|| orx_lazy_unknown_chunk1024(&roots, *work))\n            },\n        );\n\n        group.bench_with_input(BenchmarkId::new(\"orx_lazy_exact\", work), work, |b, _| {\n            assert_eq!(&expected, &orx_lazy_exact(&roots, *work, num_nodes));\n            b.iter(|| orx_lazy_exact(&roots, *work, num_nodes))\n        });\n\n        group.bench_with_input(\n            BenchmarkId::new(\"orx_lazy_exact_flat_map\", work),\n            work,\n            |b, _| {\n                assert_eq!(\n                    &expected,\n                    &orx_lazy_exact_flat_map(&roots, *work, num_nodes)\n                );\n                b.iter(|| orx_lazy_exact_flat_map(&roots, *work, num_nodes))\n            },\n        );\n\n        group.bench_with_input(BenchmarkId::new(\"orx_linearized\", work), work, |b, _| {\n            assert_eq!(&expected, &orx_linearized(&roots, *work));\n            b.iter(|| orx_linearized(&roots, *work))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/reduce.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn reduce<'a>(a: &'a Output, b: &'a Output) -> &'a Output {\n    match a.name < b.name {\n        true => a,\n        false => b,\n    }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<Output> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .map(|x| to_output(&x))\n        .collect()\n}\n\nfn seq(inputs: &[Output]) -> Option<&Output> {\n    inputs.iter().reduce(reduce)\n}\n\nfn rayon(inputs: &[Output]) -> Option<&Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().reduce_with(reduce)\n}\n\nfn orx(inputs: &[Output]) -> Option<&Output> {\n    inputs.into_par().reduce(reduce)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"reduce\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/reduce_iter_into_par.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::ParallelBridge;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(a: &Output) -> bool {\n    !a.name.ends_with('1')\n}\n\nfn reduce(a: Output, b: Output) -> Output {\n    match a.name < b.name {\n        true => a,\n        false => b,\n    }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Option<Output> {\n    inputs.iter().map(map).filter(filter).reduce(reduce)\n}\n\nfn rayon(inputs: &[usize]) -> Option<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .iter()\n        .map(map)\n        .filter(filter)\n        .par_bridge()\n        .reduce_with(reduce)\n}\n\nfn orx(inputs: &[usize]) -> Option<Output> {\n    inputs\n        .iter()\n        .iter_into_par()\n        .map(map)\n        .filter(filter)\n        .reduce(reduce)\n}\n\n#[allow(dead_code)]\nfn orx_with<P: ParThreadPool>(inputs: &[usize], pool: P) -> Option<Output> {\n    inputs\n        .iter()\n        .iter_into_par()\n        .with_pool(pool)\n        .map(map)\n        .filter(filter)\n        .reduce(reduce)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"reduce_iter_into_par\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n\n        #[cfg(feature = \"rayon-core\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx (rayon-core::ThreadPool)\", n),\n            n,\n            |b, _| {\n                let pool = rayon_core::ThreadPoolBuilder::new()\n                    .num_threads(32)\n                    .build()\n                    .unwrap();\n                assert_eq!(&expected, &orx_with(&input, &pool));\n                b.iter(|| orx_with(black_box(&input), &pool))\n            },\n        );\n\n        #[cfg(feature = \"scoped-pool\")]\n        group.bench_with_input(BenchmarkId::new(\"orx (scoped-pool::Pool)\", n), n, |b, _| {\n            let pool = scoped_pool::Pool::new(32);\n            assert_eq!(&expected, &orx_with(&input, &pool));\n            b.iter(|| orx_with(black_box(&input), &pool))\n        });\n\n        #[cfg(feature = \"scoped_threadpool\")]\n        group.bench_with_input(\n            BenchmarkId::new(\"orx (scoped_threadpool::Pool)\", n),\n            n,\n            |b, _| {\n                let pool = || scoped_threadpool::Pool::new(32);\n                assert_eq!(&expected, &orx_with(&input, pool()));\n                b.iter(|| orx_with(black_box(&input), pool()))\n            },\n        );\n\n        #[cfg(feature = \"yastl\")]\n        group.bench_with_input(BenchmarkId::new(\"orx (yastl::Pool)\", n), n, |b, _| {\n            let pool = YastlPool::new(32);\n            assert_eq!(&expected, &orx_with(&input, &pool));\n            b.iter(|| orx_with(black_box(&input), &pool))\n        });\n\n        #[cfg(feature = \"pond\")]\n        group.bench_with_input(BenchmarkId::new(\"orx (pond::Pool)\", n), n, |b, _| {\n            let pool = || PondPool::new_threads_unbounded(32);\n            assert_eq!(&expected, &orx_with(&input, pool()));\n            b.iter(|| orx_with(black_box(&input), pool()))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/reduce_long_chain.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 29;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out1 {\n    name: String,\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out2 {\n    name: String,\n    number: u32,\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out3 {\n    out2: Out2,\n    fib: u32,\n}\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Out4 {\n    a: String,\n    b: char,\n    fib: u32,\n}\n\nfn map1(idx: &usize) -> Out1 {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32 % FIB_UPPER_BOUND));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n    Out1 { name }\n}\n\nfn filter1(output: &Out1) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn map2(input: Out1) -> Out2 {\n    let number = (FIB_UPPER_BOUND + input.name.len() as u32).saturating_sub(10);\n    let number = fibonacci(&(number & FIB_UPPER_BOUND));\n    Out2 {\n        name: number.to_string(),\n        number,\n    }\n}\n\nfn filter2(output: &Out2) -> bool {\n    output.number.is_multiple_of(2) || output.name.contains('0')\n}\n\nfn map3(input: Out2) -> Out3 {\n    let fib = fibonacci(&input.number);\n    Out3 { out2: input, fib }\n}\n\nfn map4(input: Out3) -> Out4 {\n    let a = format!(\"{}!\", input.out2.name);\n    let b = input.out2.name.chars().next().unwrap();\n    let fib = fibonacci(&((input.out2.number * 7) % FIB_UPPER_BOUND));\n    Out4 { a, b, fib }\n}\n\nfn filter4(output: &Out4) -> bool {\n    output.a.len() == 5 || output.b == 'x' || output.fib % 2 == 1\n}\n\nfn reduce(x: Out4, y: Out4) -> Out4 {\n    let a = match x.fib.is_multiple_of(2) {\n        true => x.a,\n        false => y.a,\n    };\n    let b = match y.fib.is_multiple_of(2) {\n        true => x.b,\n        false => y.b,\n    };\n    let fib = x.fib + y.fib;\n    Out4 { a, b, fib }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Option<Out4> {\n    inputs\n        .iter()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .reduce(reduce)\n}\n\nfn rayon(inputs: &[usize]) -> Option<Out4> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .into_par_iter()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .reduce_with(reduce)\n}\n\nfn orx(inputs: &[usize]) -> Option<Out4> {\n    inputs\n        .into_par()\n        .map(map1)\n        .filter(filter1)\n        .map(map2)\n        .filter(filter2)\n        .map(map3)\n        .map(map4)\n        .filter(filter4)\n        .reduce(reduce)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"collect_long_chain\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/reduce_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn reduce(a: Output, b: Output) -> Output {\n    match a.name < b.name {\n        true => a,\n        false => b,\n    }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Option<Output> {\n    inputs.iter().map(map).reduce(reduce)\n}\n\nfn rayon(inputs: &[usize]) -> Option<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).reduce_with(reduce)\n}\n\nfn orx(inputs: &[usize]) -> Option<Output> {\n    inputs.into_par().map(map).reduce(reduce)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"reduce_map\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/reduce_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(a: &Output) -> bool {\n    !a.name.ends_with('1')\n}\n\nfn reduce(a: Output, b: Output) -> Output {\n    match a.name < b.name {\n        true => a,\n        false => b,\n    }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> Option<Output> {\n    inputs.iter().map(map).filter(filter).reduce(reduce)\n}\n\nfn rayon(inputs: &[usize]) -> Option<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs\n        .into_par_iter()\n        .map(map)\n        .filter(filter)\n        .reduce_with(reduce)\n}\n\nfn orx(inputs: &[usize]) -> Option<Output> {\n    inputs.into_par().map(map).filter(filter).reduce(reduce)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"reduce_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/result_collect_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse std::hint::black_box;\nuse std::num::ParseIntError;\n\ntype Err = ParseIntError;\n\nconst TEST_LARGE_OUTPUT: bool = false;\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Input {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn to_input(idx: &usize) -> Input {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Input { id, name, numbers }\n}\n\nfn to_bad_input() -> Input {\n    Input {\n        id: \"xyz\".to_string(),\n        name: \"xyz\".to_string(),\n        numbers: Default::default(),\n    }\n}\n\nfn map_input_to_result(input: &Input) -> Result<String, Err> {\n    match input.id.parse::<usize>() {\n        Ok(_) => Ok(input.id.clone()),\n        Err(e) => Err(e),\n    }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize, idx_error: usize) -> Vec<Input> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|i| match i == idx_error {\n            true => to_bad_input(),\n            false => {\n                let x = rng.random_range(0..FIB_UPPER_BOUND) as usize;\n                to_input(&x)\n            }\n        })\n        .collect()\n}\n\nfn seq(inputs: &[Input], map: impl Fn(&Input) -> Result<String, Err>) -> Result<Vec<String>, Err> {\n    inputs.iter().map(map).collect()\n}\n\nfn rayon(\n    inputs: &[Input],\n    map: impl Fn(&Input) -> Result<String, Err> + Sync + Send,\n) -> Result<Vec<String>, Err> {\n    use rayon::iter::*;\n    inputs.into_par_iter().map(map).collect()\n}\n\nfn orx(\n    inputs: &[Input],\n    map: impl Fn(&Input) -> Result<String, Err> + Sync + Clone,\n) -> Result<Vec<String>, Err> {\n    use orx_parallel::*;\n    inputs.into_par().map(map).into_fallible_result().collect()\n}\n\nfn orx_arbitrary(\n    inputs: &[Input],\n    map: impl Fn(&Input) -> Result<String, Err> + Sync + Clone,\n) -> Result<Vec<String>, Err> {\n    use orx_parallel::*;\n    inputs\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(map)\n        .into_fallible_result()\n        .collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"result_collect_map\");\n\n    for n_when in &treatments {\n        let input = inputs(N, *n_when);\n        let expected = seq(&input, map_input_to_result);\n\n        let n_when = match *n_when {\n            N_EARLY => \"error-early\",\n            N_MIDDLE => \"error-in-the-middle\",\n            N_LATE => \"error-late\",\n            N_NEVER => \"error-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, map_input_to_result));\n            b.iter(|| seq(black_box(&input), map_input_to_result))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, map_input_to_result));\n            b.iter(|| rayon(black_box(&input), map_input_to_result))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, map_input_to_result));\n            b.iter(|| orx(black_box(&input), map_input_to_result))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx_arbitrary\", n_when), n_when, |b, _| {\n            assert_eq!(\n                expected.as_ref().map(|x| x.len()),\n                orx_arbitrary(&input, map_input_to_result)\n                    .as_ref()\n                    .map(|x| x.len())\n            );\n            b.iter(|| orx_arbitrary(black_box(&input), map_input_to_result))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/result_reduce_map.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_concurrent_option::{ConcurrentOption, IntoOption};\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse std::hint::black_box;\nuse std::num::ParseIntError;\n\ntype Err = ParseIntError;\n\nconst TEST_LARGE_OUTPUT: bool = false;\nconst N: usize = 65_536 * 4;\nconst N_EARLY: usize = 1000;\nconst N_MIDDLE: usize = 65_536 * 2;\nconst N_LATE: usize = 65_536 * 4 - 10;\nconst N_NEVER: usize = usize::MAX;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Input {\n    id: String,\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn to_input(idx: &usize) -> Input {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    let id = idx.to_string();\n\n    Input { id, name, numbers }\n}\n\nfn to_bad_input() -> Input {\n    Input {\n        id: \"xyz\".to_string(),\n        name: \"xyz\".to_string(),\n        numbers: Default::default(),\n    }\n}\n\nfn map_input_to_result(input: &Input) -> Result<String, Err> {\n    match input.id.parse::<usize>() {\n        Ok(_) => Ok(input.id.clone()),\n        Err(e) => Err(e),\n    }\n}\n\nfn map_to_number(a: String) -> u32 {\n    let num = a.parse::<u32>().unwrap();\n    fibonacci(&(num % 72))\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize, idx_error: usize) -> Vec<Input> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|i| match i == idx_error {\n            true => to_bad_input(),\n            false => {\n                let x = rng.random_range(0..FIB_UPPER_BOUND) as usize;\n                to_input(&x)\n            }\n        })\n        .collect()\n}\n\nfn seq(inputs: &[Input], map: impl Fn(&Input) -> Result<String, Err>) -> Result<Option<u32>, Err> {\n    let mut error = None;\n    let sum = inputs\n        .iter()\n        .map(map)\n        .inspect(|x| {\n            if let Err(e) = x {\n                error = Some(e.clone());\n            }\n        })\n        .take_while(|x| x.is_ok())\n        .map(|x| map_to_number(x.unwrap()))\n        .reduce(|a, b| a + b);\n\n    match error {\n        Some(error) => Err(error),\n        None => Ok(sum),\n    }\n}\n\nfn rayon(\n    inputs: &[Input],\n    map: impl Fn(&Input) -> Result<String, Err> + Sync + Send,\n) -> Result<Option<u32>, Err> {\n    use rayon::iter::*;\n    let error = ConcurrentOption::none();\n    let sum = inputs\n        .into_par_iter()\n        .map(map)\n        .inspect(|x| {\n            if let Err(e) = x {\n                error.set_some(e.clone());\n            }\n        })\n        .map(|x| x.ok())\n        .while_some()\n        .map(map_to_number)\n        .reduce_with(|a, b| a + b);\n\n    match error.into_option() {\n        Some(error) => Err(error),\n        None => Ok(sum),\n    }\n}\n\nfn orx(\n    inputs: &[Input],\n    map: impl Fn(&Input) -> Result<String, Err> + Sync + Clone,\n) -> Result<Option<u32>, Err> {\n    use orx_parallel::*;\n    inputs\n        .into_par()\n        .map(map)\n        .into_fallible_result()\n        .map(map_to_number)\n        .reduce(|a, b| a + b)\n}\n\nfn orx_arbitrary(\n    inputs: &[Input],\n    map: impl Fn(&Input) -> Result<String, Err> + Sync + Clone,\n) -> Result<Option<u32>, Err> {\n    use orx_parallel::*;\n    inputs\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(map)\n        .into_fallible_result()\n        .map(map_to_number)\n        .reduce(|a, b| a + b)\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [N_EARLY, N_MIDDLE, N_LATE, N_NEVER];\n\n    let mut group = c.benchmark_group(\"result_reduce_map\");\n\n    for n_when in &treatments {\n        let input = inputs(N, *n_when);\n        let expected = seq(&input, map_input_to_result);\n\n        let n_when = match *n_when {\n            N_EARLY => \"error-early\",\n            N_MIDDLE => \"error-in-the-middle\",\n            N_LATE => \"error-late\",\n            N_NEVER => \"error-never\",\n            _ => panic!(\"unhandled n-when\"),\n        };\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &seq(&input, map_input_to_result));\n            b.iter(|| seq(black_box(&input), map_input_to_result))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &rayon(&input, map_input_to_result));\n            b.iter(|| rayon(black_box(&input), map_input_to_result))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx(&input, map_input_to_result));\n            b.iter(|| orx(black_box(&input), map_input_to_result))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx_arbitrary\", n_when), n_when, |b, _| {\n            assert_eq!(&expected, &orx_arbitrary(&input, map_input_to_result));\n            b.iter(|| orx_arbitrary(black_box(&input), map_input_to_result))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/sum.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\nfn to_output(idx: &usize) -> u32 {\n    let idx = *idx;\n    fibonacci(&(idx as u32))\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<u32> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .map(|x| to_output(&x))\n        .collect()\n}\n\nfn seq(inputs: &[u32]) -> u32 {\n    inputs.iter().sum()\n}\n\nfn rayon(inputs: &[u32]) -> u32 {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().sum()\n}\n\nfn orx(inputs: &[u32]) -> u32 {\n    inputs.into_par().sum()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"sum\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/sum_filtermap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn filter_map(idx: &usize) -> Option<u64> {\n    idx.is_multiple_of(3)\n        .then(|| to_output(idx))\n        .map(|x| x.name.len() as u64)\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> u64 {\n    inputs.iter().filter_map(filter_map).sum()\n}\n\nfn rayon(inputs: &[usize]) -> u64 {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().filter_map(filter_map).sum()\n}\n\nfn orx(inputs: &[usize]) -> u64 {\n    inputs.into_par().filter_map(filter_map).sum()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"sum_filtermap\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/sum_flatmap.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 9562;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn flat_map(idx: &usize) -> Vec<u64> {\n    (0..4)\n        .map(|i| to_output(&(idx + i)))\n        .map(|x| x.name.len() as u64)\n        .collect::<Vec<_>>()\n}\n\nfn to_output(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> u64 {\n    inputs.iter().flat_map(flat_map).sum()\n}\n\nfn rayon(inputs: &[usize]) -> u64 {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().flat_map(flat_map).sum()\n}\n\nfn orx(inputs: &[usize]) -> u64 {\n    inputs.into_par().flat_map(flat_map).sum()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"sum_flatmap\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/sum_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::hint::black_box;\n\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\nfn map(idx: &usize) -> u32 {\n    let idx = *idx;\n    fibonacci(&(idx as u32))\n}\n\nfn filter(output: &u32) -> bool {\n    !output.is_multiple_of(3)\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> Vec<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &[usize]) -> u32 {\n    inputs.iter().map(map).filter(filter).sum()\n}\n\nfn rayon(inputs: &[usize]) -> u32 {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).filter(filter).sum()\n}\n\nfn orx(inputs: &[usize]) -> u32 {\n    inputs.into_par().map(map).filter(filter).sum()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"sum_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n\n        group.bench_with_input(BenchmarkId::new(\"seq\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx\", n), n, |b, _| {\n            assert_eq!(&expected, &orx(&input));\n            b.iter(|| orx(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/t_par_merge_sorted.rs",
    "content": "use criterion::{Criterion, criterion_group, criterion_main};\n\n#[cfg(feature = \"experiment\")]\nmod inner {\n    use criterion::Criterion;\n    use orx_criterion::{Experiment, Factors};\n    use orx_parallel::DefaultRunner;\n    use orx_parallel::experiment::algorithms::merge_sorted_slices::par::{\n        ParamsParMergeSortedSlices, PivotSearch, par_merge,\n    };\n    use orx_parallel::experiment::algorithms::merge_sorted_slices::seq::{\n        ParamsSeqMergeSortedSlices, StreakSearch,\n    };\n    use orx_parallel::experiment::data_structures::slice_dst::SliceDst;\n    use orx_parallel::experiment::data_structures::slice_src::SliceSrc;\n    use rand::prelude::*;\n    use rand_chacha::ChaCha8Rng;\n    use std::cell::UnsafeCell;\n\n    type X = usize;\n\n    fn elem(i: usize) -> X {\n        i\n    }\n\n    #[inline(always)]\n    fn is_leq(a: &X, b: &X) -> bool {\n        a < b\n    }\n\n    fn new_vec<T: Ord>(len: usize, elem: impl Fn(usize) -> T, sort_kind: SortKind) -> Vec<T> {\n        let mut vec: Vec<_> = (0..len).map(elem).collect();\n        match sort_kind {\n            SortKind::Sorted => vec.sort(),\n            SortKind::Mixed => {\n                let num_shuffles = 10 * len;\n                let mut rng = ChaCha8Rng::seed_from_u64(42);\n                for _ in 0..num_shuffles {\n                    let i = rng.random_range(0..len);\n                    let j = rng.random_range(0..len);\n                    vec.swap(i, j);\n                }\n            }\n        }\n        vec\n    }\n\n    fn split_to_sorted_vecs<T: Ord + Clone>(vec: &[T], split_kind: SplitKind) -> (Vec<T>, Vec<T>) {\n        split_at(vec, split_kind.split_point(vec.len()))\n    }\n\n    fn split_at<T: Ord + Clone>(vec: &[T], split_at: usize) -> (Vec<T>, Vec<T>) {\n        let (left, right) = vec.split_at(split_at);\n        let mut left = left.to_vec();\n        let mut right = right.to_vec();\n        left.sort();\n        right.sort();\n        (left, right)\n    }\n\n    // treatments\n\n    #[derive(Clone, Copy, Debug)]\n    #[allow(dead_code)]\n    enum SortKind {\n        Sorted,\n        Mixed,\n    }\n\n    #[derive(Clone, Copy, Debug)]\n    #[allow(dead_code)]\n    enum SplitKind {\n        MoreInLeft,\n        MoreInRight,\n        Middle,\n    }\n\n    impl SplitKind {\n        fn split_point(&self, len: usize) -> usize {\n            match self {\n                Self::MoreInLeft => len * 3 / 4,\n                Self::MoreInRight => len / 4,\n                Self::Middle => len / 2,\n            }\n        }\n    }\n\n    struct Input {\n        left: Vec<X>,\n        right: Vec<X>,\n        target: UnsafeCell<Vec<X>>,\n    }\n\n    impl Drop for Input {\n        fn drop(&mut self) {\n            unsafe {\n                let target = &mut *self.target.get();\n                target.set_len(self.left.len() + self.right.len());\n                self.left.set_len(0);\n                self.right.set_len(0);\n            }\n        }\n    }\n\n    struct MergeData {\n        e: usize,\n        sort: SortKind,\n        split: SplitKind,\n    }\n\n    impl Factors for MergeData {\n        fn factor_names() -> Vec<&'static str> {\n            vec![\"e (len=2^e)\", \"sort\", \"split\"]\n        }\n\n        fn factor_names_short() -> Vec<&'static str> {\n            vec![\"e\", \"so\", \"sp\"]\n        }\n\n        fn factor_levels(&self) -> Vec<String> {\n            vec![\n                self.e.to_string(),\n                format!(\"{:?}\", self.sort),\n                format!(\"{:?}\", self.split),\n            ]\n        }\n\n        fn factor_levels_short(&self) -> Vec<String> {\n            vec![\n                self.e.to_string(),\n                match self.sort {\n                    SortKind::Sorted => \"T\",\n                    SortKind::Mixed => \"F\",\n                }\n                .to_string(),\n                match self.split {\n                    SplitKind::Middle => \"M\",\n                    SplitKind::MoreInLeft => \"L\",\n                    SplitKind::MoreInRight => \"R\",\n                }\n                .to_string(),\n            ]\n        }\n    }\n\n    impl MergeData {\n        fn all() -> Vec<Self> {\n            let mut all = vec![];\n\n            let e = [15, 20];\n            let sort = [SortKind::Mixed];\n            let split = [SplitKind::Middle];\n\n            for e in e {\n                for sort in sort {\n                    for split in split {\n                        all.push(MergeData { e, sort, split });\n                    }\n                }\n            }\n            all\n        }\n    }\n\n    // factors\n\n    struct Params(ParamsParMergeSortedSlices);\n\n    impl Factors for Params {\n        fn factor_names() -> Vec<&'static str> {\n            vec![\n                \"streak_search\",\n                \"pivot_search\",\n                \"put_large_to_left\",\n                \"min_split_len\",\n                \"chunk_size\",\n                \"num_threads\",\n            ]\n        }\n\n        fn factor_names_short() -> Vec<&'static str> {\n            vec![\"ss\", \"ps\", \"ll\", \"min\", \"ch\", \"nt\"]\n        }\n\n        fn factor_levels(&self) -> Vec<String> {\n            vec![\n                format!(\"{:?}\", self.0.seq_params.streak_search),\n                format!(\"{:?}\", self.0.pivot_search),\n                self.0.put_large_to_left.to_string(),\n                self.0.min_split_len.to_string(),\n                self.0.chunk_size.to_string(),\n                self.0.num_threads.to_string(),\n            ]\n        }\n\n        fn factor_levels_short(&self) -> Vec<String> {\n            vec![\n                match self.0.seq_params.streak_search {\n                    StreakSearch::None => \"X\",\n                    StreakSearch::Linear => \"L\",\n                    StreakSearch::Binary => \"B\",\n                }\n                .to_string(),\n                match self.0.pivot_search {\n                    PivotSearch::Linear => \"L\",\n                    PivotSearch::Binary => \"B\",\n                }\n                .to_string(),\n                match self.0.put_large_to_left {\n                    true => \"T\",\n                    false => \"F\",\n                }\n                .to_string(),\n                self.0.min_split_len.to_string(),\n                self.0.chunk_size.to_string(),\n                self.0.num_threads.to_string(),\n            ]\n        }\n    }\n\n    impl Params {\n        fn all() -> Vec<Self> {\n            let mut all = vec![];\n            let put_large_to_left = [false, true];\n            let min_split_len = [1024];\n            let streak_search = [StreakSearch::None, StreakSearch::Linear];\n            let pivot_search = [PivotSearch::Linear, PivotSearch::Binary];\n            let chunk_size = [1, 1024];\n            let num_threads = [1, 8];\n\n            for put_large_to_left in put_large_to_left[..1].to_vec() {\n                for min_split_len in min_split_len[..1].to_vec() {\n                    for streak_search in streak_search[..1].to_vec() {\n                        for pivot_search in pivot_search[..1].to_vec() {\n                            for chunk_size in chunk_size[..1].to_vec() {\n                                for num_threads in num_threads {\n                                    all.push(Self(ParamsParMergeSortedSlices {\n                                        seq_params: ParamsSeqMergeSortedSlices {\n                                            streak_search,\n                                            put_large_to_left,\n                                        },\n                                        put_large_to_left,\n                                        min_split_len,\n                                        pivot_search,\n                                        num_threads,\n                                        chunk_size,\n                                    }));\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            all\n        }\n    }\n\n    // exp\n\n    struct TuneExperiment;\n\n    impl Experiment for TuneExperiment {\n        type InputFactors = MergeData;\n\n        type AlgFactors = Params;\n\n        type Input = Input;\n\n        type Output = ();\n\n        fn input(&mut self, treatment: &Self::InputFactors) -> Self::Input {\n            let len = 1 << treatment.e;\n            let vec = new_vec(len, elem, treatment.sort);\n            let (left, right) = split_to_sorted_vecs(&vec, treatment.split);\n            let target = Vec::with_capacity(vec.len()).into();\n            Input {\n                left,\n                right,\n                target,\n            }\n        }\n\n        fn execute(&mut self, variant: &Self::AlgFactors, input: &Self::Input) -> Self::Output {\n            let target = unsafe { &mut *input.target.get() };\n            let target = SliceDst::from_vec(target);\n            let left = SliceSrc::from_slice(input.left.as_slice());\n            let right = SliceSrc::from_slice(input.right.as_slice());\n            let params = variant.0;\n            par_merge(\n                is_leq,\n                left,\n                right,\n                target,\n                &params,\n                DefaultRunner::default(),\n            );\n        }\n    }\n\n    pub fn run(c: &mut Criterion) {\n        let treatments = MergeData::all();\n        let variants = Params::all();\n        TuneExperiment.bench(c, \"t_seq_merge_sorted\", &treatments, &variants);\n    }\n}\n\n#[cfg(feature = \"experiment\")]\nfn run(c: &mut Criterion) {\n    inner::run(c);\n}\n#[cfg(not(feature = \"experiment\"))]\nfn run(_: &mut Criterion) {\n    panic!(\"REQUIRES FEATURE: experiment\");\n}\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/t_seq_merge_sorted.rs",
    "content": "use criterion::{Criterion, criterion_group, criterion_main};\n\n#[cfg(feature = \"experiment\")]\nmod inner {\n    use criterion::Criterion;\n    use orx_criterion::{Experiment, Factors};\n    use orx_parallel::experiment::algorithms::merge_sorted_slices::seq::seq_merge;\n    use orx_parallel::experiment::algorithms::merge_sorted_slices::seq::{\n        ParamsSeqMergeSortedSlices, StreakSearch,\n    };\n    use orx_parallel::experiment::data_structures::slice_dst::SliceDst;\n    use orx_parallel::experiment::data_structures::slice_src::SliceSrc;\n    use rand::prelude::*;\n    use rand_chacha::ChaCha8Rng;\n    use std::cell::UnsafeCell;\n\n    type X = usize;\n\n    fn elem(i: usize) -> X {\n        i\n    }\n\n    #[inline(always)]\n    fn is_leq(a: &X, b: &X) -> bool {\n        a < b\n    }\n\n    fn new_vec<T: Ord>(len: usize, elem: impl Fn(usize) -> T, sort_kind: SortKind) -> Vec<T> {\n        let mut vec: Vec<_> = (0..len).map(elem).collect();\n        match sort_kind {\n            SortKind::Sorted => vec.sort(),\n            SortKind::Mixed => {\n                let num_shuffles = 10 * len;\n                let mut rng = ChaCha8Rng::seed_from_u64(42);\n                for _ in 0..num_shuffles {\n                    let i = rng.random_range(0..len);\n                    let j = rng.random_range(0..len);\n                    vec.swap(i, j);\n                }\n            }\n        }\n        vec\n    }\n\n    fn split_to_sorted_vecs<T: Ord + Clone>(vec: &[T], split_kind: SplitKind) -> (Vec<T>, Vec<T>) {\n        split_at(vec, split_kind.split_point(vec.len()))\n    }\n\n    fn split_at<T: Ord + Clone>(vec: &[T], split_at: usize) -> (Vec<T>, Vec<T>) {\n        let (left, right) = vec.split_at(split_at);\n        let mut left = left.to_vec();\n        let mut right = right.to_vec();\n        left.sort();\n        right.sort();\n        (left, right)\n    }\n\n    // treatments\n\n    #[derive(Clone, Copy, Debug)]\n    enum SortKind {\n        Sorted,\n        Mixed,\n    }\n\n    #[derive(Clone, Copy, Debug)]\n    enum SplitKind {\n        MoreInLeft,\n        MoreInRight,\n        Middle,\n    }\n\n    impl SplitKind {\n        fn split_point(&self, len: usize) -> usize {\n            match self {\n                Self::MoreInLeft => len * 3 / 4,\n                Self::MoreInRight => len / 4,\n                Self::Middle => len / 2,\n            }\n        }\n    }\n\n    struct Input {\n        left: Vec<X>,\n        right: Vec<X>,\n        target: UnsafeCell<Vec<X>>,\n    }\n\n    impl Drop for Input {\n        fn drop(&mut self) {\n            unsafe {\n                let target = &mut *self.target.get();\n                target.set_len(self.left.len() + self.right.len());\n                self.left.set_len(0);\n                self.right.set_len(0);\n            }\n        }\n    }\n\n    struct MergeData {\n        e: usize,\n        sort: SortKind,\n        split: SplitKind,\n    }\n\n    impl Factors for MergeData {\n        fn factor_names() -> Vec<&'static str> {\n            vec![\"e (len=2^e)\", \"sort\", \"split\"]\n        }\n\n        fn factor_names_short() -> Vec<&'static str> {\n            vec![\"e\", \"so\", \"sp\"]\n        }\n\n        fn factor_levels(&self) -> Vec<String> {\n            vec![\n                self.e.to_string(),\n                format!(\"{:?}\", self.sort),\n                format!(\"{:?}\", self.split),\n            ]\n        }\n\n        fn factor_levels_short(&self) -> Vec<String> {\n            vec![\n                self.e.to_string(),\n                match self.sort {\n                    SortKind::Sorted => \"T\",\n                    SortKind::Mixed => \"F\",\n                }\n                .to_string(),\n                match self.split {\n                    SplitKind::Middle => \"M\",\n                    SplitKind::MoreInLeft => \"L\",\n                    SplitKind::MoreInRight => \"R\",\n                }\n                .to_string(),\n            ]\n        }\n    }\n\n    impl MergeData {\n        fn all() -> Vec<Self> {\n            let mut all = vec![];\n\n            let e = [15, 20, 22, 25];\n            let sort = [SortKind::Mixed, SortKind::Sorted];\n            let split = [\n                SplitKind::Middle,\n                SplitKind::MoreInLeft,\n                SplitKind::MoreInRight,\n            ];\n\n            for e in e {\n                for sort in sort {\n                    for split in split {\n                        all.push(MergeData { e, sort, split });\n                    }\n                }\n            }\n            all\n        }\n    }\n\n    // factors\n\n    struct Params(ParamsSeqMergeSortedSlices);\n\n    impl Factors for Params {\n        fn factor_names() -> Vec<&'static str> {\n            vec![\"streak_search\", \"put_large_to_left\"]\n        }\n\n        fn factor_names_short() -> Vec<&'static str> {\n            vec![\"nt\", \"ss\"]\n        }\n\n        fn factor_levels(&self) -> Vec<String> {\n            vec![\n                format!(\"{:?}\", self.0.streak_search),\n                self.0.put_large_to_left.to_string(),\n            ]\n        }\n\n        fn factor_levels_short(&self) -> Vec<String> {\n            vec![\n                match self.0.streak_search {\n                    StreakSearch::None => \"X\",\n                    StreakSearch::Linear => \"L\",\n                    StreakSearch::Binary => \"B\",\n                }\n                .to_string(),\n                match self.0.put_large_to_left {\n                    true => \"T\",\n                    false => \"F\",\n                }\n                .to_string(),\n            ]\n        }\n    }\n\n    impl Params {\n        fn all() -> Vec<Self> {\n            let mut all = vec![];\n            let put_large_to_left = [false, true];\n            let streak_search = [\n                StreakSearch::None,\n                StreakSearch::Linear,\n                StreakSearch::Binary,\n            ];\n            for put_large_to_left in put_large_to_left {\n                for streak_search in streak_search.iter().cloned() {\n                    all.push(Self(ParamsSeqMergeSortedSlices {\n                        streak_search,\n                        put_large_to_left,\n                    }));\n                }\n            }\n            all\n        }\n    }\n\n    // exp\n\n    struct TuneExperiment;\n\n    impl Experiment for TuneExperiment {\n        type InputFactors = MergeData;\n\n        type AlgFactors = Params;\n\n        type Input = Input;\n\n        type Output = ();\n\n        fn input(&mut self, treatment: &Self::InputFactors) -> Self::Input {\n            let len = 1 << treatment.e;\n            let vec = new_vec(len, elem, treatment.sort);\n            let (left, right) = split_to_sorted_vecs(&vec, treatment.split);\n            let target = Vec::with_capacity(vec.len()).into();\n            Input {\n                left,\n                right,\n                target,\n            }\n        }\n\n        fn execute(&mut self, variant: &Self::AlgFactors, input: &Self::Input) -> Self::Output {\n            let target = unsafe { &mut *input.target.get() };\n            let target = SliceDst::from_vec(target);\n            let left = SliceSrc::from_slice(input.left.as_slice());\n            let right = SliceSrc::from_slice(input.right.as_slice());\n            let params = variant.0;\n            seq_merge(is_leq, left, right, target, &params);\n        }\n    }\n\n    pub fn run(c: &mut Criterion) {\n        let treatments = MergeData::all();\n        let variants = Params::all();\n        TuneExperiment.bench(c, \"t_seq_merge_sorted\", &treatments, &variants);\n    }\n}\n\n#[cfg(feature = \"experiment\")]\nfn run(c: &mut Criterion) {\n    inner::run(c);\n}\n#[cfg(not(feature = \"experiment\"))]\nfn run(_: &mut Criterion) {\n    panic!(\"REQUIRES FEATURE: experiment\");\n}\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/vec_deque_collect_map_filter.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::collections::VecDeque;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: &usize) -> Output {\n    let idx = *idx;\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> VecDeque<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: &VecDeque<usize>) -> Vec<Output> {\n    inputs.iter().map(map).filter(filter).collect()\n}\n\nfn rayon(inputs: &VecDeque<usize>) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).filter(filter).collect()\n}\n\nfn orx_into_vec(inputs: &VecDeque<usize>) -> Vec<Output> {\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\nfn orx_into_split_vec(inputs: &VecDeque<usize>) -> SplitVec<Output> {\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"VecDeque: collect_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let expected = seq(&input);\n        let mut sorted = seq(&input);\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(&input));\n            b.iter(|| seq(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(&input));\n            b.iter(|| rayon(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(&input));\n            b.iter(|| orx_into_vec(black_box(&input)))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(&input));\n            b.iter(|| orx_into_split_vec(black_box(&input)))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benches/vec_deque_collect_map_filter_owned.rs",
    "content": "use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};\nuse orx_parallel::*;\nuse orx_split_vec::SplitVec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\nuse rayon::iter::IntoParallelIterator;\nuse std::collections::VecDeque;\nuse std::hint::black_box;\n\nconst TEST_LARGE_OUTPUT: bool = false;\n\nconst LARGE_OUTPUT_LEN: usize = match TEST_LARGE_OUTPUT {\n    true => 64,\n    false => 0,\n};\nconst SEED: u64 = 5426;\nconst FIB_UPPER_BOUND: u32 = 201;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct Output {\n    name: String,\n    numbers: [i64; LARGE_OUTPUT_LEN],\n}\n\nfn map(idx: usize) -> Output {\n    let prefix = match idx % 7 {\n        0 => \"zero-\",\n        3 => \"three-\",\n        _ => \"sth-\",\n    };\n    let fib = fibonacci(&(idx as u32));\n    let name = format!(\"{}-fib-{}\", prefix, fib);\n\n    let mut numbers = [0i64; LARGE_OUTPUT_LEN];\n    for (i, x) in numbers.iter_mut().enumerate() {\n        *x = match (idx * 7 + i) % 3 {\n            0 => idx as i64 + i as i64,\n            _ => idx as i64 - i as i64,\n        };\n    }\n\n    Output { name, numbers }\n}\n\nfn filter(output: &Output) -> bool {\n    let last_char = output.name.chars().last().unwrap();\n    let last_digit: u32 = last_char.to_string().parse().unwrap();\n    last_digit < 4\n}\n\nfn fibonacci(n: &u32) -> u32 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn inputs(len: usize) -> VecDeque<usize> {\n    let mut rng = ChaCha8Rng::seed_from_u64(SEED);\n    (0..len)\n        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)\n        .collect()\n}\n\nfn seq(inputs: VecDeque<usize>) -> Vec<Output> {\n    inputs.into_iter().map(map).filter(filter).collect()\n}\n\nfn rayon(inputs: VecDeque<usize>) -> Vec<Output> {\n    use rayon::iter::ParallelIterator;\n    inputs.into_par_iter().map(map).filter(filter).collect()\n}\n\nfn orx_into_vec(inputs: VecDeque<usize>) -> Vec<Output> {\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\nfn orx_into_split_vec(inputs: VecDeque<usize>) -> SplitVec<Output> {\n    inputs.into_par().map(map).filter(filter).collect()\n}\n\nfn run(c: &mut Criterion) {\n    let treatments = [65_536 * 2];\n\n    let mut group = c.benchmark_group(\"VecDeque-owned: collect_map_filter\");\n\n    for n in &treatments {\n        let input = inputs(*n);\n        let input = || input.clone();\n        let expected = seq(input());\n        let mut sorted = seq(input());\n        sorted.sort();\n\n        group.bench_with_input(BenchmarkId::new(\"seq-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &seq(input()));\n            b.iter(|| seq(black_box(input())))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"rayon-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &rayon(input()));\n            b.iter(|| rayon(black_box(input())))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_vec(input()));\n            b.iter(|| orx_into_vec(black_box(input())))\n        });\n\n        group.bench_with_input(BenchmarkId::new(\"orx-into-split-vec\", n), n, |b, _| {\n            assert_eq!(&expected, &orx_into_split_vec(input()));\n            b.iter(|| orx_into_split_vec(black_box(input())))\n        });\n    }\n\n    group.finish();\n}\n\ncriterion_group!(benches, run);\ncriterion_main!(benches);\n"
  },
  {
    "path": "docs/using.md",
    "content": "# Using Transformation\n\n[`ParIter`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html) trait is designed to be as close as possible to the `Iterator` api both due to the fact that:\n\n* iterator api is familiar and awesome, and\n* the goal is to parallelize the computation conveniently by changing `iter` with `par`; or `into_iter` with `into_par`.\n\nHowever, there are certain differences in terms of mutability of the closures, mainly to prevent race conditions.\n\n## The limitation\n\nFor instance, the following is the `map` signature of the sequential `Iterator`:\n\n```rust\nfn map<B, F>(self, f: F) -> Map<Self, F>\nwhere\n    F: FnMut(Self::Item) -> B;\n```\n\nwhile, the map signature of the parallel `ParIter` uses `Fn` rather than `FnMut`:\n\n```rust\nfn map<B, F>(self, f: F) -> impl ParIter<R, Item = B>\nwhere\n    F: Fn(Self::Item) -> B;\n```\n\nIt might be obvious but to clarify why parallel map can only accept `Fn`, assume that `f` captures a mutable counter, and increments the counter every time it is called.\n\n* This is perfectly fine in a sequential iterator. The counter will be incremented one at a time.\n* However, in parallel computation, multiple threads will be trying to increment this mutable counter at the same time leading to a race condition. Limiting `f` to be `Fn`, we guarantee that our computation is free of race condition.\n\n## A common use case, random number generators\n\nConsider that we have a computation that requires random numbers. For brevity, random number generators can be considered as iterators returning a series of random numbers as we request. Therefore, it keeps its current position and generates random numbers via a mutable reference.\n\nConsider the following example, where we take a set of `positions` and take 100 random steps to left or to right starting from each one of them. Then, we check the final positions.\n\nIn order to take the random step, we need a mutable `rng`.\n\nSince the sequential iterator's `map` method allows for `FnMut`:\n* we can use `.map(|position| random_walk(&mut rng, position, 100))`,\n* which matches the signature `F: FnMut(i64) -> i64`,\n* while the captured mutable `rng` reference is the reason of the closure being `FnMut` and it is conveniently abstracted away.\n\n```rust\nuse rand::{Rng, SeedableRng};\nuse rand_chacha::ChaCha20Rng;\n\nfn random_walk(rng: &mut impl Rng, position: i64, num_steps: usize) -> i64 {\n    (0..num_steps).fold(position, |p, _| random_step(rng, p))\n}\n\nfn random_step(rng: &mut impl Rng, position: i64) -> i64 {\n    match rng.random_bool(0.5) {\n        true => position + 1,  // to right\n        false => position - 1, // to left\n    }\n}\n\nfn input_positions() -> Vec<i64> {\n    (-10_000..=10_000).collect()\n}\n\nfn sequential() {\n    let positions = input_positions();\n    let sum_initial_positions = positions.iter().sum::<i64>();\n    println!(\"sum_initial_positions = {sum_initial_positions}\");\n\n    let mut rng = ChaCha20Rng::seed_from_u64(42);\n    let final_positions: Vec<_> = positions\n        .iter()\n        .copied()\n        .map(|position| random_walk(&mut rng, position, 100))\n        .collect();\n    let sum_final_positions = final_positions.iter().sum::<i64>();\n    println!(\"sum_final_positions = {sum_final_positions}\");\n}\n```\n\nHowever, we cannot do the same with a parallel iterator. The following will not compile:\n\n```rust\nfn parallel() {\n    let positions = input_positions();\n    let sum_initial_positions = positions.iter().sum::<i64>();\n    println!(\"sum_initial_positions = {sum_initial_positions}\");\n\n    let mut rng = ChaCha20Rng::seed_from_u64(42);\n    let final_positions: Vec<_> = positions\n        .par() // <-- parallel computation\n        .copied()\n        .map(|position| random_walk(&mut rng, position, 100)) // <-- does not compile!!\n        .collect();\n    let sum_final_positions = final_positions.iter().sum::<i64>();\n    println!(\"sum_final_positions = {sum_final_positions}\");\n}\n```\n\nAnd it should not compile. If it did, multiple threads would call `random_bool` on the same `rng` at the same time, which would lead to the race condition.\n\n## Solution `using` an explicit mutable variable\n\n[`ParIter`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html) does not allow the parallel computation defined above; however, [`ParIterUsing`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIterUsing.html) enables it safely with the following approach:\n\n* No race conditions are allowed; therefore, there cannot be one mutable **variable** that all threads accesses.\n* Instead, all threads have their own mutable **variable**.\n* Since the computation within the thread is sequential, there cannot be any race condition and we can freely mutate the **variable**.\n* This **variable** is explicitly defined by one of the two methods which transforms the `ParIter` into `ParIterUsing`.\n  * [`using`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.using): method takes a closure with signature `F: FnMut(usize) -> U`. It takes the index of the spawned thread as input and creates an instance of the variable of type `U`.\n  * [`using_clone`](https://docs.rs/orx-parallel/latest/orx_parallel/trait.ParIter.html#tymethod.using_clone) instead takes a cloneable value of type `U` and provides one clone of it to each of the threads. We can consider `par.using_clone(value)` as a shorthand for `par.using(|_thread_idx| value.clone())`.\n\nProvided that the parallel computation is executed with `N` threads, then **exactly** `N` different instances of `U` will be created and send to each thread.\n\nThen, a mutable reference to this variable will be available to all of the parallel iterator methods. For instance, the signature of `map` method of the `ParIterUsing` is as follows:\n\n```rust\nfn map<U, B, F>(self, f: F) -> impl ParIter<R, Item = B>\nwhere\n    F: Fn(&mut U, Self::Item) -> B;\n```\n\nNotice that the closure is safely `Fn` as it does not mutate any captured variable. On the other hand, it explicitly takes a mutable reference to a value of `U`. This allows us to represent the computation above and execute it in parallel as follows:\n\n```rust\nfn parallel() {\n    let positions = input_positions();\n    let sum_initial_positions = positions.iter().sum::<i64>();\n    println!(\"sum_initial_positions = {sum_initial_positions}\");\n\n    let final_positions: Vec<_> = positions\n        .par() // <-- parallel computation\n        .copied()\n        .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64)) // <-- explicit using\n        .map(|rng, position| random_walk(rng, position, 100)) // <-- safe access to mutable rng\n        .collect();\n    let sum_final_positions = final_positions.iter().sum::<i64>();\n    println!(\"sum_final_positions = {sum_final_positions}\");\n}\n```\n\nThere are two important differences here.\n\n1. With the following line, we are expressing that each thread will create a random number generator (rng). Further, we state that the seed of the rng will be `42 * t_idx` which guarantees that no two threads will use the same sequence of random numbers (important when it matters).\n\n```rust\n    .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64))\n```\n\n2. Next, in the `map` call, we have access to a mutable reference to the used variable. This variable is the `rng` created for that specific thread.\n\n```rust\n    .map(|rng, position| random_walk(rng, position, 100)) // rng: &mut ChaCha20Rng\n```\n\n## Generalization\n\nNotice that once the safety measures are defined by `ParIterUsing`, it is not different to implement `map`, `filter` or `for_each`, etc. Therefore, all these methods have access to a mutable reference of `U`. The following example demonstrates some of them, all with safe access to the mutable variable `rng`.\n\n```rust\nlet input: Vec<u64> = (1..N).collect();\nlet some_counter = AtomicU64::new(0);\n\ninput\n    .into_par()\n    .using(|thread_idx| ChaCha20Rng::seed_from_u64(thread_idx as u64 * 10))\n    .map(|_, i| fibonacci((i % 50) + 1) % 100)\n    .filter(|rng, _| rng.random_bool(0.4))\n    .flat_map(|rng, i| [rng.random_range(0..i), rng.random_range(0..i)])\n    .inspect(|rng, i| {\n        if *i < 42 && rng.random_bool(0.2) {\n            some_counter.fetch_add(*i, Ordering::Relaxed);\n        }\n    })\n    .sum()\n```\n\n## Examples - Channels\n\nRandom number generator is one of the common use cases that is important for a certain class of algorithms.\n\nHowever, there are other use cases where access to mutable variable is useful. `rayon` allows such computations with `map_with` and `for_each_with` methods, and channels are used as examples in the corresponding documentations. The following example is taken from these documentations and converted to `using` transformation:\n\n```rust\nuse orx_parallel::*;\nuse std::sync::mpsc::channel;\n\nlet (sender, receiver) = channel();\n\n(0..5)\n    .into_par()\n    .using_clone(sender)\n    .for_each(|s, x| s.send(x).unwrap());\n\nlet mut res: Vec<_> = receiver.iter().collect();\n\nres.sort();\n\nassert_eq!(&res[..], &[0, 1, 2, 3, 4])\n```\n\n## Examples - Metrics\n\nAnother potential use case is to be able to collect certain metrics about the parallel execution, which is often not trivial.\n\nRevisiting the safety notes above, we should be able to collect metrics through mutation per each thread which would give us insights about the parallel execution. To achieve this, in addition to `using`, we need some `unsafe` help with interior mutability.\n\nYou may see the corresponding example file here: [using_metrics](https://github.com/orxfun/orx-parallel/blob/main/examples/using_metrics.rs).\n\n```rust\nuse orx_parallel::*;\nuse std::cell::UnsafeCell;\n\nconst N: u64 = 10_000_000;\nconst MAX_NUM_THREADS: usize = 8;\n\n// just some work\nfn fibonacci(n: u64) -> u64 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\n#[derive(Default, Debug)]\nstruct ThreadMetrics {\n    thread_idx: usize,\n    num_items_handled: usize,\n    handled_42: bool,\n    num_filtered_out: usize,\n}\n\nstruct ThreadMetricsWriter<'a> {\n    metrics_ref: &'a mut ThreadMetrics,\n}\n\nstruct ComputationMetrics {\n    thread_metrics: UnsafeCell<[ThreadMetrics; MAX_NUM_THREADS]>,\n}\nimpl ComputationMetrics {\n    fn new() -> Self {\n        let mut thread_metrics: [ThreadMetrics; MAX_NUM_THREADS] = Default::default();\n        for i in 0..MAX_NUM_THREADS {\n            thread_metrics[i].thread_idx = i;\n        }\n        Self {\n            thread_metrics: UnsafeCell::new(thread_metrics),\n        }\n    }\n}\n\nimpl ComputationMetrics {\n    unsafe fn create_for_thread<'a>(&mut self, thread_idx: usize) -> ThreadMetricsWriter<'a> {\n        // SAFETY: here we create a mutable variable to the thread_idx-th metrics\n        // * If we call this method multiple times with the same index,\n        //   we create multiple mutable references to the same ThreadMetrics,\n        //   which would lead to a race condition.\n        // * We must make sure that `create_for_thread` is called only once per thread.\n        // * If we use `create_for_thread` within the `using` call to create mutable values\n        //   used by the threads, we are certain that the parallel computation\n        //   will only call this method once per thread; hence, it will not\n        //   cause the race condition.\n        // * On the other hand, we must ensure that we do not call this method\n        //   externally.\n        let array = unsafe { &mut *self.thread_metrics.get() };\n        ThreadMetricsWriter {\n            metrics_ref: &mut array[thread_idx],\n        }\n    }\n}\n\nfn main() {\n    let mut metrics = ComputationMetrics::new();\n\n    let input: Vec<u64> = (0..N).collect();\n\n    let sum = input\n        .par()\n        // SAFETY: we do not call `create_for_thread` externally;\n        // it is safe if it is called only by the parallel computation.\n        .using(|t| unsafe { metrics.create_for_thread(t) })\n        .map(|m: &mut ThreadMetricsWriter<'_>, i| {\n            // collect some useful metrics\n            m.metrics_ref.num_items_handled += 1;\n            m.metrics_ref.handled_42 |= *i == 42;\n\n            // actual work\n            fibonacci((*i % 50) + 1) % 100\n        })\n        .filter(|m, i| {\n            let is_even = i % 2 == 0;\n\n            if !is_even {\n                m.metrics_ref.num_filtered_out += 1;\n            }\n\n            is_even\n        })\n        .num_threads(MAX_NUM_THREADS)\n        .sum();\n\n    println!(\"\\nINPUT-LEN = {N}\");\n    println!(\"SUM = {sum}\");\n\n    println!(\"\\n\\n\");\n\n    println!(\"COLLECTED METRICS PER THREAD\");\n    for metrics in metrics.thread_metrics.get_mut().iter() {\n        println!(\"* {metrics:?}\");\n    }\n    let total_by_metrics: usize = metrics\n        .thread_metrics\n        .get_mut()\n        .iter()\n        .map(|x| x.num_items_handled)\n        .sum();\n    println!(\"\\n-> total num_items_handled by collected metrics: {total_by_metrics:?}\\n\");\n\n    assert_eq!(N as usize, total_by_metrics);\n}\n```\n\nNote that creating a thread metrics writer with the `ComputationMetrics::create_for_thread` method is `unsafe` as we can create multiple of them for the same thread metrics. However, parallel execution will not do this: it guarantees that the method will be called once per thread; hence, each call with a different thread index.\n\nOnce we define how to create the thread metrics writer with `using(|t| unsafe { metrics.create_for_thread(t) })`, the writer is then conveniently available to each of the parallel iterator methods. We can  safely use it within each of the closures to collect information; or simply omit when not required.\n\nAt the end of the computation, the collected metrics will be available by the computation metrics, `metrics`.\n\nThe output of the program is as follows:\n\n```bash\nINPUT-LEN = 10000000\nSUM = 162400000\n\nCOLLECTED METRICS PER THREAD\n* ThreadMetrics { thread_idx: 0, num_items_handled: 1310720, handled_42: true, num_filtered_out: 891288 }\n* ThreadMetrics { thread_idx: 1, num_items_handled: 1310720, handled_42: false, num_filtered_out: 891290 }\n* ThreadMetrics { thread_idx: 2, num_items_handled: 1310720, handled_42: false, num_filtered_out: 891290 }\n* ThreadMetrics { thread_idx: 3, num_items_handled: 1310720, handled_42: false, num_filtered_out: 891290 }\n* ThreadMetrics { thread_idx: 4, num_items_handled: 1087104, handled_42: false, num_filtered_out: 739231 }\n* ThreadMetrics { thread_idx: 5, num_items_handled: 1310720, handled_42: false, num_filtered_out: 891290 }\n* ThreadMetrics { thread_idx: 6, num_items_handled: 1048576, handled_42: false, num_filtered_out: 713032 }\n* ThreadMetrics { thread_idx: 7, num_items_handled: 1310720, handled_42: false, num_filtered_out: 891289 }\n\n-> total num_items_handled by collected metrics: 10000000\n```\n"
  },
  {
    "path": "examples/benchmark_collect.rs",
    "content": "mod utils;\n\n#[cfg(not(feature = \"generic_iterator\"))]\nfn main() {\n    panic!(\n        r#\"\n\nREQUIRES FEATURE: generic_iterator\n\nTo view the arguments:\ncargo run --release --features generic_iterator --example benchmark_collect -- --help\n\nTo run with default arguments:\ncargo run --release --features generic_iterator --example benchmark_collect\n\nTo run with desired arguments:\ncargo run --release --features generic_iterator --example benchmark_collect -- --len 123456 --num-repetitions 10\n\nPlay with the transformations inside the compute method to test out different computations.\n\n\"#\n    );\n}\n\n#[cfg(feature = \"generic_iterator\")]\nfn main() {\n    use clap::Parser;\n    use orx_parallel::{IntoParIter, ParIter, generic_iterator::GenericIterator};\n    use rayon::iter::{IntoParallelIterator, ParallelIterator};\n    use utils::timed_collect_all;\n\n    #[derive(Parser, Debug)]\n    struct Args {\n        /// Number of items in the input iterator.\n        #[arg(long, default_value_t = 100000)]\n        len: usize,\n        /// Number of repetitions to measure time; total time will be reported.\n        #[arg(long, default_value_t = 100)]\n        num_repetitions: usize,\n    }\n\n    fn compute(\n        iter: GenericIterator<\n            usize,\n            impl Iterator<Item = usize>,\n            impl ParallelIterator<Item = usize>,\n            impl ParIter<Item = usize>,\n        >,\n    ) -> Vec<String> {\n        iter.map(|x| x.to_string())\n            .filter_map(|x| (!x.starts_with('1')).then_some(x))\n            .flat_map(|x| [format!(\"{}!\", &x), x])\n            .filter(|x| !x.starts_with('2'))\n            .filter_map(|x| x.parse::<u64>().ok())\n            .map(|x| x.to_string())\n            .collect_vec()\n    }\n\n    let args = Args::parse();\n\n    let input = move || (0..args.len as usize).collect::<Vec<_>>();\n    let expected_output = compute(GenericIterator::sequential(input().into_iter()));\n\n    let computations: Vec<(&str, Box<dyn Fn() -> Vec<String>>)> = vec![\n        (\n            \"sequential\",\n            Box::new(move || compute(GenericIterator::sequential(input().into_iter()))),\n        ),\n        (\n            \"rayon\",\n            Box::new(move || compute(GenericIterator::rayon(input().into_par_iter()))),\n        ),\n        (\n            \"orx\",\n            Box::new(move || compute(GenericIterator::orx(input().into_par()))),\n        ),\n    ];\n\n    timed_collect_all(\n        \"benchmark_collect\",\n        args.num_repetitions,\n        &expected_output,\n        &computations,\n    );\n}\n"
  },
  {
    "path": "examples/benchmark_find.rs",
    "content": "mod utils;\n\n#[cfg(not(feature = \"generic_iterator\"))]\nfn main() {\n    panic!(\n        r#\"\n\nREQUIRES FEATURE: generic_iterator\n\nTo view the arguments:\ncargo run --release --features generic_iterator --example benchmark_find -- --help\n\nTo run with default arguments:\ncargo run --release --features generic_iterator --example benchmark_find\n\nTo run with desired arguments:\ncargo run --release --features generic_iterator --example benchmark_find -- --len 123456 --num-repetitions 10\n\nPlay with the transformations inside the compute method to test out different computations.\n\n\"#\n    );\n}\n\n#[cfg(feature = \"generic_iterator\")]\nfn main() {\n    use clap::Parser;\n    use orx_parallel::{IntoParIter, ParIter, generic_iterator::GenericIterator};\n    use rayon::iter::{IntoParallelIterator, ParallelIterator};\n    use std::fmt::Display;\n    use utils::timed_reduce_all;\n\n    #[derive(Parser, Debug)]\n    struct Args {\n        /// Number of items in the input iterator.\n        #[arg(long, default_value_t = 100000)]\n        len: usize,\n        /// Number of repetitions to measure time; total time will be reported.\n        #[arg(long, default_value_t = 100)]\n        num_repetitions: usize,\n    }\n\n    #[derive(Parser, Debug, Clone, Copy)]\n    enum FindWhen {\n        Early,\n        Middle,\n        Late,\n        Never,\n    }\n\n    impl Display for FindWhen {\n        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n            match self {\n                FindWhen::Early => write!(f, \"at the BEGINNING of the iterator\"),\n                FindWhen::Middle => write!(f, \"in the MIDDLE of the iterator\"),\n                FindWhen::Late => write!(f, \"at the END of the iterator\"),\n                FindWhen::Never => write!(f, \"is NOT in the iterator\"),\n            }\n        }\n    }\n\n    fn get_find(n: usize, find_when: FindWhen) -> impl Fn(&String) -> bool + Send + Sync + Clone {\n        move |x| match find_when {\n            FindWhen::Early => x.starts_with(\"3\"),\n            FindWhen::Middle => {\n                let position = n / 2;\n                x == &position.to_string()\n            }\n            FindWhen::Late => {\n                let position = n.saturating_sub(1);\n                x == &position.to_string()\n            }\n            FindWhen::Never => x.starts_with(\"x\"),\n        }\n    }\n\n    fn compute(\n        find: impl Fn(&String) -> bool + Send + Sync + Clone,\n        iter: GenericIterator<\n            usize,\n            impl Iterator<Item = usize>,\n            impl ParallelIterator<Item = usize>,\n            impl ParIter<Item = usize>,\n        >,\n    ) -> String {\n        iter.map(|x| x.to_string())\n            .filter_map(|x| (!x.starts_with('1')).then_some(x))\n            .flat_map(|x| [format!(\"{}!\", &x), x])\n            .filter(|x| !x.starts_with('2'))\n            .filter_map(|x| (!x.ends_with(\"!\")).then_some(x))\n            .find(find)\n            .unwrap_or_default()\n    }\n\n    let args = Args::parse();\n    let find_when = [\n        FindWhen::Early,\n        FindWhen::Middle,\n        FindWhen::Late,\n        FindWhen::Never,\n    ];\n\n    let input = move || (0..args.len as usize).collect::<Vec<_>>();\n\n    for when in find_when {\n        let find = move || get_find(args.len, when);\n        let expected_output = compute(find(), GenericIterator::sequential(input().into_iter()));\n\n        let computations: Vec<(&str, Box<dyn Fn() -> String>)> = vec![\n            (\n                \"sequential\",\n                Box::new(move || compute(find(), GenericIterator::sequential(input().into_iter()))),\n            ),\n            (\n                \"rayon\",\n                Box::new(move || compute(find(), GenericIterator::rayon(input().into_par_iter()))),\n            ),\n            (\n                \"orx\",\n                Box::new(move || compute(find(), GenericIterator::orx(input().into_par()))),\n            ),\n        ];\n\n        timed_reduce_all(\n            &format!(\"find item that is {}\", when),\n            args.num_repetitions,\n            Some(expected_output),\n            &computations,\n        );\n    }\n}\n"
  },
  {
    "path": "examples/benchmark_find_any.rs",
    "content": "mod utils;\n\n#[cfg(not(feature = \"generic_iterator\"))]\nfn main() {\n    panic!(\n        r#\"\n\nREQUIRES FEATURE: generic_iterator\n\nTo view the arguments:\ncargo run --release --features generic_iterator --example benchmark_find_any -- --help\n\nTo run with default arguments:\ncargo run --release --features generic_iterator --example benchmark_find_any\n\nTo run with desired arguments:\ncargo run --release --features generic_iterator --example benchmark_find_any -- --len 123456 --num-repetitions 10\n\nPlay with the transformations inside the compute method to test out different computations.\n\n\"#\n    );\n}\n\n#[cfg(feature = \"generic_iterator\")]\nfn main() {\n    use clap::Parser;\n    use orx_parallel::{IntoParIter, ParIter, generic_iterator::GenericIterator};\n    use rayon::iter::{IntoParallelIterator, ParallelIterator};\n    use std::fmt::Display;\n    use utils::timed_reduce_all;\n\n    #[derive(Parser, Debug)]\n    struct Args {\n        /// Number of items in the input iterator.\n        #[arg(long, default_value_t = 100000)]\n        len: usize,\n        /// Number of repetitions to measure time; total time will be reported.\n        #[arg(long, default_value_t = 100)]\n        num_repetitions: usize,\n    }\n\n    #[derive(Parser, Debug, Clone, Copy)]\n    enum FindWhen {\n        Early,\n        Middle,\n        Late,\n        Never,\n    }\n\n    impl Display for FindWhen {\n        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n            match self {\n                FindWhen::Early => write!(f, \"at the BEGINNING of the iterator\"),\n                FindWhen::Middle => write!(f, \"in the MIDDLE of the iterator\"),\n                FindWhen::Late => write!(f, \"at the END of the iterator\"),\n                FindWhen::Never => write!(f, \"is NOT in the iterator\"),\n            }\n        }\n    }\n\n    fn get_find(n: usize, find_when: FindWhen) -> impl Fn(&String) -> bool + Send + Sync + Clone {\n        move |x| match find_when {\n            FindWhen::Early => x.starts_with(\"3\"),\n            FindWhen::Middle => match x.parse::<usize>() {\n                Ok(number) => number > n / 2,\n                _ => false,\n            },\n            FindWhen::Late => match x.parse::<usize>() {\n                Ok(number) => number > n * 10 / 9,\n                _ => false,\n            },\n            FindWhen::Never => x.starts_with(\"x\"),\n        }\n    }\n\n    fn compute(\n        find: impl Fn(&String) -> bool + Send + Sync + Clone,\n        iter: GenericIterator<\n            usize,\n            impl Iterator<Item = usize>,\n            impl ParallelIterator<Item = usize>,\n            impl ParIter<Item = usize>,\n        >,\n    ) -> String {\n        iter.map(|x| x.to_string())\n            .filter_map(|x| (!x.starts_with('1')).then_some(x))\n            .flat_map(|x| [format!(\"{}!\", &x), x])\n            .filter(|x| !x.starts_with('2'))\n            .filter_map(|x| (!x.ends_with(\"!\")).then_some(x))\n            .find_any(find)\n            .unwrap_or_default()\n    }\n\n    let args = Args::parse();\n    let find_when = [\n        FindWhen::Early,\n        FindWhen::Middle,\n        FindWhen::Late,\n        FindWhen::Never,\n    ];\n\n    let input = move || (0..args.len as usize).collect::<Vec<_>>();\n\n    for when in find_when {\n        let find = move || get_find(args.len, when);\n\n        let computations: Vec<(&str, Box<dyn Fn() -> String>)> = vec![\n            (\n                \"sequential\",\n                Box::new(move || compute(find(), GenericIterator::sequential(input().into_iter()))),\n            ),\n            (\n                \"rayon\",\n                Box::new(move || compute(find(), GenericIterator::rayon(input().into_par_iter()))),\n            ),\n            (\n                \"orx\",\n                Box::new(move || compute(find(), GenericIterator::orx(input().into_par()))),\n            ),\n        ];\n\n        timed_reduce_all(\n            &format!(\"find any of the items that is {}\", when),\n            args.num_repetitions,\n            None,\n            &computations,\n        );\n    }\n}\n"
  },
  {
    "path": "examples/benchmark_heterogeneous.rs",
    "content": "mod utils;\n\n#[cfg(not(feature = \"generic_iterator\"))]\nfn main() {\n    panic!(\n        r#\"\n\nREQUIRES FEATURE: generic_iterator\n\nTo view the arguments:\ncargo run --release --features generic_iterator --example benchmark_heterogeneous -- --help\n\nTo run with default arguments:\ncargo run --release --features generic_iterator --example benchmark_heterogeneous\n\nTo run with desired arguments:\ncargo run --release --features generic_iterator --example benchmark_heterogeneous -- --len 123456 --num-repetitions 10\n\nPlay with the transformations inside the compute method to test out different computations.\n\n\"#\n    );\n}\n\n#[cfg(feature = \"generic_iterator\")]\nfn main() {\n    use clap::Parser;\n    use orx_parallel::{IntoParIter, ParIter, generic_iterator::GenericIterator};\n    use rand::prelude::*;\n    use rand_chacha::ChaCha8Rng;\n    use rayon::iter::{IntoParallelIterator, ParallelIterator};\n    use utils::timed_reduce_all;\n\n    #[derive(Parser, Debug)]\n    struct Args {\n        /// Number of items in the input iterator.\n        #[arg(long, default_value_t = 2000)]\n        len: usize,\n        /// Number of repetitions to measure time; total time will be reported.\n        #[arg(long, default_value_t = 100)]\n        num_repetitions: usize,\n    }\n\n    fn fibonacci(n: &u64) -> u64 {\n        let mut a = 0;\n        let mut b = 1;\n        for _ in 0..*n {\n            let c = a + b;\n            a = b;\n            b = c;\n        }\n        a\n    }\n\n    fn heterogeneous_computation(i: usize) -> u64 {\n        let mut rng = ChaCha8Rng::seed_from_u64(i as u64);\n        for _ in 0..10 * i {\n            let _: u32 = rng.random();\n        }\n        let n = match rng.random_bool(0.75) {\n            true => rng.random_range(1..100),\n            false => rng.random_range(10000..20000),\n        };\n        fibonacci(&n)\n    }\n\n    fn compute(\n        iter: GenericIterator<\n            usize,\n            impl Iterator<Item = usize>,\n            impl ParallelIterator<Item = usize>,\n            impl ParIter<Item = usize>,\n        >,\n    ) -> u64 {\n        iter.map(heterogeneous_computation).max().unwrap()\n    }\n\n    let args = Args::parse();\n\n    let input = move || (0..args.len as usize).collect::<Vec<_>>();\n    let expected_output = compute(GenericIterator::sequential(input().into_iter()));\n\n    let computations: Vec<(&str, Box<dyn Fn() -> u64>)> = vec![\n        (\n            \"sequential\",\n            Box::new(move || compute(GenericIterator::sequential(input().into_iter()))),\n        ),\n        (\n            \"rayon\",\n            Box::new(move || compute(GenericIterator::rayon(input().into_par_iter()))),\n        ),\n        (\n            \"orx\",\n            Box::new(move || compute(GenericIterator::orx(input().into_par()))),\n        ),\n    ];\n\n    timed_reduce_all(\n        \"benchmark_heterogeneous\",\n        args.num_repetitions,\n        Some(expected_output),\n        &computations,\n    );\n}\n"
  },
  {
    "path": "examples/benchmark_pools.rs",
    "content": "// cargo run --all-features --release --example benchmark_pools\n// to run with all options:\n//\n// output:\n//\n// Args { pool_type: All, num_threads: 16, len: 100000, num_repetitions: 1000 }\n// Std => 15.912437916s\n// Sequential => 46.194610858s\n// Pond => 42.560279289s\n// Poolite => 21.422590826s\n// RayonCore => 16.227641997s\n// ScopedPool => 15.958834105s\n// ScopedThreadPool => 17.228307255s\n// Yastl => 43.914882593s\n\n// cargo run --all-features --release --example benchmark_pools -- --pool-type scoped-pool\n// to run only using scoped-pool\n//\n// output:\n//\n// Args { pool_type: ScopedPool, num_threads: 16, len: 100000, num_repetitions: 1000 }\n// ScopedPool => 16.640308686s\n\n// cargo run --all-features --release --example benchmark_pools -- --pool-type rayon-core --len 1000 --num-repetitions 10000\n// to run only using rayon-core ThreadPool, with 10000 repetitions for input size of 1000\n//\n// output:\n//\n// Args { pool_type: RayonCore, num_threads: 16, len: 1000, num_repetitions: 10000 }\n// RayonCore => 6.950370104s\n\nmod utils;\n\nfn main() {\n    #[cfg(feature = \"std\")]\n    #[cfg(feature = \"pond\")]\n    #[cfg(feature = \"poolite\")]\n    #[cfg(feature = \"rayon-core\")]\n    #[cfg(feature = \"scoped-pool\")]\n    #[cfg(feature = \"scoped_threadpool\")]\n    #[cfg(feature = \"yastl\")]\n    {\n        use clap::Parser;\n        use orx_parallel::runner::ParallelRunner;\n        use orx_parallel::*;\n        use std::hint::black_box;\n        use std::num::NonZeroUsize;\n        use std::time::SystemTime;\n\n        #[derive(Parser, Debug)]\n        struct Args {\n            /// Type of the thread pool to be used for computations.\n            #[arg(long, default_value_t, value_enum)]\n            pool_type: PoolType,\n            /// Number of threads.\n            #[arg(long, default_value_t = NonZeroUsize::new(16).unwrap())]\n            num_threads: NonZeroUsize,\n            /// Number of items in the input iterator.\n            #[arg(long, default_value_t = 100000)]\n            len: usize,\n            /// Number of repetitions to measure time; total time will be reported.\n            #[arg(long, default_value_t = 100)]\n            num_repetitions: usize,\n        }\n\n        #[derive(clap::ValueEnum, Clone, Copy, Default, Debug)]\n        enum PoolType {\n            Std,\n            Sequential,\n            Pond,\n            Poolite,\n            RayonCore,\n            ScopedPool,\n            ScopedThreadPool,\n            Yastl,\n            #[default]\n            All,\n        }\n\n        impl PoolType {\n            fn run_single(self, nt: usize, reps: usize, input: &[usize], expected: &[String]) {\n                let now = SystemTime::now();\n                let result = match self {\n                    Self::Std => run_std(nt, reps, input),\n                    Self::Sequential => run_sequential(nt, reps, input),\n                    Self::Pond => run_pond(nt, reps, input),\n                    Self::Poolite => run_poolite(nt, reps, input),\n                    Self::RayonCore => run_rayon_core(nt, reps, input),\n                    Self::ScopedPool => run_scoped_pool(nt, reps, input),\n                    Self::ScopedThreadPool => run_scoped_threadpool(nt, reps, input),\n                    Self::Yastl => run_yastl(nt, reps, input),\n                    Self::All => panic!(\"all is handled by run_all\"),\n                };\n                let elapsed = now.elapsed().unwrap();\n                println!(\"{self:?} => {elapsed:?}\");\n                assert_eq!(expected, result);\n            }\n\n            fn run_all(nt: usize, reps: usize, input: &[usize], expected: &[String]) {\n                Self::Std.run_single(nt, reps, input, expected);\n                Self::Sequential.run_single(nt, reps, input, expected);\n                Self::Pond.run_single(nt, reps, input, expected);\n                Self::Poolite.run_single(nt, reps, input, expected);\n                Self::RayonCore.run_single(nt, reps, input, expected);\n                Self::ScopedPool.run_single(nt, reps, input, expected);\n                Self::ScopedThreadPool.run_single(nt, reps, input, expected);\n                Self::Yastl.run_single(nt, reps, input, expected);\n            }\n\n            fn run(self, nt: usize, reps: usize, input: &[usize], expected: &[String]) {\n                match self {\n                    Self::All => Self::run_all(nt, reps, input, expected),\n                    _ => self.run_single(nt, reps, input, expected),\n                }\n            }\n        }\n\n        fn run_with_runner<R: ParallelRunner>(\n            mut runner: R,\n            num_threads: usize,\n            num_repetitions: usize,\n            input: &[usize],\n        ) -> Vec<String> {\n            let mut dummy = vec![];\n            let mut result = vec![];\n            for i in 0..num_repetitions {\n                result = black_box(\n                    input\n                        .par()\n                        .num_threads(num_threads)\n                        .with_runner(&mut runner)\n                        .flat_map(|x| {\n                            [\n                                *x,\n                                fibonacci(x % 10),\n                                fibonacci(x % 21),\n                                fibonacci(x % 17),\n                                fibonacci(x % 33),\n                                fibonacci(x % 21),\n                            ]\n                        })\n                        .map(|x| 3 * x)\n                        .filter(|x| !(100..150).contains(x))\n                        .map(|x| x.to_string())\n                        .collect(),\n                );\n                if i < num_repetitions.min(result.len()) {\n                    dummy.push(result[i].clone())\n                };\n            }\n            for i in 0..dummy.len() {\n                assert_eq!(&dummy[i], &result[i]);\n            }\n            result\n        }\n\n        fn fibonacci(n: usize) -> usize {\n            let mut a = 0;\n            let mut b = 1;\n            for _ in 0..n {\n                let c = a + b;\n                a = b;\n                b = c;\n            }\n            a\n        }\n\n        fn run_std(num_threads: usize, num_repetitions: usize, input: &[usize]) -> Vec<String> {\n            let mut runner = DefaultRunner::default(); // StdRunner\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_sequential(\n            num_threads: usize,\n            num_repetitions: usize,\n            input: &[usize],\n        ) -> Vec<String> {\n            let mut runner = RunnerWithPool::from(SequentialPool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_pond(num_threads: usize, num_repetitions: usize, input: &[usize]) -> Vec<String> {\n            let mut pool = PondPool::new_threads_unbounded(num_threads);\n            let mut runner = RunnerWithPool::from(&mut pool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_poolite(num_threads: usize, num_repetitions: usize, input: &[usize]) -> Vec<String> {\n            let pool = poolite::Pool::with_builder(\n                poolite::Builder::new().min(num_threads).max(num_threads),\n            )\n            .unwrap();\n            let mut runner = RunnerWithPool::from(&pool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_rayon_core(\n            num_threads: usize,\n            num_repetitions: usize,\n            input: &[usize],\n        ) -> Vec<String> {\n            let pool = rayon_core::ThreadPoolBuilder::new()\n                .num_threads(num_threads)\n                .build()\n                .unwrap();\n            let mut runner = RunnerWithPool::from(&pool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_scoped_pool(\n            num_threads: usize,\n            num_repetitions: usize,\n            input: &[usize],\n        ) -> Vec<String> {\n            let pool = scoped_pool::Pool::new(num_threads);\n            let mut runner = RunnerWithPool::from(&pool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_scoped_threadpool(\n            num_threads: usize,\n            num_repetitions: usize,\n            input: &[usize],\n        ) -> Vec<String> {\n            let mut pool = scoped_threadpool::Pool::new(num_threads as u32);\n            let mut runner = RunnerWithPool::from(&mut pool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        fn run_yastl(num_threads: usize, num_repetitions: usize, input: &[usize]) -> Vec<String> {\n            let pool = YastlPool::new(num_threads);\n            let mut runner = RunnerWithPool::from(&pool);\n            run_with_runner(&mut runner, num_threads, num_repetitions, input)\n        }\n\n        let args = Args::parse();\n        println!(\"{args:?}\");\n\n        let input: Vec<_> = (0..args.len as usize).collect::<Vec<_>>();\n        let expected: Vec<_> = input\n            .iter()\n            .flat_map(|x| {\n                [\n                    *x,\n                    fibonacci(x % 10),\n                    fibonacci(x % 21),\n                    fibonacci(x % 17),\n                    fibonacci(x % 33),\n                    fibonacci(x % 21),\n                ]\n            })\n            .map(|x| 3 * x)\n            .filter(|x| !(100..150).contains(x))\n            .map(|x| x.to_string())\n            .collect();\n\n        args.pool_type.run(\n            args.num_threads.into(),\n            args.num_repetitions,\n            &input,\n            &expected,\n        );\n    }\n}\n"
  },
  {
    "path": "examples/benchmark_reduce.rs",
    "content": "mod utils;\n\n#[cfg(not(feature = \"generic_iterator\"))]\nfn main() {\n    panic!(\n        r#\"\n\nREQUIRES FEATURE: generic_iterator\n\nTo view the arguments:\ncargo run --release --features generic_iterator --example benchmark_reduce -- --help\n\nTo run with default arguments:\ncargo run --release --features generic_iterator --example benchmark_reduce\n\nTo run with desired arguments:\ncargo run --release --features generic_iterator --example benchmark_reduce -- --len 123456 --num-repetitions 10\n\nPlay with the transformations inside the compute method to test out different computations.\n\n\"#\n    );\n}\n\n#[cfg(feature = \"generic_iterator\")]\nfn main() {\n    use clap::Parser;\n    use orx_parallel::{IntoParIter, ParIter, generic_iterator::GenericIterator};\n    use rayon::iter::{IntoParallelIterator, ParallelIterator};\n    use utils::timed_reduce_all;\n\n    #[derive(Parser, Debug)]\n    struct Args {\n        /// Number of items in the input iterator.\n        #[arg(long, default_value_t = 100000)]\n        len: usize,\n        /// Number of repetitions to measure time; total time will be reported.\n        #[arg(long, default_value_t = 100)]\n        num_repetitions: usize,\n    }\n\n    fn reduce(a: usize, b: usize) -> usize {\n        (a + b).saturating_sub(1)\n    }\n\n    fn compute(\n        iter: GenericIterator<\n            usize,\n            impl Iterator<Item = usize>,\n            impl ParallelIterator<Item = usize>,\n            impl ParIter<Item = usize>,\n        >,\n    ) -> usize {\n        iter.map(|x| x.to_string())\n            .filter_map(|x| (!x.starts_with('1')).then_some(x))\n            .flat_map(|x| [format!(\"{}!\", &x), x])\n            .filter(|x| !x.starts_with('2'))\n            .filter_map(|x| x.parse::<u64>().ok())\n            .map(|x| x.to_string().len())\n            .reduce(reduce)\n            .unwrap_or(0)\n    }\n\n    let args = Args::parse();\n\n    let input = move || (0..args.len as usize).collect::<Vec<_>>();\n    let expected_output = compute(GenericIterator::sequential(input().into_iter()));\n\n    let computations: Vec<(&str, Box<dyn Fn() -> usize>)> = vec![\n        (\n            \"sequential\",\n            Box::new(move || compute(GenericIterator::sequential(input().into_iter()))),\n        ),\n        (\n            \"rayon\",\n            Box::new(move || compute(GenericIterator::rayon(input().into_par_iter()))),\n        ),\n        (\n            \"orx\",\n            Box::new(move || compute(GenericIterator::orx(input().into_par()))),\n        ),\n    ];\n\n    timed_reduce_all(\n        \"benchmark_reduce\",\n        args.num_repetitions,\n        Some(expected_output),\n        &computations,\n    );\n}\n"
  },
  {
    "path": "examples/collection_of_results.rs",
    "content": "use orx_concurrent_option::ConcurrentOption;\nuse orx_parallel::*;\n\nconst N: usize = 10_000;\nconst IDX_BAD_INPUT: [usize; 4] = [1900, 4156, 6777, 5663];\nconst ITERATION_ORDERS: [IterationOrder; 2] = [IterationOrder::Ordered, IterationOrder::Arbitrary];\n\nfn good_input() -> Vec<String> {\n    (0..N).map(|x| x.to_string()).collect()\n}\n\nfn bad_input() -> Vec<String> {\n    (0..N)\n        .map(|x| match IDX_BAD_INPUT.contains(&x) {\n            true => format!(\"{x}!\"),\n            false => x.to_string(),\n        })\n        .collect()\n}\n\n// demonstrates an attempt to handle fallible parallel iteration manually, not so convenient\nfn collection_of_results_good_case() {\n    for iteration_order in ITERATION_ORDERS {\n        let error = ConcurrentOption::none();\n        let mut output: Vec<_> = good_input()\n            .par()\n            .iteration_order(iteration_order)\n            .map(|x| match x.parse::<usize>() {\n                Ok(x) => Some(x),\n                Err(e) => {\n                    _ = error.set_some(e);\n                    None\n                }\n            })\n            .take_while(|x| x.is_some())\n            .map(|x| x.unwrap())\n            .collect();\n\n        if iteration_order == IterationOrder::Arbitrary {\n            output.sort();\n        }\n\n        assert!(error.is_none());\n        // since no error, whilst will always be true and all results will be collected regardless of order\n        assert_eq!(output, (0..N).collect::<Vec<_>>());\n    }\n}\n\n// demonstrates an attempt to handle fallible parallel iteration manually, not so convenient\nfn collection_of_results_bad_case() {\n    for iteration_order in ITERATION_ORDERS {\n        let error = ConcurrentOption::none();\n        let mut output: Vec<_> = bad_input()\n            .par()\n            .iteration_order(iteration_order)\n            .map(|x| match x.parse::<usize>() {\n                Ok(x) => Some(x),\n                Err(e) => {\n                    _ = error.set_some(e);\n                    None\n                }\n            })\n            .take_while(|x| x.is_some())\n            .map(|x| x.unwrap())\n            .collect();\n\n        if iteration_order == IterationOrder::Arbitrary {\n            output.sort();\n        }\n\n        assert_eq!(\n            error.map(|x| x.to_string()),\n            Some(\"invalid digit found in string\".to_string())\n        );\n\n        match iteration_order {\n            IterationOrder::Ordered => {\n                // guaranteed to stop at the first error\n                assert_eq!(output, (0..IDX_BAD_INPUT[0]).collect::<Vec<_>>())\n            }\n            IterationOrder::Arbitrary => {\n                // guaranteed to stop at any of the errors and we can take more\n                // but everything before the first error are guaranteed to be in\n                for i in 0..IDX_BAD_INPUT[0] {\n                    assert!(output.contains(&i));\n                }\n            }\n        }\n    }\n}\n\n// using fallible parallel iterator instead, which directly returns the Result\nfn collect_result() {\n    let output: Result<Vec<_>, _> = good_input()\n        .par()\n        .map(|x| x.parse::<usize>())\n        .into_fallible_result()\n        .collect();\n    assert_eq!(\n        output.map_err(|x| x.to_string()),\n        Ok((0..N).collect::<Vec<_>>())\n    );\n\n    let output: Result<Vec<_>, _> = bad_input()\n        .par()\n        .map(|x| x.parse::<usize>())\n        .into_fallible_result()\n        .collect();\n    assert_eq!(\n        output.map_err(|x| x.to_string()),\n        Err(\"invalid digit found in string\".to_string())\n    );\n}\n\nfn main() {\n    collection_of_results_good_case();\n    collection_of_results_bad_case();\n    collect_result();\n}\n"
  },
  {
    "path": "examples/function_composition_with_mut_using.rs",
    "content": "use clap::Parser;\nuse core::cell::UnsafeCell;\n\n/*\nThis example demonstrates potential issues found by miri with different versions of actually dong exactly\nthe same thing:\n\n* We compose functions which use a mutable reference to a variable.\n* These functions access the value sequentially. We do not have a race condition.\n* However, due to complexity of function composition with mutable lifetimes, we are unable to represent\n  the correctness of the composition with mutable references.\n* Miri remarks the problem since multiple closures hold a mutable reference to the same value. This is\n  correct and a potential race-condition risk in multi-threaded scenarios.\n* On the other hand, using transformation guarantees to send one clone of the used value to each one of\n  the thread which is then used sequentially.\n\nThis example demonstrates and tests different approaches which would avoid having multiple mutable\nreferences and fix the Miri error.\n\nThe versions implemented and tested are as follows:\n\ncargo +nightly miri run --example function_composition_with_mut_using -- --version mut-ref-unsafe-lt1\n> fails\n\ncargo +nightly miri run --example function_composition_with_mut_using -- --version mut-ref-unsafe-lt2\n> fails\n\ncargo +nightly miri run --example function_composition_with_mut_using -- --version unsafe-cell-on-reduce\n> fails\n\ncargo +nightly miri run --example function_composition_with_mut_using -- --version unsafe-cell-on-all\n> passes\n\ncargo +nightly miri run --example function_composition_with_mut_using -- --version clone\n> passes\n\ncargo +nightly miri run --example function_composition_with_mut_using -- --version raw-ptr-all\n> passes\n\n*/\n\n// # FAIL - mut ref & unsafe - 1\n\nfn compose_mut_ref_unsafe_1<T, U, X, I, R>(\n    xap1: X,\n    reduce1: R,\n) -> impl FnOnce(&mut U, T) -> Option<T>\nwhere\n    X: Fn(&mut U, T) -> I + Clone,\n    R: Fn(&mut U, T, T) -> T + Clone,\n    I: IntoIterator<Item = T> + Default,\n{\n    move |u: &mut U, x: T| {\n        let xap1 = xap1.clone();\n        let u2 = unsafe {\n            &mut *{\n                let p: *mut U = u;\n                p\n            }\n        };\n        let first = xap1(u, x);\n        first.into_iter().reduce(|x, y| reduce1(u2, x, y))\n    }\n}\n\nfn test_mut_ref_unsafe_1() {\n    let xap1 = |u: &mut String, x: i32| {\n        u.push('1');\n        [x, x + 2]\n    };\n\n    let reduce1 = |u: &mut String, x: i32, y: i32| {\n        u.push('2');\n        x + y\n    };\n\n    let composed = compose_mut_ref_unsafe_1(xap1, reduce1);\n\n    let mut s = String::new();\n    let result = composed(&mut s, 12);\n    dbg!(result, &s);\n\n    assert_eq!(result, Some(26));\n}\n\n// # FAIL - mut ref & unsafe - 2\n\nfn compose_mut_ref_unsafe_2<T, U, M, X, I, R>(\n    map1: M,\n    xap1: X,\n    reduce1: R,\n) -> impl FnOnce(&mut U, T) -> Option<T>\nwhere\n    M: Fn(&mut U, T) -> T + Clone,\n    X: Fn(&mut U, T) -> I + Clone,\n    I: IntoIterator<Item = T> + Default,\n    R: Fn(&mut U, T, T) -> T + Clone,\n    U: 'static,\n{\n    let xap_map = move |u: &mut U, x: T| {\n        let u2 = unsafe {\n            &mut *{\n                let p: *mut U = u;\n                p\n            }\n        };\n        let first = xap1(u, x);\n        first.into_iter().map(move |x| map1(u2, x))\n    };\n\n    move |u: &mut U, x: T| {\n        let values = xap_map(u, x);\n        values.reduce(|x, y| reduce1(u, x, y))\n    }\n}\n\nfn test_mut_ref_unsafe_2() {\n    let map1 = |u: &mut String, x: i32| {\n        u.push('0');\n        x + 1\n    };\n\n    let xap1 = |u: &mut String, x: i32| {\n        u.push('1');\n        [x, x + 2]\n    };\n\n    let reduce1 = |u: &mut String, x: i32, y: i32| {\n        u.push('2');\n        x + y\n    };\n\n    let composed = compose_mut_ref_unsafe_2(map1, xap1, reduce1);\n\n    let mut s = String::new();\n    let result = composed(&mut s, 12);\n    dbg!(result, &s);\n\n    assert_eq!(result, Some(28));\n}\n\n// # FAIL - UnsafeCell reduce\n\nfn compose_unsafe_cell_on_reduce<T, U, M, X, I, R>(\n    map1: M,\n    xap1: X,\n    reduce1: R,\n) -> impl FnOnce(&UnsafeCell<U>, T) -> Option<T>\nwhere\n    M: Fn(&mut U, T) -> T + Clone,\n    X: Fn(&mut U, T) -> I + Clone,\n    I: IntoIterator<Item = T> + Default,\n    R: Fn(&mut U, T, T) -> T + Clone,\n    U: 'static,\n{\n    let xap_map = move |u: &mut U, x: T| {\n        let u2 = unsafe {\n            &mut *{\n                let p: *mut U = u;\n                p\n            }\n        };\n        let first = xap1(u, x);\n        first.into_iter().map(move |x| map1(u2, x))\n    };\n\n    move |u: &UnsafeCell<U>, x: T| {\n        let values = xap_map(unsafe { &mut *u.get() }, x);\n        values.reduce(|x, y| reduce1(unsafe { &mut *u.get() }, x, y))\n    }\n}\n\nfn test_unsafe_cell_on_reduce() {\n    let map1 = |u: &mut String, x: i32| {\n        u.push('0');\n        x + 1\n    };\n\n    let xap1 = |u: &mut String, x: i32| {\n        u.push('1');\n        [x, x + 2]\n    };\n\n    let reduce1 = |u: &mut String, x: i32, y: i32| {\n        u.push('2');\n        x + y\n    };\n\n    let composed = compose_unsafe_cell_on_reduce(map1, xap1, reduce1);\n\n    let s = UnsafeCell::new(String::new());\n    let result = composed(&s, 12);\n    dbg!(result, &s);\n\n    assert_eq!(result, Some(28));\n}\n\n// # PASS - UnsafeCell everything\n\nfn compose_unsafe_cell_on_all<T, U, M, X, I, R>(\n    map1: M,\n    xap1: X,\n    reduce1: R,\n) -> impl FnOnce(&UnsafeCell<U>, T) -> Option<T>\nwhere\n    M: Fn(&mut U, T) -> T + Clone,\n    X: Fn(&mut U, T) -> I + Clone,\n    I: IntoIterator<Item = T> + Default,\n    R: Fn(&mut U, T, T) -> T + Clone,\n    U: 'static,\n{\n    let map2 = move |u: &UnsafeCell<U>, x: T| map1(unsafe { &mut *u.get() }, x);\n\n    let xap_map = move |u: &UnsafeCell<U>, x: T| {\n        let u2 = unsafe {\n            &*{\n                let p: *const UnsafeCell<_> = u;\n                p\n            }\n        };\n        let first = xap1(unsafe { &mut *u.get() }, x);\n        first.into_iter().map(move |x| map2(u2, x))\n    };\n\n    move |u: &UnsafeCell<U>, x: T| {\n        let values = xap_map(u, x);\n        values.reduce(|x, y| reduce1(unsafe { &mut *u.get() }, x, y))\n    }\n}\n\nfn test_unsafe_cell_on_all() {\n    let map1 = |u: &mut String, x: i32| {\n        u.push('0');\n        x + 1\n    };\n\n    let xap1 = |u: &mut String, x: i32| {\n        u.push('1');\n        [x, x + 2]\n    };\n\n    let reduce1 = |u: &mut String, x: i32, y: i32| {\n        u.push('2');\n        x + y\n    };\n\n    let composed = compose_unsafe_cell_on_all(map1, xap1, reduce1);\n\n    let s = UnsafeCell::new(String::new());\n    let result = composed(&s, 12);\n    dbg!(result, &s);\n\n    assert_eq!(result, Some(28));\n}\n\n// # PASS - clone\n\nfn compose_clone<T, U, X, I, R>(xap1: X, reduce1: R) -> impl FnOnce(&mut U, T) -> Option<T>\nwhere\n    U: Clone,\n    X: Fn(&mut U, T) -> I + Clone,\n    R: Fn(&mut U, T, T) -> T + Clone,\n    I: IntoIterator<Item = T> + Default,\n{\n    move |u: &mut U, x: T| {\n        let xap1 = xap1.clone();\n        let u2 = &mut u.clone();\n        let first = xap1(u, x);\n        first.into_iter().reduce(|x, y| reduce1(u2, x, y))\n    }\n}\n\nfn test_clone() {\n    let xap1 = |u: &mut String, x: i32| {\n        u.push('1');\n        [x, x + 2]\n    };\n\n    let reduce1 = |u: &mut String, x: i32, y: i32| {\n        u.push('2');\n        x + y\n    };\n\n    let composed = compose_clone(xap1, reduce1);\n\n    let mut s = String::new();\n    let result = composed(&mut s, 12);\n    dbg!(result, &s);\n\n    assert_eq!(result, Some(26));\n}\n\n// # PASS - raw-ptr\n\nfn compose_raw_ptr_all<T, U, M, X, I, R>(\n    map1: M,\n    xap1: X,\n    reduce1: R,\n) -> impl FnOnce(*mut U, T) -> Option<T>\nwhere\n    M: Fn(&mut U, T) -> T + Clone,\n    X: Fn(&mut U, T) -> I + Clone,\n    I: IntoIterator<Item = T> + Default,\n    R: Fn(&mut U, T, T) -> T + Clone,\n    U: 'static,\n{\n    let map2 = move |u: *mut U, x: T| map1(unsafe { &mut *u }, x);\n\n    let xap_map = move |u: *mut U, x: T| {\n        let first = xap1(unsafe { &mut *u }, x);\n        first.into_iter().map(move |x| map2(unsafe { &mut *u }, x))\n    };\n\n    move |u: *mut U, x: T| {\n        let values = xap_map(u, x);\n        values.reduce(|x, y| reduce1(unsafe { &mut *u }, x, y))\n    }\n}\n\nfn test_raw_ptr_all() {\n    let map1 = |u: &mut String, x: i32| {\n        u.push('0');\n        x + 1\n    };\n\n    let xap1 = |u: &mut String, x: i32| {\n        u.push('1');\n        [x, x + 2]\n    };\n\n    let reduce1 = |u: &mut String, x: i32, y: i32| {\n        u.push('2');\n        x + y\n    };\n\n    let composed = compose_raw_ptr_all(map1, xap1, reduce1);\n\n    let mut s = String::new();\n    let result = composed(&mut s as *mut String, 12);\n    dbg!(result, &s);\n\n    assert_eq!(result, Some(28));\n}\n\n#[derive(clap::ValueEnum, Clone, Copy, Debug)]\nenum Version {\n    MutRefUnsafeLt1,\n    MutRefUnsafeLt2,\n    UnsafeCellOnReduce,\n    UnsafeCellOnAll,\n    Clone,\n    RawPtrAll,\n}\n\n#[derive(Parser, Debug)]\nstruct Args {\n    /// Version of function composition to run and test with miri.\n    #[arg(long, value_enum)]\n    version: Version,\n}\n\nfn main() {\n    let args = Args::parse();\n    println!(\"{args:?}\");\n\n    match args.version {\n        Version::MutRefUnsafeLt1 => test_mut_ref_unsafe_1(),\n        Version::MutRefUnsafeLt2 => test_mut_ref_unsafe_2(),\n        Version::UnsafeCellOnReduce => test_unsafe_cell_on_reduce(),\n        Version::UnsafeCellOnAll => test_unsafe_cell_on_all(),\n        Version::Clone => test_clone(),\n        Version::RawPtrAll => test_raw_ptr_all(),\n    }\n}\n\n// mut-ref-unsafe-lt1, mut-ref-unsafe-lt2, unsafe-cell-on-reduce, unsafe-cell-on-all, clone, raw-ptr-all\n"
  },
  {
    "path": "examples/map_while.rs",
    "content": "use orx_parallel::*;\n\nconst N: usize = 10_000;\nconst IDX_BAD_INPUT: [usize; 4] = [1900, 4156, 6777, 5663];\n\nfn good_input() -> Vec<String> {\n    (0..N).map(|x| x.to_string()).collect()\n}\n\nfn bad_input() -> Vec<String> {\n    (0..N)\n        .map(|x| match IDX_BAD_INPUT.contains(&x) {\n            true => format!(\"{x}!\"),\n            false => x.to_string(),\n        })\n        .collect()\n}\n\nfn main() {\n    let result: Vec<_> = good_input()\n        .par()\n        .map_while(|x| x.parse::<usize>().ok())\n        .collect();\n    assert_eq!(result, (0..N).collect::<Vec<_>>());\n\n    let result: Vec<_> = bad_input()\n        .par()\n        .map_while(|x| x.parse::<usize>().ok()) // maps until 1900\n        .collect();\n    assert_eq!(result, (0..IDX_BAD_INPUT[0]).collect::<Vec<_>>());\n}\n"
  },
  {
    "path": "examples/max_num_threads_config.rs",
    "content": "/*\n1. to run the computation without any limits on max number of threads:\ncargo run --release --example max_num_threads_config\nOR\nORX_PARALLEL_MAX_NUM_THREADS=0 cargo run --release --example max_num_threads_config\n\n2. to allow parallel computation at most 4 threads:\nORX_PARALLEL_MAX_NUM_THREADS=4 cargo run --release --example max_num_threads_config\n*/\n\nuse orx_parallel::*;\n\nfn fib(n: &u64) -> u64 {\n    // just some work\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..*n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\n// A: what should name of the variable be?\nconst MAX_NUM_THREADS_ENV_VARIABLE: &str = \"ORX_PARALLEL_MAX_NUM_THREADS\";\n\nfn max_num_threads_by_env_variable() -> Option<usize> {\n    match std::env::var(MAX_NUM_THREADS_ENV_VARIABLE) {\n        Ok(s) => match s.parse::<usize>() {\n            Ok(0) => None,\n            Ok(x) => Some(x),\n            Err(_e) => None,\n        },\n        Err(_e) => None,\n    }\n}\n\nfn main() {\n    match max_num_threads_by_env_variable() {\n        Some(x) => {\n            println!(\n                \"Environment variable {MAX_NUM_THREADS_ENV_VARIABLE} is set to {x}\\n -> this will be the hard limit on the maximum number of threads that can be used by parallelization\"\n            )\n        }\n        None => {\n            println!(\n                \"Environment variable {MAX_NUM_THREADS_ENV_VARIABLE} is not set\\n -> all available threads might be used\"\n            )\n        }\n    }\n\n    let n = 1 << 31;\n    let input = 0..n;\n\n    // default -> might use all threads\n    let sum = input.par().map(|i| fib(&(i as u64 % 42)) % 42).sum();\n    println!(\"sum = {sum}\");\n}\n"
  },
  {
    "path": "examples/mutable_par_iter.rs",
    "content": "use orx_parallel::{\n    IntoParIter, IterIntoParIter, ParIter, ParallelizableCollection, ParallelizableCollectionMut,\n};\nuse std::collections::HashMap;\n\nconst N: usize = 1_000_000;\n\nfn mut_slice_into_par() {\n    // We create a mutable `slice` as our source: `&mut [T]`\n    //\n    // `&mut [T]` implements `IntoConcurrentIter<Item = &mut T>`\n    // => `&mut [T]` auto-implements `IntoParIter<Item = &mut T>`\n    // Therefore, we can call `slice.into_par()` to create a parallel\n    // iterator yielding mutable references consuming the `slice`.\n\n    let mut vec: Vec<_> = (0..N).collect();\n    let slice = vec.as_mut_slice();\n\n    let par = slice.into_par(); // IntoParIter on &mut [T]\n    par.filter(|x| **x != 42).for_each(|x| *x *= 0);\n\n    let sum = vec.par().sum();\n    assert_eq!(sum, 42);\n}\n\nfn vec_par_mut() {\n    // Here, we directly use the `vec` as our source: `Vec<T>`\n    //\n    // `Vec<T>` implements `ConcurrentCollectionMut<Item = T>`\n    // => `Vec<T>` auto-implements `ParallelizableCollectionMut<Item = T>`\n    // Therefore, we can call `vec.par_mut()` to create a parallel\n    // iterator yielding mutable references, using a mutable reference to `vec`.\n\n    let mut vec: Vec<_> = (0..N).collect();\n\n    let par = vec.par_mut();\n    par.filter(|x| **x != 42).for_each(|x| *x *= 0);\n\n    let sum = vec.par().sum();\n    assert_eq!(sum, 42);\n}\n\nfn iter_mut_into_par() {\n    // Finally, here we convert any mutable iterator into a parallel iterator.\n    //\n    // `Iterator<Item = &mut T>` implements `IterIntoConcurrentIter<Item = &mut T>`.\n    // => `Iterator<Item = &mut T>` auto-implements `IterIntoParIter<Item = &mut T>`\n    // Therefore, we can call `iter.iter_into_par()` to create a parallel\n    // iterator yielding mutable references.\n\n    let mut map: HashMap<_, _> = (0..N).map(|x| (10 * x, x)).collect();\n    let iter = map.values_mut();\n\n    let par = iter.iter_into_par();\n    par.filter(|x| **x != 42).for_each(|x| *x *= 0);\n\n    let sum = map.values().iter_into_par().sum();\n    assert_eq!(sum, 42);\n}\n\nfn main() {\n    mut_slice_into_par();\n    vec_par_mut();\n    iter_mut_into_par();\n}\n"
  },
  {
    "path": "examples/par_merge_sorted.rs",
    "content": "#[cfg(not(feature = \"experiment\"))]\nfn main() {\n    panic!(\"REQUIRES FEATURE: experiment\");\n}\n\n#[cfg(feature = \"experiment\")]\nfn main() {\n    use clap::Parser;\n    use orx_parallel::{\n        DefaultRunner,\n        experiment::{\n            algorithms::merge_sorted_slices::{\n                par::{ParamsParMergeSortedSlices, PivotSearch, par_merge},\n                seq::{ParamsSeqMergeSortedSlices, StreakSearch, seq_merge},\n            },\n            data_structures::{slice_dst::SliceDst, slice_src::SliceSrc},\n        },\n    };\n    use rand::prelude::*;\n    use rand_chacha::ChaCha8Rng;\n    use std::{cell::UnsafeCell, time::Instant};\n\n    type X = usize;\n\n    fn elem(i: usize) -> X {\n        i\n    }\n\n    #[inline(always)]\n    fn is_leq(a: &X, b: &X) -> bool {\n        a < b\n    }\n\n    fn new_vec<T: Ord>(len: usize, elem: impl Fn(usize) -> T) -> Vec<T> {\n        let mut vec: Vec<_> = (0..len).map(elem).collect();\n\n        let num_shuffles = 10 * len;\n        let mut rng = ChaCha8Rng::seed_from_u64(42);\n        for _ in 0..num_shuffles {\n            let i = rng.random_range(0..len);\n            let j = rng.random_range(0..len);\n            vec.swap(i, j);\n        }\n        vec\n    }\n\n    fn split_to_sorted_vecs<T: Ord + Clone>(vec: &[T]) -> (Vec<T>, Vec<T>) {\n        split_at(vec, vec.len() / 2)\n    }\n\n    fn split_at<T: Ord + Clone>(vec: &[T], split_at: usize) -> (Vec<T>, Vec<T>) {\n        let (left, right) = vec.split_at(split_at);\n        let mut left = left.to_vec();\n        let mut right = right.to_vec();\n        left.sort();\n        right.sort();\n        (left, right)\n    }\n\n    struct Input {\n        left: Vec<X>,\n        right: Vec<X>,\n        target: UnsafeCell<Vec<X>>,\n    }\n\n    impl Input {\n        fn is_target_sorted(&mut self) -> bool {\n            let target = self.target.get_mut();\n            let mut sorted = target.clone();\n            sorted.sort();\n            target == &sorted\n        }\n    }\n\n    impl Drop for Input {\n        fn drop(&mut self) {\n            unsafe {\n                let target = &mut *self.target.get();\n                target.set_len(self.left.len() + self.right.len());\n                self.left.set_len(0);\n                self.right.set_len(0);\n            }\n        }\n    }\n\n    #[derive(Parser, Debug)]\n    struct Args {\n        #[arg(long, default_value_t = false)]\n        with_diagnostics: bool,\n        #[arg(long, default_value_t = 10)]\n        min_split_len_e: usize,\n        #[arg(long, default_value_t = 8)]\n        num_threads: usize,\n        #[arg(long, default_value_t = 1024)]\n        chunk_size: usize,\n        #[arg(long, default_value_t = 23)]\n        len_e: usize,\n    }\n\n    let args = Args::parse();\n\n    let Args {\n        with_diagnostics,\n        min_split_len_e,\n        num_threads,\n        chunk_size,\n        len_e,\n    } = args;\n\n    let len = 1 << len_e;\n    let min_split_len = 1 << min_split_len_e;\n    let par = num_threads != 1;\n    let vec = new_vec(len, elem);\n    let (left, right) = split_to_sorted_vecs(&vec);\n    let target = Vec::with_capacity(vec.len()).into();\n    let mut input = Input {\n        left,\n        right,\n        target,\n    };\n\n    let target = unsafe { &mut *input.target.get() };\n    let target = SliceDst::from_vec(target);\n    let left = SliceSrc::from_slice(input.left.as_slice());\n    let right = SliceSrc::from_slice(input.right.as_slice());\n    let params = ParamsParMergeSortedSlices {\n        seq_params: ParamsSeqMergeSortedSlices {\n            streak_search: StreakSearch::None,\n            put_large_to_left: true,\n        },\n        pivot_search: PivotSearch::Binary,\n        put_large_to_left: true,\n        min_split_len,\n        chunk_size,\n        num_threads,\n    };\n\n    let begin = Instant::now();\n    match par {\n        true => match with_diagnostics {\n            true => par_merge(\n                is_leq,\n                left,\n                right,\n                target,\n                &params,\n                DefaultRunner::default().with_diagnostics(),\n            ),\n            false => par_merge(\n                is_leq,\n                left,\n                right,\n                target,\n                &params,\n                DefaultRunner::default(),\n            ),\n        },\n        false => seq_merge(is_leq, left, right, target, &params.seq_params),\n    }\n    println!(\"{:?}\", begin.elapsed());\n    assert!(input.is_target_sorted());\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/collection_on_entire_tree.rs",
    "content": "use crate::run_utils::timed;\nuse orx_parallel::*;\n\ntype Node = crate::node::Node<String>;\n\npub fn run(root: &Node) {\n    println!(\"\\n\\n\\n\\n\");\n    println!(\n        r#\"# COLLECTION ON ENTIRE TREE\n        \nThis example is almost the same as the \"reduction\" example.\n\nThe only difference is that instead of computing the some of mapped values,\nwe collect all mapped values in a vector.\n\nThis demonstrates the fact that a \"parallel recursive iterator\" is nothing but\na \"parallel iterator\" with access to all `ParIter` methods.\n\nIn order to change the computation from reduction to collection,\nall we need to do is to change\n\n[root].into_par_rec(extend).map(compute).sum()\n\ninto\n\n[root].into_par_rec(extend).map(compute).collect()\n    \"#\n    );\n\n    let log = |vec: Vec<u64>| println!(\"  collection-len = {:?}\", vec.len());\n\n    timed(\"sequential\", || sequential(root), log);\n    timed(\"orx_rec\", || orx_rec(root), log);\n    timed(\"orx_rec_linearized\", || orx_rec_linearized(root), log);\n    timed(\"orx_rec_exact\", || orx_rec_exact(root), log);\n\n    println!();\n}\n\n/// Just a demo computation we perform for each node.\nfn compute(node: &Node) -> u64 {\n    crate::run_utils::compute(node.data.parse::<u64>().unwrap())\n}\n\n/// # sequential\n///\n/// This is a recursive sequential implementation to compute and reduce values of\n/// all nodes descending from the root.\nfn sequential(root: &Node) -> Vec<u64> {\n    fn seq_compute_node(node: &Node, result: &mut Vec<u64>) {\n        let node_value = compute(node);\n        result.push(node_value);\n\n        for child in &node.children {\n            seq_compute_node(child, result);\n        }\n    }\n\n    let mut result = vec![];\n    seq_compute_node(root, &mut result);\n    result\n}\n\n/// # orx-parallel: parallel recursive iterator with unknown length\n///\n/// Here we parallelize by providing the `extend` function.\n///\n/// Although we don't use it here, please consider `chunk_size`\n/// optimization depending on the data whenever necessary. This might\n/// be more important in non-linear data structures compared to linear\n/// due to the dynamic nature of iteration.\nfn orx_rec(root: &Node) -> Vec<u64> {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    [root].into_par_rec(extend).map(compute).collect()\n}\n\n/// # orx-parallel: parallel recursive iterator with unknown length\n///\n/// Here we parallelize by providing the `extend` function.\n///\n/// However, rather than parallel processing over a dynamic recursive\n/// input, the iterator first flattens the tasks with the `linearize`\n/// call and then operates on it as if it is over a linear data structure.\nfn orx_rec_linearized(root: &Node) -> Vec<u64> {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    [root]\n        .into_par_rec(extend)\n        .linearize()\n        .map(compute)\n        .collect()\n}\n\n/// # orx-parallel: parallel recursive iterator with exact length\n///\n/// Here we parallelize by providing the `extend` function.\n/// Further, we precompute the total number of children and provide it while creating\n/// the parallel iterator. This is helpful to optimize parallel execution whenever\n/// it is available and cheap to compute.\n///\n/// Good thing, we can also count the number of nodes in parallel.\n///\n/// On the other hand, it is good not to keep the chunk size too large in a recursive\n/// iterator, as we limit it to 32 in the following.\nfn orx_rec_exact(root: &Node) -> Vec<u64> {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    let num_nodes = [root].into_par_rec(extend).count();\n\n    [root]\n        .into_par_rec_exact(extend, num_nodes)\n        .chunk_size(32)\n        .map(compute)\n        .collect()\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/main.rs",
    "content": "use crate::tree::Tree;\nuse clap::Parser;\nuse rand::SeedableRng;\nuse rand_chacha::ChaCha8Rng;\nuse std::sync::OnceLock;\n\nmod collection_on_entire_tree;\nmod node;\nmod reduction_on_entire_tree;\nmod reduction_on_subset_of_tree;\nmod run_utils;\nmod tree;\n\n#[derive(Parser, Debug)]\nstruct Args {\n    /// Amount of work (num times Fibonacci will be repeated).\n    #[arg(long, default_value_t = 10)]\n    amount_of_work: usize,\n}\n\npub fn amount_of_work() -> &'static usize {\n    static WORK: OnceLock<usize> = OnceLock::new();\n    WORK.get_or_init(|| Args::parse().amount_of_work)\n}\n\nfn main() {\n    let num_nodes = 100_000;\n    let out_degree = 0..100;\n\n    let mut rng = ChaCha8Rng::seed_from_u64(42);\n\n    let data = |idx: usize| idx.to_string();\n    let root = Tree::new_node(num_nodes, out_degree, data, &mut rng);\n\n    println!(\"\\nOne path from root to a leaf as an example\");\n    let mut next_node = Some(&root);\n    let mut i = 0;\n    while let Some(node) = next_node {\n        let indent: String = (0..i).map(|_| '*').collect();\n        println!(\"{indent}{node:?}\");\n        i += 1;\n        next_node = node.children.iter().max_by_key(|x| x.children.len());\n    }\n\n    println!(\"\\nTotal number of nodes = {}\", root.num_nodes());\n\n    reduction_on_entire_tree::run(&root);\n    collection_on_entire_tree::run(&root);\n    reduction_on_subset_of_tree::run(&root);\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/node.rs",
    "content": "use std::fmt::Debug;\n\npub struct Node<T> {\n    pub idx: usize,\n    pub data: T,\n    pub children: Vec<Node<T>>,\n}\n\nimpl<T> Debug for Node<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Node\")\n            .field(\"idx\", &self.idx)\n            .field(\"num_children\", &self.children.len())\n            .field(\n                \"children_idx\",\n                &self\n                    .children\n                    .iter()\n                    .take(10)\n                    .map(|x| x.idx)\n                    .collect::<Vec<_>>(),\n            )\n            .finish()\n    }\n}\n\nimpl<T> Node<T> {\n    pub fn num_nodes(&self) -> usize {\n        1 + self\n            .children\n            .iter()\n            .map(|node| node.num_nodes())\n            .sum::<usize>()\n    }\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/reduction_on_entire_tree.rs",
    "content": "use crate::run_utils::timed;\nuse orx_parallel::*;\nuse std::sync::atomic::{AtomicU64, Ordering};\n\ntype Node = crate::node::Node<String>;\n\npub fn run(root: &Node) {\n    println!(\"\\n\\n\\n\\n\");\n    println!(\n        r#\"# REDUCTION ON ENTIRE TREE\n        \nThis example demonstrates parallel computation over a tree.\nUnlike parallelization over linear data structures, we don't have access to all\ninput elements, or say tasks, ahead of time.\n\nInstead, the new elements are added dynamically on the fly.\nTherefore, these iterators are called \"parallel recursive iterator\"s.\n\nIn addition to an initial set of elements, a parallel recursive iterator is\ncreated with an \"extend\" function which defines the recursive behavior.\n\nIn this example we create an iterator where elements are \"&Node\".\nWe define the \"extend\" function as follows:\n\nfn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {{\n    queue.extend(&node.children);\n}}\n\nWhile processing a particular \"node\", we add all its children to the \"queue\".\nIn this example, we use \"queue.extend\", later we will also use \"queue.push\".\n\nThis allows to express the parallel computation as simple as over a linear\ndata structure:\n\n[root].into_par_rec(extend).map(compute).sum()\n    \"#\n    );\n\n    let log = |sum: u64| println!(\"  sum = {sum}\");\n\n    timed(\"sequential\", || sequential(root), log);\n\n    // rayon miri fails with:\n    // Undefined Behavior: trying to retag from <84156795> for SharedReadWrite permission at alloc41643328[0x8],\n    // but that tag does not exist in the borrow stack for this location\n    #[cfg(not(miri))]\n    timed(\"rayon\", || rayon(root), log);\n\n    timed(\"orx_rec\", || orx_rec(root), log);\n    timed(\"orx_rec_linearized\", || orx_rec_linearized(root), log);\n    timed(\"orx_rec_exact\", || orx_rec_exact(root), log);\n\n    println!();\n}\n\n/// Just a demo computation we perform for each node.\nfn compute(node: &Node) -> u64 {\n    crate::run_utils::compute(node.data.parse::<u64>().unwrap())\n}\n\n/// # sequential\n///\n/// This is a recursive sequential implementation to compute and reduce values of\n/// all nodes descending from the root.\nfn sequential(root: &Node) -> u64 {\n    fn seq_compute_node(node: &Node) -> u64 {\n        let node_value = compute(node);\n        let child_values = node.children.iter().map(seq_compute_node);\n        node_value + child_values.sum::<u64>()\n    }\n\n    seq_compute_node(root)\n}\n\n/// # rayon: defining the computation with rayon's scoped threads.\npub fn rayon(root: &Node) -> u64 {\n    fn process_node<'scope>(sum: &'scope AtomicU64, node: &'scope Node, s: &rayon::Scope<'scope>) {\n        for child in &node.children {\n            s.spawn(move |s| {\n                process_node(sum, child, s);\n            });\n        }\n        let node_value = compute(node);\n        sum.fetch_add(node_value, Ordering::Relaxed);\n    }\n\n    let sum = AtomicU64::new(0);\n    rayon::in_place_scope(|s| {\n        process_node(&sum, root, s);\n    });\n    sum.into_inner()\n}\n\n/// # orx-parallel: parallel recursive iterator with unknown length\n///\n/// Here we parallelize by providing the `extend` function.\n///\n/// Although we don't use it here, please consider `chunk_size`\n/// optimization depending on the data whenever necessary. This might\n/// be more important in non-linear data structures compared to linear\n/// due to the dynamic nature of iteration.\nfn orx_rec(root: &Node) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    [root].into_par_rec(extend).map(compute).sum()\n}\n\n/// # orx-parallel: parallel recursive iterator with unknown length\n///\n/// Here we parallelize by providing the `extend` function.\n///\n/// However, rather than parallel processing over a dynamic recursive\n/// input, the iterator first flattens the tasks with the `linearize`\n/// call and then operates on it as if it is over a linear data structure.\nfn orx_rec_linearized(root: &Node) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    [root].into_par_rec(extend).linearize().map(compute).sum()\n}\n\n/// # orx-parallel: parallel recursive iterator with exact length\n///\n/// Here we parallelize by providing the `extend` function.\n/// Further, we precompute the total number of children and provide it while creating\n/// the parallel iterator. This is helpful to optimize parallel execution whenever\n/// it is available and cheap to compute.\n///\n/// Good thing, we can also count the number of nodes in parallel.\n///\n/// On the other hand, it is good not to keep the chunk size too large in a recursive\n/// iterator, as we limit it to 32 in the following.\nfn orx_rec_exact(root: &Node) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        queue.extend(&node.children);\n    }\n\n    let num_nodes = [root].into_par_rec(extend).count();\n\n    [root]\n        .into_par_rec_exact(extend, num_nodes)\n        .chunk_size(32)\n        .map(compute)\n        .sum()\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/reduction_on_subset_of_tree.rs",
    "content": "use crate::run_utils::timed;\nuse orx_parallel::*;\n\ntype Node = crate::node::Node<String>;\n\npub fn run(root: &Node) {\n    println!(\"\\n\\n\\n\\n\");\n    println!(\n        r#\"# REDUCTION ON SUBSET OF THE TREE\n        \nIn the previous examples we used \"queue.extend\" method to dynamically add children\nto the queue.\n\nHowever, this method requires the children to implement 'ExactSizeIterator'.\nWhen we don't have pre-allocated children, or when we apply a filter on these children,\nwe cannot always satisfy this requirement.\n\nIn these cases,\n\n* we can use `queue.push(child)` to add children one-by-one; or\n* we can collect children into a vec and then use `queue.extend(children_vec)` to add them\n  together.\n\n`queue.push` approach has the following pros and cons:\n* (+) makes new children available as soon as available.\n* (+) does not require allocation.\n* (-) might have greater parallelization overhead.\n\n`queue.extend` approach has the following pros and cons:\n* (+) will have the minimum parallelization overhead.\n* (-) requires allocation for processing each node.\n\nThese are a couple of recommendations, we can use `push` and `extend` methods in a different\nway to optimize our use case.\n    \"#\n    );\n\n    println!(\"\\n\\n\\n\\n# REDUCTION ON SUBSET OF THE TREE\");\n    let log = |sum: u64| println!(\"  sum = {sum}\");\n\n    timed(\"sequential\", || sequential(root), log);\n\n    timed(\"push_orx_rec\", || push_orx_rec(root), log);\n    timed(\n        \"collect_extend_orx_rec\",\n        || collect_extend_orx_rec(root),\n        log,\n    );\n\n    println!();\n}\n\n/// Just a demo computation we perform for each node.\nfn compute(node: &Node) -> u64 {\n    crate::run_utils::compute(node.data.parse::<u64>().unwrap())\n}\n\nfn filter(node: &&Node) -> bool {\n    !node.data.parse::<u64>().unwrap().is_multiple_of(42)\n}\n\n/// # sequential\n///\n/// This is a recursive sequential implementation to compute and reduce values of\n/// all nodes descending from the root.\nfn sequential(root: &Node) -> u64 {\n    fn seq_compute_node(node: &Node) -> u64 {\n        let node_value = compute(node);\n        let child_values = node.children.iter().filter(filter).map(seq_compute_node);\n        node_value + child_values.sum::<u64>()\n    }\n\n    seq_compute_node(root)\n}\n\n/// # orx-parallel: parallel recursive iterator with unknown length\n///\n/// Since we do not know how many children to add ahead-of-time, we\n/// don't have an ExactSizeIterator. Therefore, instead of `queue.extend`,\n/// we use `queue.push` to add new children.\n///\n/// * (+) makes new children available as soon as available.\n/// * (+) does not require allocation.\n/// * (-) might have greater parallelization overhead.\nfn push_orx_rec(root: &Node) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        for child in node.children.iter().filter(filter) {\n            queue.push(child);\n        }\n    }\n\n    [root].into_par_rec(extend).map(compute).sum()\n}\n\n/// # orx-parallel: parallel recursive iterator with unknown length\n///\n/// Alternatively, we can collect children in a vector and then call\n/// `queue.extend` to add the new children.\n///\n/// * (+) will have the minimum parallelization overhead.\n/// * (-) requires allocation for processing each node.\nfn collect_extend_orx_rec(root: &Node) -> u64 {\n    fn extend<'a>(node: &&'a Node, queue: &Queue<&'a Node>) {\n        let children: Vec<_> = node.children.iter().filter(filter).collect();\n        queue.extend(children);\n    }\n\n    [root].into_par_rec(extend).map(compute).sum()\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/run_utils.rs",
    "content": "use crate::amount_of_work;\nuse std::time::Instant;\n\npub fn timed<F, L, T>(name: &'static str, fun: F, log: L)\nwhere\n    F: Fn() -> T,\n    L: Fn(T),\n{\n    println!(\"> {name}\");\n    let start = Instant::now();\n\n    let result = fun();\n\n    let elapsed = start.elapsed();\n\n    println!(\"  elapsed = {elapsed:?}\");\n    log(result);\n    println!();\n}\n\n/// Fibonacci as example computation on each of the node values.\npub fn compute(value: u64) -> u64 {\n    (0..*amount_of_work())\n        .map(|j| {\n            let n = core::hint::black_box(value + j as u64);\n            let mut a = 0;\n            let mut b = 1;\n            for _ in 0..n {\n                let c = a + b;\n                a = b;\n                b = c;\n            }\n            a\n        })\n        .sum()\n}\n"
  },
  {
    "path": "examples/parallelization_on_tree/tree.rs",
    "content": "use crate::node::Node;\nuse rand::Rng;\nuse std::{collections::HashSet, marker::PhantomData, ops::Range};\n\npub struct Tree<T>(PhantomData<T>);\n\nimpl<T> Tree<T> {\n    pub fn new_node(\n        num_nodes: usize,\n        degree: Range<usize>,\n        data: fn(usize) -> T,\n        rng: &mut impl Rng,\n    ) -> Node<T> {\n        assert!(num_nodes >= 2);\n\n        let mut leaves = vec![0];\n        let mut remaining: Vec<_> = (1..num_nodes).collect();\n        let mut edges = vec![];\n        let mut out_edges = vec![vec![]; num_nodes];\n\n        while !remaining.is_empty() {\n            let leaf_idx = rng.random_range(0..leaves.len());\n            let leaf = leaves.remove(leaf_idx);\n\n            let degree = rng.random_range(degree.clone());\n            match degree == 0 {\n                true => leaves.push(leaf),\n                false => {\n                    let children_indices: HashSet<_> = (0..degree)\n                        .map(|_| rng.random_range(0..remaining.len()))\n                        .collect();\n\n                    let mut sorted: Vec<_> = children_indices.iter().copied().collect();\n                    sorted.sort();\n\n                    edges.extend(children_indices.iter().map(|c| (leaf, remaining[*c])));\n                    out_edges[leaf] = children_indices.iter().map(|c| remaining[*c]).collect();\n                    leaves.extend(children_indices.iter().map(|c| remaining[*c]));\n\n                    for idx in sorted.into_iter().rev() {\n                        remaining.remove(idx);\n                    }\n                }\n            }\n        }\n\n        create_node(&out_edges, 0, data)\n    }\n}\n\nfn create_node<T>(out_edges: &[Vec<usize>], idx: usize, data: fn(usize) -> T) -> Node<T> {\n    let children: Vec<_> = out_edges[idx]\n        .iter()\n        .map(|child_idx| create_node(out_edges, *child_idx, data))\n        .collect();\n    let data = data(idx);\n    Node {\n        idx,\n        data,\n        children,\n    }\n}\n"
  },
  {
    "path": "examples/using_for_each.rs",
    "content": "use orx_parallel::*;\nuse std::sync::mpsc::channel;\n\n// taken from rayon's documentation:\n// https://docs.rs/rayon/1.10.0/rayon/iter/trait.ParallelIterator.html#method.map\nfn for_each() {\n    let (sender, receiver) = channel();\n\n    (0..5)\n        .into_par()\n        .using_clone(sender)\n        .for_each(|s, x| s.send(x).unwrap());\n\n    let mut res: Vec<_> = receiver.iter().collect();\n\n    res.sort();\n\n    assert_eq!(&res[..], &[0, 1, 2, 3, 4])\n}\n\n// taken from rayon's documentation:\n// https://docs.rs/rayon/1.10.0/rayon/iter/trait.ParallelIterator.html#method.map\nfn map() {\n    let (sender, receiver) = channel();\n\n    let a: Vec<_> = (0..5)\n        .into_par() // iterating over i32\n        .using_clone(sender)\n        .map(|s, x| {\n            s.send(x).unwrap(); // sending i32 values through the channel\n            x // returning i32\n        })\n        .collect(); // collecting the returned values into a vector\n\n    let mut b: Vec<_> = receiver\n        .iter() // iterating over the values in the channel\n        .collect(); // and collecting them\n    b.sort();\n\n    assert_eq!(a, b);\n}\n\nfn main() {\n    for_each();\n    map();\n}\n"
  },
  {
    "path": "examples/using_map.rs",
    "content": "use orx_parallel::*;\nuse rand::{Rng, SeedableRng};\nuse rand_chacha::ChaCha20Rng;\nuse std::sync::atomic::{AtomicUsize, Ordering};\n\nconst N: u64 = 100_000;\n\n// just some work\nfn fibonacci(n: u64) -> u64 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\nfn using() -> u64 {\n    let input: Vec<u64> = (1..N).collect();\n\n    input\n        .into_par()\n        .using(|thread_idx| ChaCha20Rng::seed_from_u64(thread_idx as u64 * 10))\n        .map(|_, i| fibonacci((i % 50) + 1) % 100)\n        .filter(|rng: &mut ChaCha20Rng, _: &u64| rng.random_bool(0.4))\n        .map(|rng: &mut ChaCha20Rng, i: u64| rng.random_range(0..i))\n        .sum()\n}\n\nfn using_clone() -> u64 {\n    let rng = ChaCha20Rng::seed_from_u64(42);\n\n    let input: Vec<u64> = (1..N).collect();\n\n    input\n        .into_par()\n        .using_clone(rng)\n        .map(|_, i| fibonacci((i % 50) + 1) % 100)\n        .filter(|rng: &mut ChaCha20Rng, _: &u64| rng.random_bool(0.4))\n        .map(|rng: &mut ChaCha20Rng, i: u64| rng.random_range(0..i))\n        .sum()\n}\n\nfn using_clone_while_counting_clones() -> u64 {\n    static COUNTER: AtomicUsize = AtomicUsize::new(0);\n    struct Rng(ChaCha20Rng);\n    unsafe impl Send for Rng {}\n    impl Clone for Rng {\n        fn clone(&self) -> Self {\n            _ = COUNTER.fetch_add(1, Ordering::Relaxed);\n            Self(self.0.clone())\n        }\n    }\n\n    let rng = ChaCha20Rng::seed_from_u64(42);\n\n    let input: Vec<u64> = (1..N).collect();\n\n    let result = input\n        .into_par()\n        .num_threads(8)\n        .using_clone(Rng(rng))\n        .map(|_, i| fibonacci((i % 50) + 1) % 100)\n        .filter(|rng: &mut Rng, _: &u64| rng.0.random_bool(0.4))\n        .map(|rng: &mut Rng, i: u64| rng.0.random_range(0..i))\n        .sum();\n\n    let num_clones = COUNTER.load(Ordering::Relaxed);\n    println!(\"\\n> number of times RNG is cloned (= used threads) = {num_clones}\");\n\n    result\n}\n\nfn main() {\n    println!(\"\\n\\n\\n### I. using:\");\n    println!(\n        \"* Allows to create the random number generator (RNG) of each thread using a closure that takes the thread index.\"\n    );\n    println!(\"* Hence, we can guarantee to use different RNGs for each thread.\");\n    println!(\"* The following is the example 'using' transformation used in this example.\");\n    println!(\"\\n  >  par.using(|thread_idx| ChaCha20Rng::seed_from_u64(thread_idx as u64 * 10))\");\n    let parallel_result = using();\n    println!(\"\\n* result = {parallel_result}\");\n\n    println!(\"\\n\\n\\n### II. using_clone:\");\n    println!(\n        \"* With this call we create and pass in the RNG; then each thread receives a clone of it as in its initial state.\"\n    );\n    println!(\"\\n  >  par.using_clone(my_rng)\");\n    let parallel_result = using_clone();\n    println!(\"\\n* result = {parallel_result}\");\n\n    println!(\"\\n\\n\\n### III. using_clone with a hook to count number of times the RNG is cloned:\");\n    println!(\n        \"* The computation is limited to 8 threads; therefore, at most, 8 clones of the RNG must be created.\"\n    );\n    println!(\n        \"* This example demonstrates that exactly one value is created-or-cloned per thread used.\"\n    );\n    let parallel_result = using_clone_while_counting_clones();\n    println!(\"{parallel_result}\");\n    println!(\"\\n* result = {parallel_result}\");\n}\n"
  },
  {
    "path": "examples/using_metrics.rs",
    "content": "use orx_parallel::*;\nuse std::cell::UnsafeCell;\n\nconst N: u64 = 10_000_000;\nconst MAX_NUM_THREADS: usize = 8;\n\n// just some work\nfn fibonacci(n: u64) -> u64 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n\n#[derive(Default, Debug)]\nstruct ThreadMetrics {\n    thread_idx: usize,\n    num_items_handled: usize,\n    handled_42: bool,\n    num_filtered_out: usize,\n}\n\nstruct ThreadMetricsWriter<'a> {\n    metrics_ref: &'a mut ThreadMetrics,\n}\n\nstruct ComputationMetrics {\n    thread_metrics: UnsafeCell<[ThreadMetrics; MAX_NUM_THREADS]>,\n}\nimpl ComputationMetrics {\n    fn new() -> Self {\n        let mut thread_metrics: [ThreadMetrics; MAX_NUM_THREADS] = Default::default();\n        for (i, metrics) in thread_metrics.iter_mut().enumerate().take(MAX_NUM_THREADS) {\n            metrics.thread_idx = i;\n        }\n        Self {\n            thread_metrics: UnsafeCell::new(thread_metrics),\n        }\n    }\n}\n\nunsafe impl Sync for ComputationMetrics {}\n\nimpl ComputationMetrics {\n    unsafe fn create_for_thread<'a>(&self, thread_idx: usize) -> ThreadMetricsWriter<'a> {\n        // SAFETY: here we create a mutable variable to the thread_idx-th metrics\n        // * If we call this method multiple times with the same index,\n        //   we create multiple mutable references to the same ThreadMetrics,\n        //   which would lead to a race condition.\n        // * We must make sure that `create_for_thread` is called only once per thread.\n        // * If we use `create_for_thread` within the `using` call to create mutable values\n        //   used by the threads, we are certain that the parallel computation\n        //   will only call this method once per thread; hence, it will not\n        //   cause the race condition.\n        // * On the other hand, we must ensure that we do not call this method\n        //   externally.\n        let array = unsafe { &mut *self.thread_metrics.get() };\n        ThreadMetricsWriter {\n            metrics_ref: &mut array[thread_idx],\n        }\n    }\n}\n\nfn main() {\n    let mut metrics = ComputationMetrics::new();\n\n    let input: Vec<u64> = (0..N).collect();\n\n    let sum = input\n        .par()\n        // SAFETY: we do not call `create_for_thread` externally;\n        // it is safe if it is called only by the parallel computation.\n        // Since we unsafely implement Sync for ComputationMetrics,\n        // we must ensure that ComputationMetrics is not used elsewhere.\n        .using(|t| unsafe { metrics.create_for_thread(t) })\n        .map(|m: &mut ThreadMetricsWriter<'_>, i| {\n            // collect some useful metrics\n            m.metrics_ref.num_items_handled += 1;\n            m.metrics_ref.handled_42 |= *i == 42;\n\n            // actual work\n            fibonacci((*i % 50) + 1) % 100\n        })\n        .filter(|m, i| {\n            let is_even = i % 2 == 0;\n\n            if !is_even {\n                m.metrics_ref.num_filtered_out += 1;\n            }\n\n            is_even\n        })\n        .num_threads(MAX_NUM_THREADS)\n        .sum();\n\n    println!(\"\\nINPUT-LEN = {N}\");\n    println!(\"SUM = {sum}\");\n\n    println!(\"\\n\\n\");\n\n    println!(\"COLLECTED METRICS PER THREAD\");\n    for metrics in metrics.thread_metrics.get_mut().iter() {\n        println!(\"* {metrics:?}\");\n    }\n    let total_by_metrics: usize = metrics\n        .thread_metrics\n        .get_mut()\n        .iter()\n        .map(|x| x.num_items_handled)\n        .sum();\n    println!(\"\\n-> total num_items_handled by collected metrics: {total_by_metrics:?}\\n\");\n\n    assert_eq!(N as usize, total_by_metrics);\n}\n"
  },
  {
    "path": "examples/using_random_walk.rs",
    "content": "use orx_parallel::*;\nuse rand::{Rng, SeedableRng};\nuse rand_chacha::ChaCha20Rng;\n\nfn random_walk(rng: &mut impl Rng, position: i64, num_steps: usize) -> i64 {\n    (0..num_steps).fold(position, |p, _| random_step(rng, p))\n}\n\nfn random_step(rng: &mut impl Rng, position: i64) -> i64 {\n    match rng.random_bool(0.5) {\n        true => position + 1,  // to right\n        false => position - 1, // to left\n    }\n}\n\nfn input_positions() -> Vec<i64> {\n    (-10_000..=10_000).collect()\n}\n\nfn sequential() {\n    let positions = input_positions();\n    let sum_initial_positions = positions.iter().sum::<i64>();\n    println!(\"sum_initial_positions = {sum_initial_positions}\");\n\n    let mut rng = ChaCha20Rng::seed_from_u64(42);\n    let final_positions: Vec<_> = positions\n        .iter()\n        .copied()\n        .map(|position| random_walk(&mut rng, position, 100))\n        .collect();\n    let sum_final_positions = final_positions.iter().sum::<i64>();\n    println!(\"sum_final_positions = {sum_final_positions}\");\n}\n\nfn parallel() {\n    let positions = input_positions();\n    let sum_initial_positions = positions.iter().sum::<i64>();\n    println!(\"sum_initial_positions = {sum_initial_positions}\");\n\n    let final_positions: Vec<_> = positions\n        .par()\n        .copied()\n        .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64))\n        .map(|rng, position| random_walk(rng, position, 100))\n        .collect();\n    let sum_final_positions = final_positions.iter().sum::<i64>();\n    println!(\"sum_final_positions = {sum_final_positions}\");\n}\n\nfn main() {\n    println!(\"\\n\\nSEQUENTIAL\");\n    sequential();\n\n    println!(\"\\n\\nPARALLEL\");\n    parallel();\n}\n"
  },
  {
    "path": "examples/utils/benchmark_utils.rs",
    "content": "#![allow(dead_code)]\n\nuse std::{\n    fmt::Debug,\n    hint::black_box,\n    time::{Duration, SystemTime},\n};\n\n// reduce\n\nfn timed_reduce<F, O>(num_repetitions: usize, expected_output: &Option<O>, fun: F) -> Duration\nwhere\n    F: Fn() -> O,\n    O: PartialEq + Debug,\n{\n    if let Some(expected_output) = expected_output.as_ref() {\n        let result = fun();\n        assert_eq!(&result, expected_output);\n    }\n\n    // warm up\n    for _ in 0..10 {\n        let _ = black_box(fun());\n    }\n\n    // measurement\n\n    let now = SystemTime::now();\n    for _ in 0..num_repetitions {\n        let result = black_box(fun());\n        if let Some(expected_output) = expected_output.as_ref() {\n            assert_eq!(&result, expected_output);\n        }\n    }\n    now.elapsed().unwrap()\n}\n\ntype Computation<'a, O> = (&'a str, Box<dyn Fn() -> O>);\n\npub fn timed_reduce_all<O>(\n    benchmark_name: &str,\n    num_repetitions: usize,\n    expected_output: Option<O>,\n    computations: &[Computation<'_, O>],\n) where\n    O: PartialEq + Debug + Clone,\n{\n    println!(\"\\n{} {} {}\", \"#\".repeat(10), benchmark_name, \"#\".repeat(10));\n    for (name, fun) in computations {\n        let duration = timed_reduce(num_repetitions, &expected_output, fun);\n        println!(\"{:>10} : {:?}\", name, duration);\n    }\n    println!(\"{}\\n\", \"#\".repeat(10 + 10 + 2 + benchmark_name.len()));\n}\n\n// collect\n\nfn timed_collect<F, Out, O>(num_repetitions: usize, expected_output: &[O], fun: F) -> Duration\nwhere\n    F: Fn() -> Out,\n    Out: IntoIterator<Item = O>,\n    O: PartialEq + Debug,\n{\n    let result = fun();\n    assert_eq!(result.into_iter().collect::<Vec<_>>(), expected_output);\n\n    // warm up\n    for _ in 0..10 {\n        let _ = black_box(fun());\n    }\n\n    // measurement\n\n    let now = SystemTime::now();\n    for _ in 0..num_repetitions {\n        let _ = black_box(fun());\n    }\n    now.elapsed().unwrap()\n}\n\npub fn timed_collect_all<Out, O>(\n    benchmark_name: &str,\n    num_repetitions: usize,\n    expected_output: &[O],\n    computations: &[Computation<'_, Out>],\n) where\n    Out: IntoIterator<Item = O>,\n    O: PartialEq + Debug,\n{\n    println!(\"\\n{} {} {}\", \"#\".repeat(10), benchmark_name, \"#\".repeat(10));\n    for (name, fun) in computations {\n        let duration = timed_collect(num_repetitions, expected_output, fun);\n        println!(\"{:>10} : {:?}\", name, duration);\n    }\n    println!(\"{}\\n\", \"#\".repeat(10 + 10 + 2 + benchmark_name.len()));\n}\n"
  },
  {
    "path": "examples/utils/mod.rs",
    "content": "#![allow(unused_imports)]\n\nmod benchmark_utils;\n\npub use benchmark_utils::*;\n"
  },
  {
    "path": "src/collect_into/collect.rs",
    "content": "use crate::Params;\nuse crate::executor::parallel_compute as prc;\nuse crate::generic_values::runner_results::{\n    Fallibility, Infallible, ParallelCollect, ParallelCollectArbitrary, Stop,\n};\nuse crate::runner::{NumSpawned, ParallelRunner};\nuse crate::{IterationOrder, generic_values::Values};\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub fn map_collect_into<R, I, O, M1, P>(\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    map1: M1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n    O: Send,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    match (params.is_sequential(), params.iteration_order) {\n        (true, _) => (\n            NumSpawned::zero(),\n            map_collect_into_seq(iter, map1, pinned_vec),\n        ),\n        #[cfg(test)]\n        (false, IterationOrder::Arbitrary) => {\n            prc::collect_arbitrary::m(orchestrator, params, iter, map1, pinned_vec)\n        }\n        (false, _) => prc::collect_ordered::m(orchestrator, params, iter, map1, pinned_vec),\n    }\n}\n\nfn map_collect_into_seq<I, O, M1, P>(iter: I, map1: M1, mut pinned_vec: P) -> P\nwhere\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n    O: Send,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    let iter = iter.into_seq_iter();\n    for i in iter {\n        pinned_vec.push(map1(i));\n    }\n    pinned_vec\n}\n\npub fn xap_collect_into<R, I, Vo, X1, P>(\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values<Fallibility = Infallible>,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    match (params.is_sequential(), params.iteration_order) {\n        (true, _) => (\n            NumSpawned::zero(),\n            xap_collect_into_seq(iter, xap1, pinned_vec),\n        ),\n        (false, IterationOrder::Arbitrary) => {\n            let (num_threads, result) =\n                prc::collect_arbitrary::x(orchestrator, params, iter, xap1, pinned_vec);\n            let pinned_vec = match result {\n                ParallelCollectArbitrary::AllOrUntilWhileCollected { pinned_vec } => pinned_vec,\n            };\n            (num_threads, pinned_vec)\n        }\n        (false, IterationOrder::Ordered) => {\n            let (num_threads, result) =\n                prc::collect_ordered::x(orchestrator, params, iter, xap1, pinned_vec);\n            let pinned_vec = match result {\n                ParallelCollect::AllCollected { pinned_vec } => pinned_vec,\n                ParallelCollect::StoppedByWhileCondition {\n                    pinned_vec,\n                    stopped_idx: _,\n                } => pinned_vec,\n            };\n            (num_threads, pinned_vec)\n        }\n    }\n}\n\nfn xap_collect_into_seq<I, Vo, X1, P>(iter: I, xap1: X1, mut pinned_vec: P) -> P\nwhere\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let iter = iter.into_seq_iter();\n    for i in iter {\n        let vt = xap1(i);\n        let done = vt.push_to_pinned_vec(&mut pinned_vec);\n        if Vo::sequential_push_to_stop(done).is_some() {\n            break;\n        }\n    }\n\n    pinned_vec\n}\n\npub fn xap_try_collect_into<R, I, Vo, X1, P>(\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (\n    NumSpawned,\n    Result<P, <Vo::Fallibility as Fallibility>::Error>,\n)\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    match (params.is_sequential(), params.iteration_order) {\n        (true, _) => (\n            NumSpawned::zero(),\n            xap_try_collect_into_seq(iter, xap1, pinned_vec),\n        ),\n        (false, IterationOrder::Arbitrary) => {\n            let (nt, result) =\n                prc::collect_arbitrary::x(orchestrator, params, iter, xap1, pinned_vec);\n            (nt, result.into_result())\n        }\n        (false, IterationOrder::Ordered) => {\n            let (nt, result) =\n                prc::collect_ordered::x(orchestrator, params, iter, xap1, pinned_vec);\n            (nt, result.into_result())\n        }\n    }\n}\n\nfn xap_try_collect_into_seq<I, Vo, X1, P>(\n    iter: I,\n    xap1: X1,\n    mut pinned_vec: P,\n) -> Result<P, <Vo::Fallibility as Fallibility>::Error>\nwhere\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let iter = iter.into_seq_iter();\n    for i in iter {\n        let vt = xap1(i);\n        let done = vt.push_to_pinned_vec(&mut pinned_vec);\n        if let Some(stop) = Vo::sequential_push_to_stop(done) {\n            match stop {\n                Stop::DueToWhile => return Ok(pinned_vec),\n                Stop::DueToError { error } => return Err(error),\n            }\n        }\n    }\n\n    Ok(pinned_vec)\n}\n"
  },
  {
    "path": "src/collect_into/fixed_vec.rs",
    "content": "use super::par_collect_into::ParCollectIntoCore;\nuse crate::Params;\nuse crate::generic_values::runner_results::{Fallibility, Infallible};\nuse crate::generic_values::{TransformableValues, Values};\nuse crate::runner::ParallelRunner;\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::FixedVec;\n#[cfg(test)]\nuse orx_pinned_vec::PinnedVec;\n\nimpl<O> ParCollectIntoCore<O> for FixedVec<O>\nwhere\n    O: Send + Sync,\n{\n    type BridgePinnedVec = Self;\n\n    fn empty(iter_len: Option<usize>) -> Self {\n        let vec = <Vec<_> as ParCollectIntoCore<_>>::empty(iter_len);\n        vec.into()\n    }\n\n    fn m_collect_into<R, I, M1>(self, orchestrator: R, params: Params, iter: I, map1: M1) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(I::Item) -> O + Sync,\n        O: Send,\n    {\n        let vec = Vec::from(self);\n        FixedVec::from(vec.m_collect_into(orchestrator, params, iter, map1))\n    }\n\n    fn x_collect_into<R, I, Vo, X1>(\n        self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(I::Item) -> Vo + Sync,\n    {\n        let vec = Vec::from(self);\n        FixedVec::from(vec.x_collect_into(orchestrator, params, iter, xap1))\n    }\n\n    fn x_try_collect_into<R, I, Vo, X1>(\n        self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as Fallibility>::Error>\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(I::Item) -> Vo + Sync,\n        Vo: Values<Item = O>,\n    {\n        let vec = Vec::from(self);\n        vec.x_try_collect_into(orchestrator, params, iter, xap1)\n            .map(FixedVec::from)\n    }\n\n    // test\n\n    #[cfg(test)]\n    fn length(&self) -> usize {\n        self.len()\n    }\n}\n"
  },
  {
    "path": "src/collect_into/mod.rs",
    "content": "pub(crate) mod collect;\nmod fixed_vec;\nmod par_collect_into;\nmod split_vec;\npub(crate) mod utils;\nmod vec;\n\npub use par_collect_into::ParCollectInto;\npub(crate) use par_collect_into::ParCollectIntoCore;\n"
  },
  {
    "path": "src/collect_into/par_collect_into.rs",
    "content": "use crate::Params;\nuse crate::generic_values::runner_results::{Fallibility, Infallible};\nuse crate::generic_values::{TransformableValues, Values};\nuse crate::runner::ParallelRunner;\nuse crate::using::UParCollectIntoCore;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_iterable::Collection;\nuse orx_pinned_vec::IntoConcurrentPinnedVec;\n\npub trait ParCollectIntoCore<O>: Collection<Item = O> {\n    type BridgePinnedVec: IntoConcurrentPinnedVec<O>;\n\n    fn empty(iter_len: Option<usize>) -> Self;\n\n    fn m_collect_into<R, I, M1>(self, orchestrator: R, params: Params, iter: I, map1: M1) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(I::Item) -> O + Sync;\n\n    fn x_collect_into<R, I, Vo, X1>(\n        self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(I::Item) -> Vo + Sync;\n\n    fn x_try_collect_into<R, I, Vo, X1>(\n        self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as Fallibility>::Error>\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(I::Item) -> Vo + Sync,\n        Vo: Values<Item = O>,\n        Self: Sized;\n\n    // test\n\n    #[cfg(test)]\n    fn length(&self) -> usize;\n\n    #[cfg(test)]\n    fn is_empty(&self) -> bool {\n        self.length() == 0\n    }\n\n    #[cfg(test)]\n    fn is_equal_to<'a>(&self, b: impl orx_iterable::Iterable<Item = &'a O>) -> bool\n    where\n        O: PartialEq + 'a,\n    {\n        let mut b = b.iter();\n        for x in self.iter() {\n            match b.next() {\n                Some(y) if x != y => return false,\n                None => return false,\n                _ => {}\n            }\n        }\n\n        b.next().is_none()\n    }\n\n    #[cfg(test)]\n    fn is_equal_to_ref(&self, b: impl orx_iterable::Iterable<Item = O>) -> bool\n    where\n        O: PartialEq,\n    {\n        let mut b = b.iter();\n        for x in self.iter() {\n            match b.next() {\n                Some(y) if x != &y => return false,\n                None => return false,\n                _ => {}\n            }\n        }\n\n        b.next().is_none()\n    }\n}\n\n/// Collection types into which outputs of a parallel computations can be collected into.\npub trait ParCollectInto<O>: ParCollectIntoCore<O> + UParCollectIntoCore<O> {}\n\nimpl<O, C> ParCollectInto<O> for C where C: ParCollectIntoCore<O> + UParCollectIntoCore<O> {}\n"
  },
  {
    "path": "src/collect_into/split_vec.rs",
    "content": "use super::collect::{map_collect_into, xap_collect_into, xap_try_collect_into};\nuse super::par_collect_into::ParCollectIntoCore;\nuse crate::Params;\nuse crate::collect_into::utils::split_vec_reserve;\nuse crate::generic_values::runner_results::{Fallibility, Infallible};\nuse crate::generic_values::{TransformableValues, Values};\nuse crate::runner::ParallelRunner;\nuse orx_concurrent_iter::ConcurrentIter;\n#[cfg(test)]\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::{GrowthWithConstantTimeAccess, PseudoDefault, SplitVec};\n\nimpl<O, G> ParCollectIntoCore<O> for SplitVec<O, G>\nwhere\n    O: Send + Sync,\n    G: GrowthWithConstantTimeAccess,\n    Self: PseudoDefault,\n{\n    type BridgePinnedVec = Self;\n\n    fn empty(iter_len: Option<usize>) -> Self {\n        let mut vec = Self::pseudo_default();\n        split_vec_reserve(&mut vec, false, iter_len);\n        vec\n    }\n\n    fn m_collect_into<R, I, M1>(\n        mut self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        map1: M1,\n    ) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(I::Item) -> O + Sync,\n        O: Send,\n    {\n        split_vec_reserve(&mut self, params.is_sequential(), iter.try_get_len());\n        let (_, pinned_vec) = map_collect_into(orchestrator, params, iter, map1, self);\n        pinned_vec\n    }\n\n    fn x_collect_into<R, I, Vo, X1>(\n        mut self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(I::Item) -> Vo + Sync,\n    {\n        split_vec_reserve(&mut self, params.is_sequential(), iter.try_get_len());\n        let (_num_spawned, pinned_vec) = xap_collect_into(orchestrator, params, iter, xap1, self);\n        pinned_vec\n    }\n\n    fn x_try_collect_into<R, I, Vo, X1>(\n        mut self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as Fallibility>::Error>\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(I::Item) -> Vo + Sync,\n        Vo: Values<Item = O>,\n        Self: Sized,\n    {\n        split_vec_reserve(&mut self, params.is_sequential(), iter.try_get_len());\n        let (_num_spawned, result) = xap_try_collect_into(orchestrator, params, iter, xap1, self);\n        result\n    }\n\n    // test\n\n    #[cfg(test)]\n    fn length(&self) -> usize {\n        self.len()\n    }\n}\n"
  },
  {
    "path": "src/collect_into/utils.rs",
    "content": "use alloc::vec::Vec;\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::{GrowthWithConstantTimeAccess, SplitVec};\n\npub fn extend_vec_from_split<T, G>(\n    mut initial_vec: Vec<T>,\n    collected_split_vec: SplitVec<T, G>,\n) -> Vec<T>\nwhere\n    G: GrowthWithConstantTimeAccess,\n{\n    match initial_vec.len() {\n        0 => collected_split_vec.to_vec(),\n        _ => {\n            initial_vec.reserve(collected_split_vec.len());\n            initial_vec.extend(collected_split_vec);\n            initial_vec\n        }\n    }\n}\n\npub fn split_vec_reserve<T, G: GrowthWithConstantTimeAccess>(\n    split_vec: &mut SplitVec<T, G>,\n    is_sequential: bool,\n    iter_len: Option<usize>,\n) {\n    let len_to_extend = match (is_sequential, iter_len) {\n        (true, _) => None, // not required to concurrent reserve when seq\n        (false, x) => x,\n    };\n\n    match len_to_extend {\n        None => {\n            let capacity_bound = split_vec.capacity_bound();\n            split_vec.reserve_maximum_concurrent_capacity(capacity_bound)\n        }\n        Some(len) => split_vec.reserve_maximum_concurrent_capacity(split_vec.len() + len),\n    };\n}\n"
  },
  {
    "path": "src/collect_into/vec.rs",
    "content": "use super::par_collect_into::ParCollectIntoCore;\nuse crate::Params;\nuse crate::collect_into::collect::map_collect_into;\nuse crate::collect_into::utils::extend_vec_from_split;\nuse crate::generic_values::runner_results::{Fallibility, Infallible};\nuse crate::generic_values::{TransformableValues, Values};\nuse crate::runner::ParallelRunner;\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::FixedVec;\nuse orx_split_vec::SplitVec;\n\nimpl<O> ParCollectIntoCore<O> for Vec<O>\nwhere\n    O: Send + Sync,\n{\n    type BridgePinnedVec = FixedVec<O>;\n\n    fn empty(iter_len: Option<usize>) -> Self {\n        match iter_len {\n            Some(len) => Vec::with_capacity(len),\n            None => Vec::new(),\n        }\n    }\n\n    fn m_collect_into<R, I, M1>(\n        mut self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        map1: M1,\n    ) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(I::Item) -> O + Sync,\n        O: Send,\n    {\n        match iter.try_get_len() {\n            None => {\n                let split_vec = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n                let split_vec = split_vec.m_collect_into(orchestrator, params, iter, map1);\n                extend_vec_from_split(self, split_vec)\n            }\n            Some(len) => {\n                self.reserve(len);\n                let fixed_vec = FixedVec::from(self);\n                let (_, fixed_vec) = map_collect_into(orchestrator, params, iter, map1, fixed_vec);\n                Vec::from(fixed_vec)\n            }\n        }\n    }\n\n    fn x_collect_into<R, I, Vo, X1>(\n        self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(I::Item) -> Vo + Sync,\n    {\n        let split_vec = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n        let split_vec = split_vec.x_collect_into(orchestrator, params, iter, xap1);\n        extend_vec_from_split(self, split_vec)\n    }\n\n    fn x_try_collect_into<R, I, Vo, X1>(\n        self,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as Fallibility>::Error>\n    where\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(I::Item) -> Vo + Sync,\n        Vo: Values<Item = O>,\n        Self: Sized,\n    {\n        let split_vec = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n        let result = split_vec.x_try_collect_into(orchestrator, params, iter, xap1);\n        result.map(|split_vec| extend_vec_from_split(self, split_vec))\n    }\n\n    // test\n\n    #[cfg(test)]\n    fn length(&self) -> usize {\n        self.len()\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/fallible_option.rs",
    "content": "use crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParIterResult,\n    par_iter_option::{ParIterOption, ResultIntoOption},\n    runner::{DefaultRunner, ParallelRunner},\n};\nuse core::marker::PhantomData;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with None.\npub struct ParOption<F, T, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    F: ParIterResult<R, Item = T, Err = ()>,\n{\n    par: F,\n    phantom: PhantomData<(T, R)>,\n}\n\nimpl<F, T, R> ParOption<F, T, R>\nwhere\n    R: ParallelRunner,\n    F: ParIterResult<R, Item = T, Err = ()>,\n{\n    pub(crate) fn new(par: F) -> Self {\n        Self {\n            par,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<F, T, R> ParIterOption<R> for ParOption<F, T, R>\nwhere\n    R: ParallelRunner,\n    F: ParIterResult<R, Item = T, Err = ()>,\n{\n    type Item = T;\n\n    // params transformations\n\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self {\n        Self::new(self.par.num_threads(num_threads))\n    }\n\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self {\n        Self::new(self.par.chunk_size(chunk_size))\n    }\n\n    fn iteration_order(self, order: IterationOrder) -> Self {\n        Self::new(self.par.iteration_order(order))\n    }\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterOption<Q, Item = Self::Item> {\n        ParOption::new(self.par.with_runner(orchestrator))\n    }\n\n    // computation transformations\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIterOption<R, Item = Out>\n    where\n        Map: Fn(Self::Item) -> Out + Sync + Clone,\n        Out: Send,\n    {\n        ParOption::new(self.par.map(map))\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIterOption<R, Item = Self::Item>\n    where\n        Self: Sized,\n        Filter: Fn(&Self::Item) -> bool + Sync + Clone,\n        Self::Item: Send,\n    {\n        ParOption::new(self.par.filter(filter))\n    }\n\n    fn flat_map<IOut, FlatMap>(self, flat_map: FlatMap) -> impl ParIterOption<R, Item = IOut::Item>\n    where\n        Self: Sized,\n        IOut: IntoIterator,\n        IOut::Item: Send,\n        FlatMap: Fn(Self::Item) -> IOut + Sync + Clone,\n    {\n        ParOption::new(self.par.flat_map(flat_map))\n    }\n\n    fn filter_map<Out, FilterMap>(self, filter_map: FilterMap) -> impl ParIterOption<R, Item = Out>\n    where\n        Self: Sized,\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync + Clone,\n        Out: Send,\n    {\n        ParOption::new(self.par.filter_map(filter_map))\n    }\n\n    fn inspect<Operation>(self, operation: Operation) -> impl ParIterOption<R, Item = Self::Item>\n    where\n        Self: Sized,\n        Operation: Fn(&Self::Item) + Sync + Clone,\n        Self::Item: Send,\n    {\n        ParOption::new(self.par.inspect(operation))\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>,\n    {\n        self.par.collect_into(output).into_option()\n    }\n\n    fn collect<C>(self) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>,\n    {\n        self.par.collect().into_option()\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        self.par.reduce(reduce).into_option()\n    }\n\n    // early exit\n\n    fn first(self) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send,\n    {\n        self.par.first().into_option()\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/fallible_result/map_result.rs",
    "content": "use crate::computational_variants::ParMap;\nuse crate::executor::parallel_compute as prc;\nuse crate::par_iter_result::{IntoResult, ParIterResult};\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::{IterationOrder, ParCollectInto, ParIter};\nuse core::marker::PhantomData;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub struct ParMapResult<I, T, E, O, M1, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    O: IntoResult<T, E>,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    par: ParMap<I, O, M1, R>,\n    phantom: PhantomData<(T, E)>,\n}\n\nimpl<I, T, E, O, M1, R> ParMapResult<I, T, E, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    O: IntoResult<T, E>,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    pub(crate) fn new(par: ParMap<I, O, M1, R>) -> Self {\n        Self {\n            par,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<I, T, E, O, M1, R> ParIterResult<R> for ParMapResult<I, T, E, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    O: IntoResult<T, E>,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    type Item = T;\n\n    type Err = E;\n\n    type RegularItem = O;\n\n    type RegularParIter = ParMap<I, O, M1, R>;\n\n    fn con_iter_len(&self) -> Option<usize> {\n        self.par.con_iter().try_get_len()\n    }\n\n    fn into_regular_par(self) -> Self::RegularParIter {\n        self.par\n    }\n\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self {\n        Self {\n            par: regular_par,\n            phantom: PhantomData,\n        }\n    }\n\n    // params transformations\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResult<Q, Item = Self::Item, Err = Self::Err> {\n        let (_, params, iter, m1) = self.par.destruct();\n        ParMapResult {\n            par: ParMap::new(orchestrator, params, iter, m1),\n            phantom: PhantomData,\n        }\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (orchestrator, params, iter, m1) = self.par.destruct();\n        let x1 = |i: I::Item| m1(i).into_result();\n        output.x_try_collect_into(orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.par.destruct();\n        let x1 = |i: I::Item| m1(i).into_result();\n        prc::reduce::x(orchestrator, params, iter, x1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (orchestrator, params, iter, m1) = self.par.destruct();\n        let x1 = |i: I::Item| m1(i).into_result();\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_, result) = prc::next::x(orchestrator, params, iter, x1);\n                result.map(|x| x.map(|y| y.1))\n            }\n            IterationOrder::Arbitrary => {\n                let (_, result) = prc::next_any::x(orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/fallible_result/mod.rs",
    "content": "mod map_result;\nmod par_result;\nmod xap_result;\n\npub use map_result::ParMapResult;\npub use par_result::ParResult;\npub use xap_result::ParXapResult;\n"
  },
  {
    "path": "src/computational_variants/fallible_result/par_result.rs",
    "content": "use crate::computational_variants::Par;\nuse crate::executor::parallel_compute as prc;\nuse crate::par_iter_result::{IntoResult, ParIterResult};\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::{IterationOrder, ParCollectInto, ParIter};\nuse core::marker::PhantomData;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub struct ParResult<I, T, E, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    I::Item: IntoResult<T, E>,\n{\n    par: Par<I, R>,\n    phantom: PhantomData<(T, E)>,\n}\n\nimpl<I, T, E, R> ParResult<I, T, E, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    I::Item: IntoResult<T, E>,\n{\n    pub(crate) fn new(par: Par<I, R>) -> Self {\n        Self {\n            par,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<I, T, E, R> ParIterResult<R> for ParResult<I, T, E, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    I::Item: IntoResult<T, E>,\n{\n    type Item = T;\n\n    type Err = E;\n\n    type RegularItem = I::Item;\n\n    type RegularParIter = Par<I, R>;\n\n    fn con_iter_len(&self) -> Option<usize> {\n        self.par.con_iter().try_get_len()\n    }\n\n    fn into_regular_par(self) -> Self::RegularParIter {\n        self.par\n    }\n\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self {\n        Self {\n            par: regular_par,\n            phantom: PhantomData,\n        }\n    }\n\n    // params transformations\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResult<Q, Item = Self::Item, Err = Self::Err> {\n        let (_, params, iter) = self.par.destruct();\n        ParResult {\n            par: Par::new(orchestrator, params, iter),\n            phantom: PhantomData,\n        }\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (orchestrator, params, iter) = self.par.destruct();\n        let x1 = |i: I::Item| i.into_result();\n        output.x_try_collect_into(orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (orchestrator, params, iter) = self.par.destruct();\n        let x1 = |i: I::Item| i.into_result();\n        prc::reduce::x(orchestrator, params, iter, x1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (orchestrator, params, iter) = self.par.destruct();\n        let x1 = |i: I::Item| i.into_result();\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_, result) = prc::next::x(orchestrator, params, iter, x1);\n                result.map(|x| x.map(|y| y.1))\n            }\n            IterationOrder::Arbitrary => {\n                let (_, result) = prc::next_any::x(orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/fallible_result/xap_result.rs",
    "content": "use crate::computational_variants::ParXap;\nuse crate::executor::parallel_compute as prc;\nuse crate::generic_values::TransformableValues;\nuse crate::generic_values::runner_results::Infallible;\nuse crate::par_iter_result::{IntoResult, ParIterResult};\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::{IterationOrder, ParCollectInto, Params};\nuse core::marker::PhantomData;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub struct ParXapResult<I, T, E, Vo, X1, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues,\n    Vo::Item: IntoResult<T, E>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    phantom: PhantomData<(T, E)>,\n}\n\nimpl<I, T, E, Vo, X1, R> ParXapResult<I, T, E, Vo, X1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues,\n    Vo::Item: IntoResult<T, E>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    pub(crate) fn new(orchestrator: R, params: Params, iter: I, xap1: X1) -> Self {\n        Self {\n            orchestrator,\n            params,\n            iter,\n            xap1,\n            phantom: PhantomData,\n        }\n    }\n\n    fn destruct(self) -> (R, Params, I, X1) {\n        (self.orchestrator, self.params, self.iter, self.xap1)\n    }\n}\n\nimpl<I, T, E, Vo, X1, R> ParIterResult<R> for ParXapResult<I, T, E, Vo, X1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    Vo::Item: IntoResult<T, E>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    type Item = T;\n\n    type Err = E;\n\n    type RegularItem = Vo::Item;\n\n    type RegularParIter = ParXap<I, Vo, X1, R>;\n\n    fn con_iter_len(&self) -> Option<usize> {\n        self.iter.try_get_len()\n    }\n\n    fn into_regular_par(self) -> Self::RegularParIter {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self {\n        let (orchestrator, params, iter, x1) = regular_par.destruct();\n        Self::new(orchestrator, params, iter, x1)\n    }\n\n    // params transformations\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResult<Q, Item = Self::Item, Err = Self::Err> {\n        let (_, params, iter, x1) = self.destruct();\n        ParXapResult::new(orchestrator, params, iter, x1)\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = |i: I::Item| x1(i).map_while_ok(|x| x.into_result());\n        output.x_try_collect_into(orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = |i: I::Item| x1(i).map_while_ok(|x| x.into_result());\n        prc::reduce::x(orchestrator, params, iter, x1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = |i: I::Item| x1(i).map_while_ok(|x| x.into_result());\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_, result) = prc::next::x(orchestrator, params, iter, x1);\n                result.map(|x| x.map(|y| y.1))\n            }\n            IterationOrder::Arbitrary => {\n                let (_, result) = prc::next_any::x(orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/map.rs",
    "content": "use super::xap::ParXap;\nuse crate::computational_variants::fallible_result::ParMapResult;\nuse crate::executor::parallel_compute as prc;\nuse crate::generic_values::{Vector, WhilstAtom};\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::{UParMap, UsingClone, UsingFun};\nuse crate::{ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParEnumerate, ParIter, Params};\nuse crate::{ParIterResult, ParIterUsing};\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator that maps inputs.\npub struct ParMap<I, O, M1, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    map1: M1,\n}\n\nimpl<I, O, M1, R> ParMap<I, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    pub(crate) fn new(orchestrator: R, params: Params, iter: I, map1: M1) -> Self {\n        Self {\n            orchestrator,\n            params,\n            iter,\n            map1,\n        }\n    }\n\n    pub(crate) fn destruct(self) -> (R, Params, I, M1) {\n        (self.orchestrator, self.params, self.iter, self.map1)\n    }\n}\n\nunsafe impl<I, O, M1, R> Send for ParMap<I, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n{\n}\n\nunsafe impl<I, O, M1, R> Sync for ParMap<I, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n{\n}\n\nimpl<I, O, M1, R> ParIter<R> for ParMap<I, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    type Item = O;\n\n    fn con_iter(&self) -> &impl ConcurrentIter {\n        &self.iter\n    }\n\n    fn params(&self) -> Params {\n        self.params\n    }\n\n    // params transformations\n\n    fn num_threads(mut self, num_threads: impl Into<NumThreads>) -> Self {\n        self.params = self.params.with_num_threads(num_threads);\n        self\n    }\n\n    fn chunk_size(mut self, chunk_size: impl Into<ChunkSize>) -> Self {\n        self.params = self.params.with_chunk_size(chunk_size);\n        self\n    }\n\n    fn iteration_order(mut self, collect: IterationOrder) -> Self {\n        self.params = self.params.with_collect_ordering(collect);\n        self\n    }\n\n    fn with_runner<Q: ParallelRunner>(self, orchestrator: Q) -> impl ParIter<Q, Item = Self::Item> {\n        let (_, params, iter, map) = self.destruct();\n        ParMap::new(orchestrator, params, iter, map)\n    }\n\n    // using transformations\n\n    fn using<'using, U, F>(\n        self,\n        using: F,\n    ) -> impl ParIterUsing<'using, UsingFun<F, U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: 'using,\n        F: Fn(usize) -> U + Sync,\n    {\n        let using = UsingFun::new(using);\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let m1 = move |_: &mut U, t: I::Item| x1(t);\n        UParMap::new(using, orchestrator, params, iter, m1)\n    }\n\n    fn using_clone<U>(\n        self,\n        value: U,\n    ) -> impl ParIterUsing<'static, UsingClone<U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: Clone + 'static,\n    {\n        let using = UsingClone::new(value);\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let m1 = move |_: &mut U, t: I::Item| x1(t);\n        UParMap::new(using, orchestrator, params, iter, m1)\n    }\n\n    // computation transformations\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIter<R, Item = Out>\n    where\n        Map: Fn(Self::Item) -> Out + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        let m1 = move |x| map(m1(x));\n        ParMap::new(orchestrator, params, iter, m1)\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIter<R, Item = Self::Item>\n    where\n        Filter: Fn(&Self::Item) -> bool + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n\n        let x1 = move |i: I::Item| {\n            let value = m1(i);\n            filter(&value).then_some(value)\n        };\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn flat_map<IOut, FlatMap>(self, flat_map: FlatMap) -> impl ParIter<R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(Self::Item) -> IOut + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        let x1 = move |i: I::Item| Vector(flat_map(m1(i)));\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn filter_map<Out, FilterMap>(self, filter_map: FilterMap) -> impl ParIter<R, Item = Out>\n    where\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        let x1 = move |i: I::Item| filter_map(m1(i));\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn take_while<While>(self, take_while: While) -> impl ParIter<R, Item = Self::Item>\n    where\n        While: Fn(&Self::Item) -> bool + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        let x1 = move |value: I::Item| WhilstAtom::new(m1(value), &take_while);\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn into_fallible_result<Out, Err>(self) -> impl ParIterResult<R, Item = Out, Err = Err>\n    where\n        Self::Item: IntoResult<Out, Err>,\n    {\n        ParMapResult::new(self)\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        output.m_collect_into(orchestrator, params, iter, m1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        prc::reduce::m(orchestrator, params, iter, m1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n    {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        match params.iteration_order {\n            IterationOrder::Ordered => prc::next::m(orchestrator, params, iter, m1).1,\n            IterationOrder::Arbitrary => prc::next_any::m(orchestrator, params, iter, m1).1,\n        }\n    }\n}\n\nimpl<I, O, M1, R> ParEnumerate<R> for ParMap<I, O, M1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    fn enumerate(self) -> impl ParIter<R, Item = (usize, Self::Item)> {\n        let (orchestrator, params, iter, m1) = self.destruct();\n        let x1 = move |(x, i): (usize, I::Item)| (x, m1(i));\n        ParMap::new(orchestrator, params, iter.enumerate(), x1)\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/mod.rs",
    "content": "#[cfg(test)]\nmod tests;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with None.\npub mod fallible_option;\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub mod fallible_result;\n\nmod map;\nmod par;\nmod xap;\n\npub use map::ParMap;\npub use par::Par;\npub use xap::ParXap;\n"
  },
  {
    "path": "src/computational_variants/par.rs",
    "content": "use super::{map::ParMap, xap::ParXap};\nuse crate::computational_variants::fallible_result::ParResult;\nuse crate::executor::parallel_compute as prc;\nuse crate::generic_values::{Vector, WhilstAtom};\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::{UPar, UsingClone, UsingFun};\nuse crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParIter, Params, default_fns::map_self,\n};\nuse crate::{IntoParIter, ParEnumerate, ParIterResult, ParIterUsing};\nuse orx_concurrent_iter::chain::ChainKnownLenI;\nuse orx_concurrent_iter::{ConcurrentIter, ExactSizeConcurrentIter};\n\n/// A parallel iterator.\npub struct Par<I, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    orchestrator: R,\n    params: Params,\n    iter: I,\n}\n\nimpl<I, R> Par<I, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    pub(crate) fn new(orchestrator: R, params: Params, iter: I) -> Self {\n        Self {\n            orchestrator,\n            iter,\n            params,\n        }\n    }\n\n    pub(crate) fn destruct(self) -> (R, Params, I) {\n        (self.orchestrator, self.params, self.iter)\n    }\n\n    pub(crate) fn orchestrator(&self) -> &R {\n        &self.orchestrator\n    }\n}\n\nunsafe impl<I, R> Send for Par<I, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n}\n\nunsafe impl<I, R> Sync for Par<I, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n}\n\nimpl<I, R> ParIter<R> for Par<I, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    type Item = I::Item;\n\n    fn con_iter(&self) -> &impl ConcurrentIter {\n        &self.iter\n    }\n\n    fn params(&self) -> Params {\n        self.params\n    }\n\n    // params transformations\n\n    fn num_threads(mut self, num_threads: impl Into<NumThreads>) -> Self {\n        self.params = self.params.with_num_threads(num_threads);\n        self\n    }\n\n    fn chunk_size(mut self, chunk_size: impl Into<ChunkSize>) -> Self {\n        self.params = self.params.with_chunk_size(chunk_size);\n        self\n    }\n\n    fn iteration_order(mut self, collect: IterationOrder) -> Self {\n        self.params = self.params.with_collect_ordering(collect);\n        self\n    }\n\n    fn with_runner<Q: ParallelRunner>(self, orchestrator: Q) -> impl ParIter<Q, Item = Self::Item> {\n        Par::new(orchestrator, self.params, self.iter)\n    }\n\n    // using transformations\n\n    fn using<'using, U, F>(\n        self,\n        using: F,\n    ) -> impl ParIterUsing<'using, UsingFun<F, U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: 'using,\n        F: Fn(usize) -> U + Sync,\n    {\n        let using = UsingFun::new(using);\n        let (orchestrator, params, iter) = self.destruct();\n        UPar::new(using, orchestrator, params, iter)\n    }\n\n    fn using_clone<U>(\n        self,\n        value: U,\n    ) -> impl ParIterUsing<'static, UsingClone<U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: Clone + 'static,\n    {\n        let using = UsingClone::new(value);\n        let (orchestrator, params, iter) = self.destruct();\n        UPar::new(using, orchestrator, params, iter)\n    }\n\n    // computation transformations\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIter<R, Item = Out>\n    where\n        Map: Fn(Self::Item) -> Out + Sync,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        ParMap::new(orchestrator, params, iter, map)\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIter<R, Item = Self::Item>\n    where\n        Filter: Fn(&Self::Item) -> bool + Sync,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        let x1 = move |i: Self::Item| filter(&i).then_some(i);\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn flat_map<IOut, FlatMap>(self, flat_map: FlatMap) -> impl ParIter<R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(Self::Item) -> IOut + Sync,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        let x1 = move |i: Self::Item| Vector(flat_map(i));\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn filter_map<Out, FilterMap>(self, filter_map: FilterMap) -> impl ParIter<R, Item = Out>\n    where\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        ParXap::new(orchestrator, params, iter, filter_map)\n    }\n\n    fn take_while<While>(self, take_while: While) -> impl ParIter<R, Item = Self::Item>\n    where\n        While: Fn(&Self::Item) -> bool + Sync,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        let x1 = move |value: Self::Item| WhilstAtom::new(value, &take_while);\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn into_fallible_result<Out, Err>(self) -> impl ParIterResult<R, Item = Out, Err = Err>\n    where\n        Self::Item: IntoResult<Out, Err>,\n    {\n        ParResult::new(self)\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        output.m_collect_into(orchestrator, params, iter, map_self)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        prc::reduce::m(orchestrator, params, iter, map_self, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Option<Self::Item> {\n        let (orchestrator, params, iter) = self.destruct();\n        match params.iteration_order {\n            IterationOrder::Ordered => prc::next::m(orchestrator, params, iter, map_self).1,\n            IterationOrder::Arbitrary => prc::next_any::m(orchestrator, params, iter, map_self).1,\n        }\n    }\n}\n\nimpl<I, R> Par<I, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    /// Creates a chain of this and `other` parallel iterators.\n    ///\n    /// The first iterator is required to have a known length for chaining.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec!['a', 'b', 'c']; // with exact len\n    /// let b = vec!['d', 'e', 'f'].into_iter().filter(|x| *x != 'x');\n    ///\n    /// let chain = a.into_par().chain(b.iter_into_par());\n    /// assert_eq!(\n    ///     chain.collect::<Vec<_>>(),\n    ///     vec!['a', 'b', 'c', 'd', 'e', 'f'],\n    /// );\n    /// ```\n    pub fn chain<C>(self, other: C) -> Par<ChainKnownLenI<I, C::IntoIter>, R>\n    where\n        I: ExactSizeConcurrentIter,\n        C: IntoParIter<Item = I::Item>,\n    {\n        let (orchestrator, params, iter) = self.destruct();\n        let iter = iter.chain(other.into_con_iter());\n        Par::new(orchestrator, params, iter)\n    }\n}\n\nimpl<I, R> ParEnumerate<R> for Par<I, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    fn enumerate(self) -> impl ParIter<R, Item = (usize, Self::Item)> {\n        let (orchestrator, params, iter) = self.destruct();\n        Par::new(orchestrator, params, iter.enumerate())\n    }\n}\n"
  },
  {
    "path": "src/computational_variants/tests/copied.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<usize>>(n: usize) -> O {\n    (0..n).collect()\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input: Vec<_> = input::<Vec<_>>(n);\n        let expected: usize = input.iter().copied().sum();\n        let par = || input.par().num_threads(nt).chunk_size(chunk);\n\n        let output = par().copied().sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let map = |x: usize| x + 1;\n        let expected: usize = input.iter().copied().map(&map).sum();\n        let par = || input.par().num_threads(nt).chunk_size(chunk);\n\n        let output = par().copied().map(map).sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().map(map).sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let flat_map = |x: usize| [x, x + 1, x + 2];\n        let expected: usize = input.iter().copied().flat_map(&flat_map).sum();\n        let par = || input.par().num_threads(nt).chunk_size(chunk);\n\n        let output = par().copied().flat_map(flat_map).sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().flat_map(flat_map).sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: usize| (!x.is_multiple_of(3)).then(|| x + 1);\n        let expected: usize = input.iter().copied().filter_map(&filter_map).sum();\n        let par = || input.par().num_threads(nt).chunk_size(chunk);\n\n        let output = par().copied().filter_map(filter_map).sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().filter_map(filter_map).sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: usize| (!x.is_multiple_of(3)).then(|| x + 1);\n        let filter = |x: &usize| x % 3 != 1;\n        let flat_map = |x: usize| [x, x + 1, x + 2];\n        let expected: usize = input\n            .iter()\n            .copied()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .flat_map(&flat_map)\n            .sum();\n        let par = || input.par().num_threads(nt).chunk_size(chunk);\n\n        let output = par()\n            .copied()\n            .filter_map(filter_map)\n            .filter(filter)\n            .flat_map(flat_map)\n            .sum();\n        assert_eq!(output, expected);\n\n        let output = par()\n            .cloned()\n            .filter_map(filter_map)\n            .filter(filter)\n            .flat_map(flat_map)\n            .sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/count.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = n;\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = n;\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.map(|x| format!(\"{}!\", x));\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n        let expected = input.clone().into_iter().flat_map(&flat_map).count();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.flat_map(flat_map);\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let expected = input.clone().into_iter().filter_map(&filter_map).count();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map);\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n        let expected = input\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .flat_map(&flat_map)\n            .count();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map).filter(filter).flat_map(flat_map);\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/enumerate.rs",
    "content": "use std::string::ToString;\n\nuse crate::{test_utils::*, *};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\n#[test_matrix(N, NT, CHUNK)]\nfn enumerate_sequential(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let par = (0..n).into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.enumerate();\n        let vec: Vec<_> = par.collect();\n\n        vec.iter().for_each(|(idx, value)| {\n            assert_eq!(idx, value);\n        });\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn enumerate_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let par = (0..n).into_par().num_threads(nt).chunk_size(chunk);\n        let par = par\n            .enumerate()\n            .map(|(idx, value): (usize, usize)| (idx + 1, value.pow(2)));\n        let vec: Vec<_> = par.collect();\n\n        vec.iter().for_each(|(idx_outer, value)| {\n            assert_eq!((*idx_outer - 1).pow(2), *value);\n        });\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn enumerate_using(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let par = (0..n)\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .enumerate()\n            .using_clone(\"XyZw\".to_string());\n\n        let par = par.map(|_u, (idx, value)| (idx + 1, value.pow(2)));\n        let vec: Vec<_> = par.collect();\n\n        vec.iter().for_each(|(idx_outer, value)| {\n            assert_eq!((idx_outer - 1).pow(2), *value);\n        });\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/fallible_option.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[test_matrix(NT, CHUNK)]\nfn fallible_option_collect_empty(nt: &[usize], chunk: &[usize]) {\n    let test = |_, nt, chunk| {\n        let input = || input::<Vec<_>>(0);\n\n        let par = input()\n            .into_iter()\n            .map(|_| None::<String>)\n            .collect::<Vec<_>>()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .into_fallible_option();\n        let output: Option<Vec<_>> = par.collect();\n\n        assert_eq!(output, Some(Vec::new()));\n    };\n    test_n_nt_chunk(&[0], nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_option_collect_partial_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(|x| (x != \"50\").then_some(x))\n            .into_fallible_option()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"));\n        let output: Option<Vec<_>> = par.collect();\n\n        assert_eq!(output, None);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_option_collect_complete_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let expected: Vec<_> = input()\n            .into_iter()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"))\n            .filter_map(Some)\n            .collect();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(|x| (x != \"xyz\").then_some(x))\n            .into_fallible_option()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"))\n            .filter_map(Some);\n        let output: Option<Vec<_>> = par.collect();\n\n        assert_eq!(output, Some(expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/fallible_result.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[derive(Debug, PartialEq, Eq)]\nstruct MyErr(String);\nimpl MyErr {\n    fn new() -> Self {\n        Self(\"error\".to_string())\n    }\n}\n\n#[test_matrix(NT, CHUNK)]\nfn fallible_result_collect_empty(nt: &[usize], chunk: &[usize]) {\n    let test = |_, nt, chunk| {\n        let input = || input::<Vec<_>>(0);\n\n        let par = input()\n            .into_iter()\n            .map(|_| Err::<String, _>(MyErr::new()))\n            .collect::<Vec<_>>()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .into_fallible_result();\n        let output: Result<Vec<_>, MyErr> = par.collect();\n\n        assert_eq!(output, Ok(Vec::new()));\n    };\n    test_n_nt_chunk(&[0], nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_result_collect_partial_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(|x| match x == \"50\" {\n                true => Err(MyErr::new()),\n                false => Ok(x),\n            })\n            .into_fallible_result()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"));\n        let output: Result<Vec<_>, MyErr> = par.collect();\n\n        assert_eq!(output, Err(MyErr::new()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_result_collect_complete_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let expected: Vec<_> = input()\n            .into_iter()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"))\n            .filter_map(Some)\n            .collect();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(|x| match x == \"xyz\" {\n                true => Err(MyErr::new()),\n                false => Ok(x),\n            })\n            .into_fallible_result()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"))\n            .filter_map(Some);\n        let output: Result<Vec<_>, MyErr> = par.collect();\n\n        assert_eq!(output, Ok(expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/flatten.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse alloc::{format, vec};\nuse test_case::test_matrix;\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || {\n            (0..n)\n                .map(|i| [i.to_string(), (i + 1).to_string()])\n                .collect::<Vec<_>>()\n        };\n\n        let expected: Vec<_> = input().into_iter().flatten().collect();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<_> = par.flatten().collect();\n\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || (0..n).collect::<Vec<_>>();\n        let map = |i: usize| vec![i.to_string(), (i + 1).to_string()];\n\n        #[allow(clippy::map_flatten)]\n        let expected: Vec<_> = input().into_iter().map(&map).flatten().collect();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<_> = par.map(&map).flatten().collect();\n\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || (0..n).map(|i| i.to_string()).collect::<Vec<_>>();\n        let filter_map = |x: String| {\n            x.starts_with('3')\n                .then(|| vec![x.clone(), format!(\"{}!\", x)])\n        };\n\n        #[allow(clippy::map_flatten)]\n        let expected: Vec<_> = input()\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .flatten()\n            .collect();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<_> = par.filter_map(filter_map).flatten().collect();\n\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || (0..n).map(|i| i.to_string()).collect::<Vec<_>>();\n        let filter_map = |x: String| {\n            x.starts_with('3')\n                .then(|| vec![x.clone(), format!(\"{}!\", x)])\n        };\n        let filter = |x: &Vec<String>| x.len() == 2;\n        let map = |mut x: Vec<String>| {\n            x.push(\"lorem\".to_string());\n            x\n        };\n        #[allow(clippy::map_flatten)]\n        let expected: Vec<_> = input()\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .map(&map)\n            .flatten()\n            .collect();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<_> = par\n            .filter_map(filter_map)\n            .filter(filter)\n            .map(map)\n            .flatten()\n            .collect();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/for_each.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_vec::ConcurrentVec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn sorted(mut x: Vec<String>) -> Vec<String> {\n    x.sort();\n    x\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let vec = ConcurrentVec::new();\n        par.for_each(|x| {\n            _ = vec.push(x);\n        });\n\n        assert_eq!(sorted(vec.to_vec()), sorted(input()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let map = |x| format!(\"{}!\", x);\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.map(&map);\n        let vec = ConcurrentVec::new();\n        par.for_each(|x| {\n            _ = vec.push(x);\n        });\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().map(map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.flat_map(flat_map);\n        let vec = ConcurrentVec::new();\n        par.for_each(|x| {\n            _ = vec.push(x);\n        });\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().flat_map(flat_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map);\n        let vec = ConcurrentVec::new();\n        par.for_each(|x| {\n            _ = vec.push(x);\n        });\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().filter_map(filter_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map).filter(filter).flat_map(flat_map);\n        let vec = ConcurrentVec::new();\n        par.for_each(|x| {\n            _ = vec.push(x);\n        });\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(\n                input()\n                    .into_iter()\n                    .filter_map(filter_map)\n                    .filter(filter)\n                    .flat_map(flat_map)\n                    .collect()\n            )\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/inspect.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_vec::ConcurrentVec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn sorted(mut x: Vec<String>) -> Vec<String> {\n    x.sort();\n    x\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let vec = ConcurrentVec::new();\n        par.inspect(|x| {\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(sorted(vec.to_vec()), sorted(input()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let map = |x| format!(\"{}!\", x);\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.map(&map);\n        let vec = ConcurrentVec::new();\n        par.inspect(|x| {\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().map(map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.flat_map(flat_map);\n        let vec = ConcurrentVec::new();\n        par.inspect(|x| {\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().flat_map(flat_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map);\n        let vec = ConcurrentVec::new();\n        par.inspect(|x| {\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().filter_map(filter_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input().into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map).filter(filter).flat_map(flat_map);\n        let vec = ConcurrentVec::new();\n        par.inspect(|x| {\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(\n                input()\n                    .into_iter()\n                    .filter_map(filter_map)\n                    .filter(filter)\n                    .flat_map(flat_map)\n                    .collect()\n            )\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/iter_consuming.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Collection;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\nconst N_OFFSET: usize = 13;\n\nfn offset() -> Vec<String> {\n    vec![\"x\".to_string(); N_OFFSET]\n}\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(\n    with_offset: bool,\n    input: &impl Collection<Item = String>,\n    map: impl Fn(String) -> String,\n) -> Vec<String> {\n    match with_offset {\n        true => {\n            let mut vec = offset();\n            vec.extend(input.iter().cloned().map(map));\n            vec\n        }\n        false => input.iter().cloned().map(map).collect(),\n    }\n}\n\n// collect - empty\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn empty_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &vec, |x| x);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input.iter_into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn empty_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(false, &vec, |x| x);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input.iter_into_par().num_threads(nt).chunk_size(chunk);\n        let output: C = par.collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn map_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &vec, map);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input.iter_into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.map(map).collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(false, &vec, map);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input.iter_into_par().num_threads(nt).chunk_size(chunk);\n        let output: C = par.map(map).collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/iter_ref.rs",
    "content": "use crate::{collect_into::ParCollectIntoCore, test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::{Collection, IntoCloningIterable};\nuse orx_split_vec::{Doubling, Linear, PseudoDefault, SplitVec};\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(input: &impl Collection<Item = String>, map: impl Fn(String) -> String) -> Vec<String> {\n    input.iter().cloned().map(map).collect()\n}\n\n// collect - empty\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, |x| x);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(Vec::new());\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(FixedVec::pseudo_default());\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(SplitVec::<_, Doubling>::pseudo_default());\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(SplitVec::<_, Linear>::pseudo_default());\n        assert!(output.is_equal_to_ref(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, |x| x);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output: FixedVec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output: SplitVec<&String, Doubling> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output: SplitVec<&String, Linear> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, map2);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<String> = par.map(map).collect_into(vec![]);\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, map2);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input.par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<String> = par.map(map).collect();\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/map/collect.rs",
    "content": "use crate::collect_into::collect::map_collect_into;\nuse crate::{IterationOrder, Params, runner::DefaultRunner};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn m_map_collect(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let value = || map(i.to_string());\n        output.push(value());\n        expected.push(value());\n    }\n    expected.extend(input.clone().into_iter().map(map));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let (_, mut output) = map_collect_into(DefaultRunner::default(), params, iter, map, output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n"
  },
  {
    "path": "src/computational_variants/tests/map/find.rs",
    "content": "use crate::{Params, default_fns::map_self, executor::parallel_compute, runner::DefaultRunner};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n\n    let expected = input.clone().into_iter().next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n\n    let output = parallel_compute::next::m(DefaultRunner::default(), params, iter, map_self).1;\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_map_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n\n    let expected = input.clone().into_iter().map(map).next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let output = parallel_compute::next::m(DefaultRunner::default(), params, iter, map).1;\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/map/mod.rs",
    "content": "mod collect;\nmod find;\nmod reduce;\n"
  },
  {
    "path": "src/computational_variants/tests/map/reduce.rs",
    "content": "use crate::{Params, default_fns::map_self, executor::parallel_compute, runner::DefaultRunner};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let reduce = |x: String, y: String| match x < y {\n        true => y,\n        false => x,\n    };\n\n    let expected = input.clone().into_iter().reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let (_, output) =\n        parallel_compute::reduce::m(DefaultRunner::default(), params, iter, map_self, reduce);\n\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_map_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n    let reduce = |x: String, y: String| match x < y {\n        true => y,\n        false => x,\n    };\n\n    let expected = input.clone().into_iter().map(map).reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let (_, output) =\n        parallel_compute::reduce::m(DefaultRunner::default(), params, iter, map, reduce);\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/min_max.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse core::cmp::Ordering;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn cmp(a: &usize, b: &usize) -> Ordering {\n    match a < b {\n        true => Ordering::Less,\n        false => Ordering::Greater,\n    }\n}\n\nfn key(a: &usize) -> u64 {\n    *a as u64 + 10\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || {\n            input::<Vec<_>>(n)\n                .iter()\n                .map(|x| x.parse::<usize>().expect(\"is-ok\"))\n                .collect::<Vec<_>>()\n        };\n\n        let par = || input().into_par().num_threads(nt).chunk_size(chunk);\n\n        assert_eq!(par().min(), input().iter().min().copied());\n        assert_eq!(par().max(), input().iter().max().copied());\n\n        assert_eq!(par().min_by(cmp), input().into_iter().min_by(cmp));\n        assert_eq!(par().max_by(cmp), input().into_iter().max_by(cmp));\n\n        assert_eq!(par().min_by_key(key), input().into_iter().min_by_key(key));\n        assert_eq!(par().max_by_key(key), input().into_iter().max_by_key(key));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let map = |x: String| x.parse::<usize>().expect(\"is-ok\");\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .map(&map)\n        };\n\n        assert_eq!(par().min(), input().into_iter().map(&map).min());\n        assert_eq!(par().max(), input().into_iter().map(&map).max());\n\n        assert_eq!(par().min_by(cmp), input().into_iter().map(&map).min_by(cmp));\n        assert_eq!(par().max_by(cmp), input().into_iter().map(&map).max_by(cmp));\n\n        assert_eq!(\n            par().min_by_key(key),\n            input().into_iter().map(&map).min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input().into_iter().map(&map).max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let flat_map = |x: String| {\n            let n = x.len();\n            let a = x.parse::<usize>().expect(\"is-ok\");\n            (0..n).map(|i| a + i).collect::<Vec<_>>()\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .flat_map(&flat_map)\n        };\n\n        assert_eq!(par().min(), input().into_iter().flat_map(&flat_map).min());\n        assert_eq!(par().max(), input().into_iter().flat_map(&flat_map).max());\n\n        assert_eq!(\n            par().min_by(cmp),\n            input().into_iter().flat_map(&flat_map).min_by(cmp)\n        );\n        assert_eq!(\n            par().max_by(cmp),\n            input().into_iter().flat_map(&flat_map).max_by(cmp)\n        );\n\n        assert_eq!(\n            par().min_by_key(key),\n            input().into_iter().flat_map(&flat_map).min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input().into_iter().flat_map(&flat_map).max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| {\n            x.starts_with('3')\n                .then(|| x.parse::<usize>().expect(\"is-ok\"))\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .filter_map(&filter_map)\n        };\n\n        assert_eq!(\n            par().min(),\n            input().into_iter().filter_map(&filter_map).min()\n        );\n        assert_eq!(\n            par().max(),\n            input().into_iter().filter_map(&filter_map).max()\n        );\n\n        assert_eq!(\n            par().min_by(cmp),\n            input().into_iter().filter_map(&filter_map).min_by(cmp)\n        );\n        assert_eq!(\n            par().max_by(cmp),\n            input().into_iter().filter_map(&filter_map).max_by(cmp)\n        );\n\n        assert_eq!(\n            par().min_by_key(key),\n            input().into_iter().filter_map(&filter_map).min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input().into_iter().filter_map(&filter_map).max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| {\n            let n = x.len();\n            let a = x.parse::<usize>().expect(\"is-ok\");\n            (0..n).map(|i| a + i).collect::<Vec<_>>()\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n        };\n\n        assert_eq!(\n            par().min(),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .min()\n        );\n        assert_eq!(\n            par().max(),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .max()\n        );\n\n        assert_eq!(\n            par().min_by(cmp),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .min_by(cmp)\n        );\n        assert_eq!(\n            par().max_by(cmp),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .max_by(cmp)\n        );\n\n        assert_eq!(\n            par().min_by_key(key),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/mod.rs",
    "content": "mod copied;\nmod count;\nmod enumerate;\nmod fallible_option;\nmod fallible_result;\nmod flatten;\nmod for_each;\nmod inspect;\nmod iter_consuming;\nmod iter_ref;\nmod map;\nmod min_max;\nmod range;\nmod slice;\nmod sum;\nmod vectors;\nmod xap;\n"
  },
  {
    "path": "src/computational_variants/tests/range.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Iterable;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\nconst N_OFFSET: usize = 13;\n\nfn offset() -> Vec<usize> {\n    vec![9; N_OFFSET]\n}\n\nfn expected<T>(\n    with_offset: bool,\n    input: impl Iterable<Item = usize>,\n    map: impl Fn(usize) -> T + Copy,\n) -> Vec<T> {\n    match with_offset {\n        true => {\n            let mut vec: Vec<_> = offset().into_iter().map(map).collect();\n            vec.extend(input.iter().map(map));\n            vec\n        }\n        false => input.iter().map(map).collect(),\n    }\n}\n\n// collect - empty\n\n#[test_matrix(\n    [Vec::<usize>::new(), SplitVec::<usize>::new(), FixedVec::<usize>::new(0), Vec::<usize>::from_iter(offset()), SplitVec::<usize>::from_iter(offset()), FixedVec::<usize>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn empty_collect_into<C>(output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<usize> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let input = 0..n;\n        let expected = expected(!output.is_empty(), input.clone(), |x| x);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<usize>::new(), SplitVec::<usize>::new(), FixedVec::<usize>::new(0)],\n    N, NT, CHUNK)\n]\nfn empty_collect<C>(_: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<usize>,\n{\n    let test = |n, nt, chunk| {\n        let input = 0..n;\n        let expected = expected(false, input.clone(), |x| x);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: C = par.collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect_into<C>(output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let map = |x: usize| x.to_string();\n        let input = 0..n;\n        let expected = expected(!output.is_empty(), input.clone(), map);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.map(map).collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect<C>(_: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let map = |x: usize| x.to_string();\n        let input = 0..n;\n        let expected = expected(false, input.clone(), map);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: C = par.map(map).collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/slice.rs",
    "content": "use crate::{collect_into::ParCollectIntoCore, test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Collection;\nuse orx_split_vec::{Doubling, Linear, PseudoDefault, SplitVec};\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(input: &impl Collection<Item = String>, map: impl Fn(String) -> String) -> Vec<String> {\n    input.iter().cloned().map(map).collect()\n}\n\n// collect - empty\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, |x| x);\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(Vec::new());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(FixedVec::pseudo_default());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(SplitVec::<_, Doubling>::pseudo_default());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(SplitVec::<_, Linear>::pseudo_default());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, |x| x);\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: FixedVec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: SplitVec<&String, Doubling> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: SplitVec<&String, Linear> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, map2);\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<String> = par.map(map).collect_into(vec![]);\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, map2);\n\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: Vec<String> = par.map(map).collect();\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/sum.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input: Vec<_> = input::<Vec<_>>(n).iter().map(|x| x.len()).collect();\n        let expected: usize = input.iter().sum();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let map = |x: String| x.len();\n        let expected: usize = input.clone().into_iter().map(&map).sum();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.map(map);\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string().len()).collect::<Vec<_>>();\n        let expected: usize = input.clone().into_iter().flat_map(&flat_map).sum();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.flat_map(flat_map);\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x.len());\n        let expected: usize = input.clone().into_iter().filter_map(&filter_map).sum();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map);\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string().len()).collect::<Vec<_>>();\n        let expected: usize = input\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .flat_map(&flat_map)\n            .sum();\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let par = par.filter_map(filter_map).filter(filter).flat_map(flat_map);\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/vectors.rs",
    "content": "use crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Collection;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\nconst N_OFFSET: usize = 13;\n\nfn offset() -> Vec<String> {\n    vec![\"x\".to_string(); N_OFFSET]\n}\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(\n    with_offset: bool,\n    input: &impl Collection<Item = String>,\n    map: impl Fn(String) -> String,\n) -> Vec<String> {\n    match with_offset {\n        true => {\n            let mut vec = offset();\n            vec.extend(input.iter().cloned().map(map));\n            vec\n        }\n        false => input.iter().cloned().map(map).collect(),\n    }\n}\n\n// collect - empty\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\nN, NT, CHUNK)\n]\nfn empty_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &input, |x| x);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn empty_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = expected(false, &input, |x| x);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: C = par.collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn map_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let input = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &input, map);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output = par.map(map).collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let input = input::<Vec<_>>(n);\n        let expected = expected(false, &input, map);\n        let par = input.into_par().num_threads(nt).chunk_size(chunk);\n        let output: C = par.map(map).collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/xap/collect.rs",
    "content": "use crate::ParIter;\nuse crate::computational_variants::ParXap;\nuse crate::generic_values::Vector;\nuse crate::runner::DefaultRunner;\nuse crate::{IterationOrder, Params};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test]\nfn todo_panic_at_con_bag_new() {\n    // TODO: this code panics when ParThreadPool::map uses ConcurrentBag::new rather than ConcurrentBag::with_fixed_capacity\n    let n = 10;\n    let nt = 2;\n    let chunk = 1;\n    let ordering = IterationOrder::Arbitrary;\n\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let i = i.to_string();\n        for x in fmap(i) {\n            output.push(x.clone());\n            expected.push(x);\n        }\n    }\n    expected.extend(input.clone().into_iter().flat_map(&fmap));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let mut output = x.collect_into(output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn x_flat_map_collect(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let i = i.to_string();\n        for x in fmap(i) {\n            output.push(x.clone());\n            expected.push(x);\n        }\n    }\n    expected.extend(input.clone().into_iter().flat_map(&fmap));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let mut output = x.collect_into(output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn x_filter_map_collect(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| (!x.starts_with('3')).then_some(format!(\"{}!\", x));\n    let xmap = |x: String| Vector(fmap(x));\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let i = i.to_string();\n        if let Some(x) = fmap(i) {\n            output.push(x.clone());\n            expected.push(x);\n        }\n    }\n    expected.extend(input.clone().into_iter().flat_map(&fmap));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let mut output = x.collect_into(output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n"
  },
  {
    "path": "src/computational_variants/tests/xap/find.rs",
    "content": "use crate::ParIter;\nuse crate::Params;\nuse crate::computational_variants::ParXap;\nuse crate::generic_values::Vector;\nuse crate::runner::DefaultRunner;\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_flat_map_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n\n    let expected = input.clone().into_iter().flat_map(fmap).next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let output = x.first();\n\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_filter_map_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| (!x.starts_with('3')).then_some(format!(\"{}!\", x));\n    let xmap = |x: String| Vector(fmap(x));\n\n    let expected = input.clone().into_iter().filter_map(fmap).next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let output = x.first();\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/computational_variants/tests/xap/mod.rs",
    "content": "mod collect;\nmod find;\nmod reduce;\n"
  },
  {
    "path": "src/computational_variants/tests/xap/reduce.rs",
    "content": "use crate::ParIter;\nuse crate::Params;\nuse crate::computational_variants::ParXap;\nuse crate::generic_values::Vector;\nuse crate::runner::DefaultRunner;\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_flat_map_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n    let reduce = |x: String, y: String| match x > y {\n        true => x,\n        false => y,\n    };\n\n    let expected = input.clone().into_iter().flat_map(fmap).reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let output = x.reduce(reduce);\n\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_filter_map_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| (!x.starts_with('3')).then_some(format!(\"{}!\", x));\n    let xmap = |x: String| Vector(fmap(x));\n    let reduce = |x: String, y: String| match x > y {\n        true => x,\n        false => y,\n    };\n\n    let expected = input.clone().into_iter().filter_map(fmap).reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = ParXap::new(DefaultRunner::default(), params, iter, xmap);\n\n    let output = x.reduce(reduce);\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/computational_variants/xap.rs",
    "content": "use crate::computational_variants::fallible_result::ParXapResult;\nuse crate::executor::parallel_compute as prc;\nuse crate::generic_values::TransformableValues;\nuse crate::generic_values::runner_results::Infallible;\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::{UParXap, UsingClone, UsingFun};\nuse crate::{ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParIter, Params};\nuse crate::{ParIterResult, ParIterUsing};\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator that xaps inputs.\n///\n/// *xap* is a generalization of  one-to-one map, filter-map and flat-map operations.\npub struct ParXap<I, Vo, X1, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n}\n\nimpl<I, Vo, X1, R> ParXap<I, Vo, X1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    pub(crate) fn new(orchestrator: R, params: Params, iter: I, xap1: X1) -> Self {\n        Self {\n            orchestrator,\n            params,\n            iter,\n            xap1,\n        }\n    }\n\n    pub(crate) fn destruct(self) -> (R, Params, I, X1) {\n        (self.orchestrator, self.params, self.iter, self.xap1)\n    }\n}\n\nunsafe impl<I, Vo, X1, R> Send for ParXap<I, Vo, X1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n}\n\nunsafe impl<I, Vo, X1, R> Sync for ParXap<I, Vo, X1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n}\n\nimpl<I, Vo, X1, R> ParIter<R> for ParXap<I, Vo, X1, R>\nwhere\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    type Item = Vo::Item;\n\n    fn con_iter(&self) -> &impl ConcurrentIter {\n        &self.iter\n    }\n\n    fn params(&self) -> Params {\n        self.params\n    }\n\n    // params transformations\n\n    fn num_threads(mut self, num_threads: impl Into<NumThreads>) -> Self {\n        self.params = self.params.with_num_threads(num_threads);\n        self\n    }\n\n    fn chunk_size(mut self, chunk_size: impl Into<ChunkSize>) -> Self {\n        self.params = self.params.with_chunk_size(chunk_size);\n        self\n    }\n\n    fn iteration_order(mut self, collect: IterationOrder) -> Self {\n        self.params = self.params.with_collect_ordering(collect);\n        self\n    }\n\n    fn with_runner<Q: ParallelRunner>(self, orchestrator: Q) -> impl ParIter<Q, Item = Self::Item> {\n        let (_, params, iter, x1) = self.destruct();\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    // using transformations\n\n    fn using<'using, U, F>(\n        self,\n        using: F,\n    ) -> impl ParIterUsing<'using, UsingFun<F, U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: 'using,\n        F: Fn(usize) -> U + Sync,\n    {\n        let using = UsingFun::new(using);\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let m1 = move |_: *mut U, t: I::Item| x1(t);\n        UParXap::new(using, orchestrator, params, iter, m1)\n    }\n\n    fn using_clone<U>(\n        self,\n        value: U,\n    ) -> impl ParIterUsing<'static, UsingClone<U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: Clone + 'static,\n    {\n        let using = UsingClone::new(value);\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let m1 = move |_: *mut U, t: I::Item| x1(t);\n        UParXap::new(using, orchestrator, params, iter, m1)\n    }\n\n    // computation transformations\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIter<R, Item = Out>\n    where\n        Map: Fn(Self::Item) -> Out + Sync + Clone,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = move |i: I::Item| {\n            let vo = x1(i);\n            vo.map(map.clone())\n        };\n\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIter<R, Item = Self::Item>\n    where\n        Filter: Fn(&Self::Item) -> bool + Sync + Clone,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = move |i: I::Item| {\n            let values = x1(i);\n            values.filter(filter.clone())\n        };\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn flat_map<IOut, FlatMap>(self, flat_map: FlatMap) -> impl ParIter<R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(Self::Item) -> IOut + Sync + Clone,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = move |i: I::Item| {\n            let vo = x1(i);\n            vo.flat_map(flat_map.clone())\n        };\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn filter_map<Out, FilterMap>(self, filter_map: FilterMap) -> impl ParIter<R, Item = Out>\n    where\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync + Clone,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = move |i: I::Item| {\n            let vo = x1(i);\n            vo.filter_map(filter_map.clone())\n        };\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn take_while<While>(self, take_while: While) -> impl ParIter<R, Item = Self::Item>\n    where\n        While: Fn(&Self::Item) -> bool + Sync + Clone,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let x1 = move |i: I::Item| {\n            let vo = x1(i);\n            vo.whilst(take_while.clone())\n        };\n        ParXap::new(orchestrator, params, iter, x1)\n    }\n\n    fn into_fallible_result<Out, Err>(self) -> impl ParIterResult<R, Item = Out, Err = Err>\n    where\n        Self::Item: IntoResult<Out, Err>,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        ParXapResult::new(orchestrator, params, iter, x1)\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        output.x_collect_into(orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        let (_, Ok(acc)) = prc::reduce::x(orchestrator, params, iter, x1, reduce);\n        acc\n    }\n\n    // early exit\n\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n    {\n        let (orchestrator, params, iter, x1) = self.destruct();\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_num_threads, Ok(result)) = prc::next::x(orchestrator, params, iter, x1);\n                result.map(|x| x.1)\n            }\n            IterationOrder::Arbitrary => {\n                let (_num_threads, Ok(result)) = prc::next_any::x(orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/default_fns.rs",
    "content": "use core::ops::Add;\n\n#[inline(always)]\npub fn map_self<T>(input: T) -> T {\n    input\n}\n\n#[inline(always)]\npub fn map_count<T>(_: T) -> usize {\n    1\n}\n\n#[inline(always)]\npub fn map_copy<T: Copy>(x: &T) -> T {\n    *x\n}\n\n#[inline(always)]\npub fn map_clone<T: Clone>(x: &T) -> T {\n    x.clone()\n}\n\n#[inline(always)]\npub fn reduce_sum<T>(a: T, b: T) -> T\nwhere\n    T: Add<T, Output = T>,\n{\n    a + b\n}\n\n#[inline(always)]\npub fn reduce_unit(_: (), _: ()) {}\n\n// using\n\n#[inline(always)]\npub fn u_map_self<U, T>(_: &mut U, input: T) -> T {\n    input\n}\n\n#[inline(always)]\npub fn u_map_copy<U, T: Copy>(_: &mut U, x: &T) -> T {\n    *x\n}\n\n#[inline(always)]\npub fn u_map_clone<U, T: Clone>(_: &mut U, x: &T) -> T {\n    x.clone()\n}\n\n#[inline(always)]\npub fn u_map_count<U, T>(_: &mut U, _: T) -> usize {\n    1\n}\n\n#[inline(always)]\npub fn u_reduce_sum<U, T>(_: &mut U, a: T, b: T) -> T\nwhere\n    T: Add<T, Output = T>,\n{\n    a + b\n}\n\n#[inline(always)]\npub fn u_reduce_unit<U>(_: &mut U, _: (), _: ()) {}\n"
  },
  {
    "path": "src/enumerate/mod.rs",
    "content": "use crate::{ParIter, ParallelRunner};\n\n/// A parallel iterator with a known and fixed size,\n/// meaning all transformations are 1 to 1.\npub trait ParEnumerate<R: ParallelRunner>: ParIter<R> {\n    /// Creates an iterator which gives each value along with its index in the source collection.\n    ///\n    /// The iterator returned yields pairs `(i, val)`, where `i` is the index in the source collection,\n    /// and `val` is the value returned by the iterator.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let vec = vec![26i32, -27, 5];\n    ///\n    /// let max_abs = vec.into_par().enumerate().max_by_key(|(_idx, x)| x.abs());\n    /// assert_eq!(max_abs, Some((1, -27)));\n    /// ```\n    fn enumerate(self) -> impl ParIter<R, Item = (usize, Self::Item)>;\n}\n"
  },
  {
    "path": "src/env.rs",
    "content": "use core::num::NonZeroUsize;\n\n#[cfg(feature = \"std\")]\nconst MAX_NUM_THREADS_ENV_VARIABLE: &str = \"ORX_PARALLEL_MAX_NUM_THREADS\";\n\npub fn max_num_threads_by_env_variable() -> Option<NonZeroUsize> {\n    #[cfg(feature = \"std\")]\n    match std::env::var(MAX_NUM_THREADS_ENV_VARIABLE) {\n        Ok(s) => match s.parse::<usize>() {\n            Ok(x) => NonZeroUsize::new(x), // None if 0; Some(x) if x is set to a positive bound\n            Err(_e) => None,               // not a number, ignored assuming no bound\n        },\n        Err(_e) => None, // not set, no bound\n    }\n\n    #[cfg(not(feature = \"std\"))]\n    None\n}\n"
  },
  {
    "path": "src/executor/computation_kind.rs",
    "content": "/// Computation kind.\n#[derive(Clone, Copy)]\npub enum ComputationKind {\n    /// Computation where outputs are collected into a collection.\n    Collect,\n    /// Computation where the inputs or intermediate results are reduced to a single value.\n    Reduce,\n    /// Computation which allows for early returns, such as `find` operation.\n    EarlyReturn,\n}\n"
  },
  {
    "path": "src/executor/executor_with_diagnostics/mod.rs",
    "content": "mod parallel_executor;\nmod shared_state;\nmod thread_executor;\n\npub use parallel_executor::ParallelExecutorWithDiagnostics;\n"
  },
  {
    "path": "src/executor/executor_with_diagnostics/parallel_executor.rs",
    "content": "use super::{\n    shared_state::SharedStateWithDiagnostics, thread_executor::ThreadExecutorWithDiagnostics,\n};\nuse crate::ParallelExecutor;\nuse crate::runner::{ComputationKind, NumSpawned};\nuse orx_concurrent_iter::ConcurrentIter;\nuse std::num::NonZeroUsize;\n\n/// A parallel executor which wraps another parallel executor `E` and collects diagnostics about:\n///\n/// * how many threads are used for the parallel computation\n/// * how many times each thread received a tasks\n/// * average chunk size; i.e., average number of tasks, that each thread received\n/// * and finally, explicit chunk sizes for the first task assignments.\n///\n/// The diagnostics are printed on the stdout once the parallel computation is completed.\n/// Therefore, this executor is suitable only for test purposed, but not for production.\n///\n/// Any executor can be converted into executor with diagnostics.\n/// In the example below, executor of the default runner is converted to executor with diagnostics.\n///\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// // normal execution\n///\n/// let range = 0..4096;\n/// let sum = range\n///     .par()\n///     .map(|x| x + 1)\n///     .filter(|x| x.is_multiple_of(2))\n///     .sum();\n/// assert_eq!(sum, 4196352);\n///\n/// // execution with diagnostics\n///\n/// let range = 0..4096;\n/// let sum = range\n///     .par()\n///     .with_runner(DefaultRunner::default().with_diagnostics())\n///     .map(|x| x + 1)\n///     .filter(|x| x.is_multiple_of(2))\n///     .sum();\n/// assert_eq!(sum, 4196352);\n///\n/// // prints diagnostics, which looks something like the following:\n/// //\n/// // - Number of threads used = 5\n/// //\n/// // - [Thread idx]: num_calls, num_tasks, avg_chunk_size, first_chunk_sizes\n/// //   - [0]: 25, 1600, 64, [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]\n/// //   - [1]: 26, 1664, 64, [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]\n/// //   - [2]: 13, 832, 64, [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]\n/// //   - [3]: 0, 0, 0, []\n/// //   - [4]: 0, 0, 0, []\n/// ```\n#[derive(Clone)]\npub struct ParallelExecutorWithDiagnostics<E>\nwhere\n    E: ParallelExecutor,\n{\n    executor: E,\n}\n\nimpl<E> ParallelExecutor for ParallelExecutorWithDiagnostics<E>\nwhere\n    E: ParallelExecutor,\n{\n    type SharedState = SharedStateWithDiagnostics<E::SharedState>;\n\n    type ThreadExecutor = ThreadExecutorWithDiagnostics<E>;\n\n    fn new(\n        kind: ComputationKind,\n        params: crate::Params,\n        initial_input_len: Option<usize>,\n        max_num_threads: NonZeroUsize,\n    ) -> Self {\n        let executor = E::new(kind, params, initial_input_len, max_num_threads);\n        Self { executor }\n    }\n\n    fn new_shared_state(&self) -> Self::SharedState {\n        let inner_state = self.executor.new_shared_state();\n        SharedStateWithDiagnostics::new(inner_state)\n    }\n\n    fn do_spawn_new<I>(\n        &self,\n        num_spawned: NumSpawned,\n        shared_state: &Self::SharedState,\n        iter: &I,\n    ) -> bool\n    where\n        I: ConcurrentIter,\n    {\n        self.executor\n            .do_spawn_new(num_spawned, shared_state.inner(), iter)\n    }\n\n    fn new_thread_executor(\n        &self,\n        thread_idx: usize,\n        shared_state: &Self::SharedState,\n    ) -> Self::ThreadExecutor {\n        let executor = self\n            .executor\n            .new_thread_executor(thread_idx, shared_state.inner());\n        ThreadExecutorWithDiagnostics::new(thread_idx, executor)\n    }\n\n    fn complete_task(self, shared_state: Self::SharedState) {\n        shared_state.display();\n    }\n}\n"
  },
  {
    "path": "src/executor/executor_with_diagnostics/shared_state.rs",
    "content": "use alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse std::println;\n\npub struct SharedStateWithDiagnostics<S> {\n    inner: S,\n    task_counts: ConcurrentBag<(usize, Vec<usize>)>, // (thread_idx, chunk sizes)\n}\n\nimpl<S> SharedStateWithDiagnostics<S> {\n    pub fn new(inner: S) -> Self {\n        let tasks = ConcurrentBag::new();\n        Self {\n            inner,\n            task_counts: tasks,\n        }\n    }\n\n    #[inline(always)]\n    pub fn inner(&self) -> &S {\n        &self.inner\n    }\n\n    pub fn add_task_counts_of_thread(&self, thread_idx: usize, chunk_sizes: Vec<usize>) {\n        self.task_counts.push((thread_idx, chunk_sizes));\n    }\n\n    pub fn display(self) {\n        let mut task_counts = self.task_counts.into_inner().to_vec();\n        task_counts.sort_by_key(|x| x.0);\n\n        println!(\"\\n# Parallel Executor Diagnostics\");\n        println!(\"\\n- Number of threads used = {}\", task_counts.len());\n\n        println!(\"\\n- [Thread idx]: num_calls, num_tasks, avg_chunk_size, first_chunk_sizes\");\n\n        for (thread_idx, task_counts) in task_counts {\n            let total: usize = task_counts.iter().sum();\n            let num_calls = task_counts.len();\n            let avg_chunk_size = match num_calls {\n                0 => 0,\n                n => total / n,\n            };\n            let first_chunks: Vec<_> = task_counts.iter().copied().take(10).collect();\n\n            println!(\n                \"  - [{thread_idx}]: {num_calls}, {total}, {avg_chunk_size}, {first_chunks:?}\",\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/executor/executor_with_diagnostics/thread_executor.rs",
    "content": "use super::shared_state::SharedStateWithDiagnostics;\nuse crate::{ParallelExecutor, ThreadExecutor};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::ConcurrentIter;\n\npub struct ThreadExecutorWithDiagnostics<E>\nwhere\n    E: ParallelExecutor,\n{\n    thread_idx: usize,\n    executor: E::ThreadExecutor,\n    task_counts: Vec<usize>, // (thread_idx, chunk_size)\n}\n\nimpl<E> ThreadExecutorWithDiagnostics<E>\nwhere\n    E: ParallelExecutor,\n{\n    pub(super) fn new(thread_idx: usize, executor: E::ThreadExecutor) -> Self {\n        Self {\n            thread_idx,\n            executor,\n            task_counts: vec![],\n        }\n    }\n}\n\nimpl<E> ThreadExecutor for ThreadExecutorWithDiagnostics<E>\nwhere\n    E: ParallelExecutor,\n{\n    type SharedState = SharedStateWithDiagnostics<E::SharedState>;\n\n    fn next_chunk_size<I>(&self, shared_state: &Self::SharedState, iter: &I) -> usize\n    where\n        I: ConcurrentIter,\n    {\n        self.executor.next_chunk_size(shared_state.inner(), iter)\n    }\n\n    fn begin_chunk(&mut self, chunk_size: usize) {\n        self.executor.begin_chunk(chunk_size);\n    }\n\n    fn complete_chunk(&mut self, shared_state: &Self::SharedState, chunk_size: usize) {\n        self.task_counts.push(chunk_size);\n        self.executor\n            .complete_chunk(shared_state.inner(), chunk_size);\n    }\n\n    fn complete_task(&mut self, shared_state: &Self::SharedState) {\n        self.executor.complete_task(shared_state.inner());\n        shared_state.add_task_counts_of_thread(self.thread_idx, self.task_counts.clone());\n    }\n}\n"
  },
  {
    "path": "src/executor/fixed_chunk_executor/chunk_size.rs",
    "content": "use crate::{parameters::ChunkSize, runner::ComputationKind};\nuse core::num::NonZeroUsize;\n\nconst MAX_CHUNK_SIZE: usize = 1 << 20;\nconst DESIRED_MIN_CHUNK_SIZE: usize = 64;\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum ResolvedChunkSize {\n    Min(usize),\n    Exact(usize),\n}\n\nimpl ResolvedChunkSize {\n    pub fn new(\n        kind: ComputationKind,\n        initial_len: Option<usize>,\n        max_num_threads: NonZeroUsize,\n        chunk_size: ChunkSize,\n    ) -> Self {\n        match chunk_size {\n            ChunkSize::Auto => Self::Min(auto_chunk_size(kind, initial_len, max_num_threads)),\n            ChunkSize::Min(x) => Self::Min(min_chunk_size(initial_len, max_num_threads, x.into())),\n            ChunkSize::Exact(x) => Self::Exact(x.into()),\n        }\n    }\n\n    pub fn chunk_size(self) -> usize {\n        match self {\n            Self::Min(x) => x,\n            Self::Exact(x) => x,\n        }\n    }\n}\n\nconst fn min_required_len(kind: ComputationKind, one_round_len: usize) -> usize {\n    match kind {\n        ComputationKind::Collect => one_round_len * 4,\n        ComputationKind::Reduce => one_round_len * 4,\n        ComputationKind::EarlyReturn => one_round_len * 8,\n    }\n}\n\nfn auto_chunk_size(\n    kind: ComputationKind,\n    initial_len: Option<usize>,\n    max_num_threads: NonZeroUsize,\n) -> usize {\n    fn find_chunk_size(kind: ComputationKind, input_len: usize, num_threads: usize) -> usize {\n        let mut chunk_size = MAX_CHUNK_SIZE;\n\n        loop {\n            let one_round_len = chunk_size * num_threads;\n\n            // heterogeneity buffer\n            if input_len >= min_required_len(kind, one_round_len) {\n                break;\n            }\n\n            // len is still greater, we don't want chunk size to be too small\n            if input_len >= one_round_len && chunk_size <= DESIRED_MIN_CHUNK_SIZE {\n                break;\n            }\n\n            // absolute breaking condition\n            if chunk_size == 1 {\n                break;\n            }\n\n            chunk_size >>= 1;\n        }\n\n        chunk_size\n    }\n\n    match initial_len {\n        None => 1, // TODO: is this a good choice?\n        Some(0) => 1,\n        Some(input_len) => find_chunk_size(kind, input_len, max_num_threads.into()),\n    }\n}\n\nfn min_chunk_size(\n    initial_len: Option<usize>,\n    max_num_threads: NonZeroUsize,\n    chunk_size: usize,\n) -> usize {\n    let max_num_threads: usize = max_num_threads.into();\n    match initial_len {\n        None => chunk_size,\n        Some(0) => 1,\n        Some(len) => {\n            let one_round_len = max_num_threads * chunk_size;\n            match one_round_len > len {\n                true => div_ceil(len, max_num_threads),\n                false => chunk_size,\n            }\n        }\n    }\n}\n\nconst fn div_ceil(number: usize, divider: usize) -> usize {\n    let x = number / divider;\n    let remainder = number - x * divider;\n    x + if remainder > 0 { 1 } else { 0 }\n}\n"
  },
  {
    "path": "src/executor/fixed_chunk_executor/mod.rs",
    "content": "mod chunk_size;\nmod parallel_executor;\nmod thread_executor;\n\npub use parallel_executor::FixedChunkRunner;\n"
  },
  {
    "path": "src/executor/fixed_chunk_executor/parallel_executor.rs",
    "content": "use super::{chunk_size::ResolvedChunkSize, thread_executor::FixedChunkThreadExecutor};\nuse crate::runner::ComputationKind;\nuse crate::{\n    executor::parallel_executor::ParallelExecutor, parameters::Params, runner::NumSpawned,\n};\nuse core::{\n    num::NonZeroUsize,\n    sync::atomic::{AtomicUsize, Ordering},\n};\nuse orx_concurrent_iter::ConcurrentIter;\n\nconst LAG_PERIODICITY: usize = 4;\n\npub struct FixedChunkRunner {\n    initial_len: Option<usize>,\n    resolved_chunk_size: ResolvedChunkSize,\n    max_num_threads: usize,\n    current_chunk_size: AtomicUsize,\n}\n\nimpl Clone for FixedChunkRunner {\n    fn clone(&self) -> Self {\n        Self {\n            initial_len: self.initial_len,\n            resolved_chunk_size: self.resolved_chunk_size,\n            max_num_threads: self.max_num_threads,\n            current_chunk_size: self.current_chunk_size.load(Ordering::Relaxed).into(),\n        }\n    }\n}\n\nimpl FixedChunkRunner {\n    fn spawn_new(&self, num_spawned: usize, remaining: Option<usize>) -> bool {\n        match (num_spawned, remaining) {\n            (_, Some(0)) => false,\n            (x, _) if x >= self.max_num_threads => false,\n            _ => true,\n        }\n    }\n\n    fn next_chunk(&self, num_spawned: usize, remaining_len: Option<usize>) -> Option<usize> {\n        match (self.initial_len, remaining_len) {\n            (Some(initial_len), Some(remaining_len)) => {\n                self.next_chunk_size_known_len(num_spawned, initial_len, remaining_len)\n            }\n            _ => self.next_chunk_size_unknown_len(num_spawned),\n        }\n    }\n\n    fn next_chunk_size_unknown_len(&self, num_spawned: usize) -> Option<usize> {\n        match num_spawned {\n            x if x >= self.max_num_threads => None,\n            _ => Some(self.resolved_chunk_size.chunk_size()),\n        }\n    }\n\n    fn next_chunk_size_known_len(\n        &self,\n        num_spawned: usize,\n        initial_len: usize,\n        remaining_len: usize,\n    ) -> Option<usize> {\n        match num_spawned {\n            x if x >= self.max_num_threads => None,\n            _ => match self.resolved_chunk_size {\n                ResolvedChunkSize::Exact(x) => Some(x),\n                ResolvedChunkSize::Min(x) => {\n                    let chunk_size = match num_spawned {\n                        0 => x,\n                        _ => {\n                            let done = initial_len - remaining_len;\n                            let done_per_thread = done / num_spawned;\n                            let num_chunks_per_thread = (done_per_thread / x).max(1);\n                            let num_chunks_per_thread = num_chunks_per_thread.max(1);\n                            num_chunks_per_thread * x\n                        }\n                    };\n\n                    Some(chunk_size)\n                }\n            },\n        }\n    }\n}\n\nimpl ParallelExecutor for FixedChunkRunner {\n    type SharedState = ();\n\n    type ThreadExecutor = FixedChunkThreadExecutor;\n\n    fn new(\n        kind: ComputationKind,\n        params: Params,\n        initial_len: Option<usize>,\n        max_num_threads: NonZeroUsize,\n    ) -> Self {\n        let resolved_chunk_size =\n            ResolvedChunkSize::new(kind, initial_len, max_num_threads, params.chunk_size);\n\n        Self {\n            initial_len,\n            resolved_chunk_size,\n            max_num_threads: max_num_threads.into(),\n            current_chunk_size: resolved_chunk_size.chunk_size().into(),\n        }\n    }\n\n    fn new_shared_state(&self) -> Self::SharedState {}\n\n    fn do_spawn_new<I>(&self, num_spawned: NumSpawned, _: &Self::SharedState, iter: &I) -> bool\n    where\n        I: ConcurrentIter,\n    {\n        let num_spawned = num_spawned.into_inner();\n        if num_spawned.is_multiple_of(LAG_PERIODICITY) {\n            match self.next_chunk(num_spawned, iter.try_get_len()) {\n                Some(c) => self.current_chunk_size.store(c, Ordering::Relaxed),\n                None => return false,\n            }\n        }\n\n        self.spawn_new(num_spawned, iter.try_get_len())\n    }\n\n    fn new_thread_executor(&self, _: usize, _: &Self::SharedState) -> Self::ThreadExecutor {\n        Self::ThreadExecutor {\n            chunk_size: self.current_chunk_size.load(Ordering::Relaxed),\n        }\n    }\n\n    fn complete_task(self, _: Self::SharedState) {}\n}\n"
  },
  {
    "path": "src/executor/fixed_chunk_executor/thread_executor.rs",
    "content": "use crate::executor::thread_executor::ThreadExecutor;\nuse orx_concurrent_iter::ConcurrentIter;\n\npub struct FixedChunkThreadExecutor {\n    pub(super) chunk_size: usize,\n}\n\nimpl ThreadExecutor for FixedChunkThreadExecutor {\n    type SharedState = ();\n\n    #[inline(always)]\n    fn next_chunk_size<I>(&self, _: &Self::SharedState, _: &I) -> usize\n    where\n        I: ConcurrentIter,\n    {\n        self.chunk_size\n    }\n\n    fn begin_chunk(&mut self, _: usize) {}\n\n    fn complete_chunk(&mut self, _: &Self::SharedState, _: usize) {}\n\n    fn complete_task(&mut self, _: &Self::SharedState) {}\n}\n"
  },
  {
    "path": "src/executor/mod.rs",
    "content": "#[cfg(feature = \"std\")]\nmod executor_with_diagnostics;\nmod fixed_chunk_executor;\npub(crate) mod parallel_compute;\nmod parallel_executor;\nmod thread_compute;\nmod thread_executor;\n\n#[cfg(feature = \"std\")]\npub use executor_with_diagnostics::ParallelExecutorWithDiagnostics;\npub use parallel_executor::ParallelExecutor;\npub use thread_executor::ThreadExecutor;\n\n/// Default parallel executor.\npub type DefaultExecutor = fixed_chunk_executor::FixedChunkRunner;\n"
  },
  {
    "path": "src/executor/parallel_compute/collect_arbitrary.rs",
    "content": "use crate::Params;\nuse crate::executor::thread_compute as th;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::ParallelCollectArbitrary;\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf, ThreadRunnerOf};\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\n#[cfg(test)]\npub fn m<C, I, O, M1, P>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(I::Item) -> O + Sync,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    let capacity_bound = pinned_vec.capacity_bound();\n    let offset = pinned_vec.len();\n    let mut bag: ConcurrentBag<O, P> = pinned_vec.into();\n    match iter.try_get_len() {\n        Some(iter_len) => bag.reserve_maximum_capacity(offset + iter_len),\n        None => bag.reserve_maximum_capacity(capacity_bound),\n    };\n\n    let thread_work = |_, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n        th::collect_arbitrary::m(thread_runner, iter, state, &map1, &bag);\n    };\n    let num_spawned = orchestrator.run_all(params, iter, ComputationKind::Collect, thread_work);\n\n    let values = bag.into_inner();\n    (num_spawned, values)\n}\n\npub fn x<C, I, Vo, X1, P>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (NumSpawned, ParallelCollectArbitrary<Vo, P>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let capacity_bound = pinned_vec.capacity_bound();\n    let offset = pinned_vec.len();\n\n    let mut bag: ConcurrentBag<Vo::Item, P> = pinned_vec.into();\n    match iter.try_get_len() {\n        Some(iter_len) => bag.reserve_maximum_capacity(offset + iter_len),\n        None => bag.reserve_maximum_capacity(capacity_bound),\n    };\n\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n        th::collect_arbitrary::x(thread_runner, iter, state, &xap1, &bag).into_result()\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n\n    let result = match result {\n        Err(error) => ParallelCollectArbitrary::StoppedByError { error },\n        Ok(_) => ParallelCollectArbitrary::AllOrUntilWhileCollected {\n            pinned_vec: bag.into_inner(),\n        },\n    };\n\n    (num_spawned, result)\n}\n"
  },
  {
    "path": "src/executor/parallel_compute/collect_ordered.rs",
    "content": "use crate::Params;\nuse crate::executor::thread_compute as th;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{Fallibility, ParallelCollect};\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf, ThreadRunnerOf};\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_concurrent_ordered_bag::ConcurrentOrderedBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub fn m<C, I, O, M1, P>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(I::Item) -> O + Sync,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    let offset = pinned_vec.len();\n    let o_bag: ConcurrentOrderedBag<O, P> = pinned_vec.into();\n\n    let thread_do = |_, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n        th::collect_ordered::m(thread_runner, iter, state, &map1, &o_bag, offset);\n    };\n    let num_spawned = orchestrator.run_all(params, iter, ComputationKind::Collect, thread_do);\n\n    let values = unsafe { o_bag.into_inner().unwrap_only_if_counts_match() };\n    (num_spawned, values)\n}\n\npub fn x<C, I, Vo, X1, P>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (NumSpawned, ParallelCollect<Vo, P>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    <Vo::Fallibility as Fallibility>::Error: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n        th::collect_ordered::x(thread_runner, iter, state, &xap1).into_result()\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n\n    let result = match result {\n        Err(error) => ParallelCollect::StoppedByError { error },\n        Ok(results) => ParallelCollect::reduce(results, pinned_vec),\n    };\n    (num_spawned, result)\n}\n"
  },
  {
    "path": "src/executor/parallel_compute/mod.rs",
    "content": "pub(crate) mod collect_arbitrary;\npub(crate) mod collect_ordered;\npub(crate) mod next;\npub(crate) mod next_any;\npub(crate) mod reduce;\n"
  },
  {
    "path": "src/executor/parallel_compute/next.rs",
    "content": "use crate::Params;\nuse crate::executor::thread_compute as th;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{Fallibility, NextSuccess, NextWithIdx};\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf};\nuse orx_concurrent_iter::ConcurrentIter;\n\npub fn m<C, I, O, M1>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n) -> (NumSpawned, Option<O>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, thread_runner| {\n        Ok(th::next::m(thread_runner, iter, state, &map1))\n    };\n    let (num_spawned, result) =\n        orchestrator.map_infallible(params, iter, ComputationKind::Collect, thread_map);\n\n    let next = match result {\n        Ok(results) => results\n            .into_iter()\n            .flatten()\n            .min_by_key(|x| x.0)\n            .map(|x| x.1),\n    };\n    (num_spawned, next)\n}\n\ntype ResultNext<Vo> = Result<\n    Option<(usize, <Vo as Values>::Item)>,\n    <<Vo as Values>::Fallibility as Fallibility>::Error,\n>;\n\npub fn x<C, I, Vo, X1>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n) -> (NumSpawned, ResultNext<Vo>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, th_runner| match th::next::x(\n        th_runner, iter, state, &xap1,\n    ) {\n        NextWithIdx::Found { idx, value } => Ok(Some(NextSuccess::Found { idx, value })),\n        NextWithIdx::NotFound => Ok(None),\n        NextWithIdx::StoppedByWhileCondition { idx } => {\n            Ok(Some(NextSuccess::StoppedByWhileCondition { idx }))\n        }\n        NextWithIdx::StoppedByError { error } => Err(error),\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n    let next = result.map(|results| NextSuccess::reduce(results.into_iter().flatten()));\n    (num_spawned, next)\n}\n"
  },
  {
    "path": "src/executor/parallel_compute/next_any.rs",
    "content": "use crate::Params;\nuse crate::executor::thread_compute as th;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::Fallibility;\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf};\nuse orx_concurrent_iter::ConcurrentIter;\n\npub fn m<C, I, O, M1>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n) -> (NumSpawned, Option<O>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(I::Item) -> O + Sync,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, thread_runner| {\n        Ok(th::next_any::m(thread_runner, iter, state, &map1))\n    };\n    let (num_spawned, result) =\n        orchestrator.map_infallible(params, iter, ComputationKind::Collect, thread_map);\n\n    let next = match result {\n        Ok(results) => results.into_iter().flatten().next(),\n    };\n    (num_spawned, next)\n}\n\ntype ResultNextAny<Vo> =\n    Result<Option<<Vo as Values>::Item>, <<Vo as Values>::Fallibility as Fallibility>::Error>;\n\npub fn x<C, I, Vo, X1>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n) -> (NumSpawned, ResultNextAny<Vo>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, th_runner| {\n        th::next_any::x(th_runner, iter, state, &xap1)\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n    let next = result.map(|results| results.into_iter().flatten().next());\n    (num_spawned, next)\n}\n"
  },
  {
    "path": "src/executor/parallel_compute/reduce.rs",
    "content": "use crate::Params;\nuse crate::executor::thread_compute as th;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::Fallibility;\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf, ThreadRunnerOf};\nuse orx_concurrent_iter::ConcurrentIter;\n\npub fn m<C, I, O, M1, Red>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n    reduce: Red,\n) -> (NumSpawned, Option<O>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O + Sync,\n    Red: Fn(O, O) -> O + Sync,\n    O: Send,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n        Ok(th::reduce::m(thread_runner, iter, state, &map1, &reduce))\n    };\n    let (num_spawned, result) =\n        orchestrator.map_infallible(params, iter, ComputationKind::Collect, thread_map);\n\n    let acc = match result {\n        Ok(results) => results.into_iter().flatten().reduce(reduce),\n    };\n\n    (num_spawned, acc)\n}\n\ntype ResultReduce<Vo> =\n    Result<Option<<Vo as Values>::Item>, <<Vo as Values>::Fallibility as Fallibility>::Error>;\n\npub fn x<C, I, Vo, X1, Red>(\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    reduce: Red,\n) -> (NumSpawned, ResultReduce<Vo>)\nwhere\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo + Sync,\n    Red: Fn(Vo::Item, Vo::Item) -> Vo::Item + Sync,\n{\n    let thread_map = |_, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n        th::reduce::x(thread_runner, iter, state, &xap1, &reduce).into_result()\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n    let acc = result.map(|results| results.into_iter().flatten().reduce(reduce));\n    (num_spawned, acc)\n}\n"
  },
  {
    "path": "src/executor/parallel_executor.rs",
    "content": "use super::thread_executor::ThreadExecutor;\nuse crate::{\n    parameters::Params,\n    runner::{ComputationKind, NumSpawned},\n};\nuse core::num::NonZeroUsize;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel executor which is responsible for taking a computation defined as a composition\n/// of iterator methods, spawns threads, shares tasks and returns the result of the parallel\n/// execution.\npub trait ParallelExecutor: Sized + Sync + 'static + Clone {\n    /// Data shared to the thread executors.\n    type SharedState: Send + Sync;\n\n    /// Thread executor that is responsible for executing the tasks allocated to a thread.\n    type ThreadExecutor: ThreadExecutor<SharedState = Self::SharedState>;\n\n    /// Creates a new parallel executor for the given computation `kind`, parallelization `params`\n    /// and `initial_input_len`.\n    fn new(\n        kind: ComputationKind,\n        params: Params,\n        initial_input_len: Option<usize>,\n        max_num_threads: NonZeroUsize,\n    ) -> Self;\n\n    /// Creates an initial shared state.\n    fn new_shared_state(&self) -> Self::SharedState;\n\n    /// Returns true if it is beneficial to spawn a new thread provided that:\n    ///\n    /// * `num_spawned` threads are already been spawned, and\n    /// * `shared_state` is the current parallel execution state.\n    fn do_spawn_new<I>(\n        &self,\n        num_spawned: NumSpawned,\n        shared_state: &Self::SharedState,\n        iter: &I,\n    ) -> bool\n    where\n        I: ConcurrentIter;\n\n    /// Creates a new thread executor provided that the current parallel execution state is\n    /// `shared_state`.\n    fn new_thread_executor(\n        &self,\n        thread_idx: usize,\n        shared_state: &Self::SharedState,\n    ) -> Self::ThreadExecutor;\n\n    /// Executes the finalization tasks when the entire parallel computation is completed.\n    fn complete_task(self, shared_state: Self::SharedState);\n}\n"
  },
  {
    "path": "src/executor/thread_compute/collect_arbitrary.rs",
    "content": "use crate::ThreadExecutor;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{Stop, ThreadCollectArbitrary};\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\n// m\n\n#[cfg(test)]\npub fn m<C, I, O, M1, P>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n    bag: &ConcurrentBag<O, P>,\n) where\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O,\n    P: IntoConcurrentPinnedVec<O>,\n    O: Send,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(value) => _ = bag.push(map1(value)),\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => _ = bag.extend(chunk.map(&map1)),\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n}\n\n// x\n\npub fn x<C, I, Vo, X1, P>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n    bag: &ConcurrentBag<Vo::Item, P>,\n) -> ThreadCollectArbitrary<Vo::Fallibility>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(I::Item) -> Vo,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n    Vo::Item: Send,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(value) => {\n                    // TODO: possible to try to get len and bag.extend(values_vt.values()) when available, same holds for chunk below\n                    let vo = xap1(value);\n                    let done = vo.push_to_bag(bag);\n\n                    if let Some(stop) = Vo::arbitrary_push_to_stop(done) {\n                        iter.skip_to_end();\n                        runner.complete_chunk(shared_state, chunk_size);\n                        runner.complete_task(shared_state);\n                        match stop {\n                            Stop::DueToWhile => {\n                                return ThreadCollectArbitrary::StoppedByWhileCondition;\n                            }\n                            Stop::DueToError { error } => {\n                                return ThreadCollectArbitrary::StoppedByError { error };\n                            }\n                        }\n                    }\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        for value in chunk {\n                            let vo = xap1(value);\n                            let done = vo.push_to_bag(bag);\n\n                            if let Some(stop) = Vo::arbitrary_push_to_stop(done) {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                match stop {\n                                    Stop::DueToWhile => {\n                                        return ThreadCollectArbitrary::StoppedByWhileCondition;\n                                    }\n                                    Stop::DueToError { error } => {\n                                        return ThreadCollectArbitrary::StoppedByError { error };\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n\n    ThreadCollectArbitrary::AllCollected\n}\n"
  },
  {
    "path": "src/executor/thread_compute/collect_ordered.rs",
    "content": "use crate::ThreadExecutor;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{StopWithIdx, ThreadCollect};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\nuse orx_concurrent_ordered_bag::ConcurrentOrderedBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub fn m<C, I, O, M1, P>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n    o_bag: &ConcurrentOrderedBag<O, P>,\n    offset: usize,\n) where\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O,\n    P: IntoConcurrentPinnedVec<O>,\n    O: Send,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, value)) => unsafe { o_bag.set_value(offset + idx, map1(value)) },\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((begin_idx, chunk)) => {\n                        let values = chunk.map(map1);\n                        unsafe { o_bag.set_values(offset + begin_idx, values) };\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n}\n\npub fn x<C, I, Vo, X1>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n) -> ThreadCollect<Vo>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(I::Item) -> Vo,\n{\n    let mut collected = Vec::new();\n    let out_vec = &mut collected;\n\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, i)) => {\n                    let vo = xap1(i);\n                    let done = vo.push_to_vec_with_idx(idx, out_vec);\n                    if let Some(stop) = Vo::ordered_push_to_stop(done) {\n                        iter.skip_to_end();\n                        runner.complete_chunk(shared_state, chunk_size);\n                        runner.complete_task(shared_state);\n                        match stop {\n                            StopWithIdx::DueToWhile { idx } => {\n                                return ThreadCollect::StoppedByWhileCondition {\n                                    vec: collected,\n                                    stopped_idx: idx,\n                                };\n                            }\n                            StopWithIdx::DueToError { idx: _, error } => {\n                                return ThreadCollect::StoppedByError { error };\n                            }\n                        }\n                    }\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((chunk_begin_idx, chunk)) => {\n                        for (within_chunk_idx, value) in chunk.enumerate() {\n                            let vo = xap1(value);\n                            let done = vo.push_to_vec_with_idx(chunk_begin_idx, out_vec);\n                            if let Some(stop) = Vo::ordered_push_to_stop(done) {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                match stop {\n                                    StopWithIdx::DueToWhile { idx } => {\n                                        return ThreadCollect::StoppedByWhileCondition {\n                                            vec: collected,\n                                            stopped_idx: idx + within_chunk_idx,\n                                        };\n                                    }\n                                    StopWithIdx::DueToError { idx: _, error } => {\n                                        return ThreadCollect::StoppedByError { error };\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n\n    ThreadCollect::AllCollected { vec: collected }\n}\n"
  },
  {
    "path": "src/executor/thread_compute/mod.rs",
    "content": "pub(super) mod collect_arbitrary;\npub(super) mod collect_ordered;\npub(super) mod next;\npub(super) mod next_any;\npub(super) mod reduce;\n"
  },
  {
    "path": "src/executor/thread_compute/next.rs",
    "content": "use crate::{\n    ThreadExecutor,\n    generic_values::Values,\n    generic_values::runner_results::{Next, NextWithIdx},\n};\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\n\npub fn m<C, I, O, M1>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n) -> Option<(usize, O)>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, i)) => {\n                    let first = map1(i);\n                    iter.skip_to_end();\n                    runner.complete_chunk(shared_state, chunk_size);\n                    runner.complete_task(shared_state);\n                    return Some((idx, first));\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((idx, mut chunk)) => {\n                        if let Some(i) = chunk.next() {\n                            let first = map1(i);\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Some((idx, first));\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    None\n}\n\npub fn x<C, I, Vo, X1>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n) -> NextWithIdx<Vo>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(I::Item) -> Vo,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, i)) => {\n                    let vt = xap1(i);\n                    match vt.next() {\n                        Next::Done { value } => {\n                            if let Some(value) = value {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                return NextWithIdx::Found { idx, value };\n                            }\n                        }\n                        Next::StoppedByError { error } => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return NextWithIdx::StoppedByError { error };\n                        }\n                        Next::StoppedByWhileCondition => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return NextWithIdx::StoppedByWhileCondition { idx };\n                        }\n                    }\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((idx, chunk)) => {\n                        for i in chunk {\n                            let vt = xap1(i);\n                            match vt.next() {\n                                Next::Done { value } => {\n                                    if let Some(value) = value {\n                                        iter.skip_to_end();\n                                        runner.complete_chunk(shared_state, chunk_size);\n                                        runner.complete_task(shared_state);\n                                        return NextWithIdx::Found { idx, value };\n                                    }\n                                }\n                                Next::StoppedByError { error } => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return NextWithIdx::StoppedByError { error };\n                                }\n                                Next::StoppedByWhileCondition => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return NextWithIdx::StoppedByWhileCondition { idx };\n                                }\n                            }\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    NextWithIdx::NotFound\n}\n"
  },
  {
    "path": "src/executor/thread_compute/next_any.rs",
    "content": "use crate::{\n    ThreadExecutor,\n    generic_values::Values,\n    generic_values::runner_results::{Fallibility, Next},\n};\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\n\npub fn m<C, I, O, M1>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n) -> Option<O>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(I::Item) -> O,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let first = map1(i);\n                    iter.skip_to_end();\n                    runner.complete_chunk(shared_state, chunk_size);\n                    runner.complete_task(shared_state);\n                    return Some(first);\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(mut chunk) => {\n                        if let Some(i) = chunk.next() {\n                            let first = map1(i);\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Some(first);\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    None\n}\n\npub fn x<C, I, Vo, X1>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n) -> Result<Option<Vo::Item>, <Vo::Fallibility as Fallibility>::Error>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(I::Item) -> Vo,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let vt = xap1(i);\n                    match vt.next() {\n                        Next::Done { value } => {\n                            if let Some(value) = value {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                return Ok(Some(value));\n                            }\n                        }\n                        Next::StoppedByError { error } => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Err(error);\n                        }\n                        Next::StoppedByWhileCondition => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Ok(None);\n                        }\n                    }\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        for i in chunk {\n                            let vt = xap1(i);\n                            match vt.next() {\n                                Next::Done { value } => {\n                                    if let Some(value) = value {\n                                        iter.skip_to_end();\n                                        runner.complete_chunk(shared_state, chunk_size);\n                                        runner.complete_task(shared_state);\n                                        return Ok(Some(value));\n                                    }\n                                }\n                                Next::StoppedByError { error } => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return Err(error);\n                                }\n                                Next::StoppedByWhileCondition => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return Ok(None);\n                                }\n                            }\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    Ok(None)\n}\n"
  },
  {
    "path": "src/executor/thread_compute/reduce.rs",
    "content": "use crate::{\n    ThreadExecutor,\n    generic_values::{\n        Values,\n        runner_results::{Reduce, StopReduce},\n    },\n};\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\n\n// m\n\npub fn m<C, I, O, M1, Red>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n    reduce: &Red,\n) -> Option<O>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(I::Item) -> O,\n    Red: Fn(O, O) -> O,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    let mut acc = None;\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let y = map1(i);\n                    acc = match acc {\n                        Some(x) => Some(reduce(x, y)),\n                        None => Some(y),\n                    };\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        // println!(\"chunk = {}\", chunk.len());\n                        let res = chunk.map(map1).reduce(reduce);\n                        acc = match acc {\n                            Some(x) => match res {\n                                Some(y) => Some(reduce(x, y)),\n                                None => Some(x),\n                            },\n                            None => res,\n                        };\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    acc\n}\n\n// x\n\npub fn x<C, I, Vo, X1, Red>(\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n    reduce: &Red,\n) -> Reduce<Vo>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(I::Item) -> Vo,\n    Red: Fn(Vo::Item, Vo::Item) -> Vo::Item,\n{\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    let mut acc = None;\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let vo = xap1(i);\n                    let reduce = vo.acc_reduce(acc, reduce);\n                    acc = match Vo::reduce_to_stop(reduce) {\n                        Ok(acc) => acc,\n                        Err(stop) => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            match stop {\n                                StopReduce::DueToWhile { acc } => {\n                                    return Reduce::StoppedByWhileCondition { acc };\n                                }\n                                StopReduce::DueToError { error } => {\n                                    return Reduce::StoppedByError { error };\n                                }\n                            }\n                        }\n                    };\n                }\n                None => {\n                    if iter.is_completed_when_none_returned() {\n                        break;\n                    }\n                }\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        for i in chunk {\n                            let vo = xap1(i);\n                            let reduce = vo.acc_reduce(acc, reduce);\n                            acc = match Vo::reduce_to_stop(reduce) {\n                                Ok(acc) => acc,\n                                Err(stop) => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    match stop {\n                                        StopReduce::DueToWhile { acc } => {\n                                            return Reduce::StoppedByWhileCondition { acc };\n                                        }\n                                        StopReduce::DueToError { error } => {\n                                            return Reduce::StoppedByError { error };\n                                        }\n                                    }\n                                }\n                            };\n                        }\n                    }\n                    None => {\n                        if iter.is_completed_when_none_returned() {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n\n    Reduce::Done { acc }\n}\n"
  },
  {
    "path": "src/executor/thread_executor.rs",
    "content": "use orx_concurrent_iter::ConcurrentIter;\n\n/// Thread executor responsible for executing the tasks assigned to the thread by the\n/// parallel executor.\npub trait ThreadExecutor: Sized {\n    /// Type of the shared state among threads.\n    type SharedState;\n\n    /// Returns the next chunks size to be pulled from the input `iter` for the given\n    /// current `shared_state`.\n    fn next_chunk_size<I>(&self, shared_state: &Self::SharedState, iter: &I) -> usize\n    where\n        I: ConcurrentIter;\n\n    /// Hook that will be called before starting to execute the chunk of the given `chunk_size`.\n    fn begin_chunk(&mut self, chunk_size: usize);\n\n    /// Hook that will be called after completing the chunk of the given `chunk_size`.\n    /// The `shared_state` is also provided so that it can be updated to send information to the\n    /// parallel executor and other thread executors.\n    fn complete_chunk(&mut self, shared_state: &Self::SharedState, chunk_size: usize);\n\n    /// Hook that will be called after completing the task.\n    /// The `shared_state` is also provided so that it can be updated to send information to the\n    /// parallel executor and other thread executors.\n    fn complete_task(&mut self, shared_state: &Self::SharedState);\n}\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/mod.rs",
    "content": "#[cfg(test)]\nmod tests;\n\n/// Sequential variant for merging two sorted slices into one sorted slice.\npub mod seq;\n\n/// Parallel variant for merging two sorted slices into one sorted slice.\npub mod par;\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/par.rs",
    "content": "use crate::experiment::algorithms::merge_sorted_slices::seq::{\n    ParamsSeqMergeSortedSlices, bin_search_idx, seq_merge_unchecked,\n};\nuse crate::experiment::data_structures::{slice_dst::SliceDst, slice_src::SliceSrc};\nuse crate::{IntoParIterRec, ParIter, ParallelRunner};\nuse core::cmp::Ordering;\nuse orx_concurrent_recursive_iter::Queue;\n\n/// Determines how to search the pivot for splitting the slices.\n#[derive(Clone, Copy, Debug)]\npub enum PivotSearch {\n    /// We search the pivot position by a linear search.\n    Linear,\n    /// We search the pivot position by a binary search since both source slices are sorted.\n    Binary,\n}\n\n/// Parameters of the sequential algorithm for merging two sorted slices into one sorted slice.\n#[derive(Clone, Copy, Debug)]\npub struct ParamsParMergeSortedSlices {\n    /// Parameters of sequential merging.\n    pub seq_params: ParamsSeqMergeSortedSlices,\n    /// When true, the algorithm always puts the larger slice to the left;\n    /// otherwise to the right.\n    pub put_large_to_left: bool,\n    /// Determines how to search the pivot for splitting the slices.\n    pub pivot_search: PivotSearch,\n    /// Number of threads.\n    pub num_threads: usize,\n    /// Chunk size to be used by parallelization.\n    pub chunk_size: usize,\n    /// Minimum length of a slice to be split into two tasks.\n    pub min_split_len: usize,\n}\n\nstruct Task<'a, T> {\n    left: SliceSrc<'a, T>,\n    right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n}\n\nunsafe impl<'a, T> Send for Task<'a, T> {}\n\nimpl<'a, T> Task<'a, T> {\n    /// Clones the task.\n    ///\n    /// # SAFETY\n    ///\n    /// The purpose of destination slice `target` is to mutate the underlying memory.\n    /// Therefore, cloning task is marked as unsafe.\n    ///\n    /// - (i) assuming the clone will be used to mutate the memory, caller must\n    ///   ensure that `&self.target` will not be used.\n    unsafe fn clone(&self) -> Self {\n        Self {\n            left: self.left.clone(),\n            right: self.right.clone(),\n            target: unsafe { self.target.clone() },\n        }\n    }\n}\n\n/// # Panics\n///\n/// - (i) if `target.len()` is not equal to `left.len() + right.len()`\n/// - (ii) if any pair of of `left`, `right` or `target` are overlapping.\npub fn par_merge<'a, T, F, R: ParallelRunner>(\n    is_leq: F,\n    left: SliceSrc<'a, T>,\n    right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n    params: &ParamsParMergeSortedSlices,\n    runner: R,\n) where\n    T: Send + Sync,\n    F: Fn(&T, &T) -> bool + Sync,\n{\n    assert_eq!(target.len(), left.len() + right.len());\n    assert!(target.core().is_non_overlapping(&left.core()));\n    assert!(target.core().is_non_overlapping(&right.core()));\n    assert!(left.core().is_non_overlapping(&right.core()));\n\n    let initial_task = [Task {\n        left,\n        right,\n        target,\n    }];\n\n    let handle_extend = |task: &Task<'a, T>, queue: &Queue<'_, Task<'a, T>>| {\n        // SAFETY: req't (i) and (ii) are satisfied by panic conditions\n        unsafe { handle_extend(&is_leq, params, task, queue) }\n    };\n\n    initial_task\n        .into_par_rec(handle_extend)\n        .with_runner(runner)\n        .num_threads(params.num_threads)\n        .chunk_size(params.chunk_size)\n        .for_each(|_| {});\n}\n\n/// # SAFETY\n///\n/// - (i) `target.len()` must equal `left.len() + right.len()`\n/// - (ii) no pair of `left`, `right` and `target` can be overlapping.\nunsafe fn handle_extend<'a, T, F>(\n    is_leq: F,\n    params: &ParamsParMergeSortedSlices,\n    task: &Task<'a, T>,\n    queue: &Queue<'_, Task<'a, T>>,\n) where\n    T: Send + Sync,\n    F: Fn(&T, &T) -> bool,\n{\n    let min_split_len = core::cmp::min(params.min_split_len, 3);\n\n    // SAFETY: this method both handles and extends the queue; which will be\n    // visited only once; hence, the reference `task` will not be used to\n    // mutate the underlying memory, satisfying condition (i).\n    let task = unsafe { task.clone() };\n\n    let (mut left, mut right, target) = (task.left, task.right, task.target);\n    match (left.len(), right.len()) {\n        (x, y) if x < min_split_len || y < min_split_len => {\n            // SAFETY: req't (i) & (ii) are satisfied by conditions (i) & (ii)\n            unsafe { seq_merge_unchecked(is_leq, left, right, target, &params.seq_params) };\n        }\n        _ => {\n            let is_large_on_left = left.len() >= right.len();\n            if is_large_on_left != params.put_large_to_left {\n                (left, right) = (right, left);\n            }\n\n            let position = left.len() / 2;\n            // SAFETY: position <= self.len()\n            let [left_left, left_right] = unsafe { left.split_at_unchecked(position) };\n\n            // SAFETY: since left.len() >= 2, then left_right.len() > 0\n            let pivot = unsafe { left_right.first_unchecked() };\n\n            let pos_right =\n                match params.pivot_search {\n                    PivotSearch::Linear => right\n                        .values()\n                        .position(|r| is_leq(pivot, r))\n                        .unwrap_or(right.len()),\n                    PivotSearch::Binary => bin_search_idx(right.as_slice().binary_search_by(|r| {\n                        match is_leq(r, pivot) {\n                            true => Ordering::Less,\n                            false => Ordering::Greater,\n                        }\n                    })),\n                };\n\n            // SAFETY: (i) pos_right <= right.len() is satisfied by the expression declaring pos_right\n            let [right_left, right_right] = unsafe { right.split_at_unchecked(pos_right) };\n\n            let target_left_len = left_left.len() + right_left.len();\n            // SAFETY: (i) target_left_len <= target.len() is satisfied by cond'n (i) target.len() == left.len() + right.len()\n            let [target_left, target_right] = unsafe { target.split_at_unchecked(target_left_len) };\n\n            let task_left = Task {\n                left: left_left,\n                right: right_left,\n                target: target_left,\n            };\n            let task_right = Task {\n                left: left_right,\n                right: right_right,\n                target: target_right,\n            };\n            queue.extend([task_left, task_right]);\n        }\n    }\n}\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/seq.rs",
    "content": "use crate::experiment::data_structures::{slice_dst::SliceDst, slice_src::SliceSrc};\nuse core::cmp::Ordering;\n\npub(super) fn bin_search_idx(idx: Result<usize, usize>) -> usize {\n    match idx {\n        Ok(x) => x,\n        Err(x) => x,\n    }\n}\n\n/// Determines the streak search.\n///\n/// Assume at an intermediate step of the algorithm, current value of left slice is\n/// less than current value of right slice.\n///\n/// In this case, we will copy the current element of the left slice to the current\n/// position of the target slice.\n///\n/// However, if next `n` elements of the left slice are all smaller than the current\n/// value of the right slice, we can copy all `n` elements at once. The subslice of\n/// this `n` elements is called the streak.\n#[derive(Clone, Copy, Debug)]\npub enum StreakSearch {\n    /// We don't search for a streak; we copy elements one by one.\n    None,\n    /// We search the streak by a linear search.\n    Linear,\n    /// We search the streak by a binary search since both source slices are sorted.\n    Binary,\n}\n\n/// Parameters of the sequential algorithm for merging two sorted slices into one sorted slice.\n#[derive(Clone, Copy, Debug)]\npub struct ParamsSeqMergeSortedSlices {\n    /// Streak search method.\n    pub streak_search: StreakSearch,\n    /// When true, the algorithm always puts the larger slice to the left;\n    /// otherwise to the right.\n    pub put_large_to_left: bool,\n}\n\n/// # Panics\n///\n/// - (i) if `target.len()` is not equal to `left.len() + right.len()`\n/// - (ii) if any pair of of `left`, `right` or `target` are overlapping.\npub fn seq_merge<'a, T: 'a, F>(\n    is_leq: F,\n    left: SliceSrc<'a, T>,\n    right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n    params: &ParamsSeqMergeSortedSlices,\n) where\n    F: Fn(&T, &T) -> bool,\n{\n    assert_eq!(target.len(), left.len() + right.len());\n    assert!(target.core().is_non_overlapping(&left.core()));\n    assert!(target.core().is_non_overlapping(&right.core()));\n    assert!(left.core().is_non_overlapping(&right.core()));\n\n    // SAFETY: safety requirements are satisfied by panic conditions (i) and (ii)\n    unsafe { seq_merge_unchecked(is_leq, left, right, target, params) }\n}\n\n/// # SAFETY\n///\n/// - (i) `target.len()` must equal `left.len() + right.len()`\n/// - (ii) no pair of `left`, `right` and `target` can be overlapping.\npub unsafe fn seq_merge_unchecked<'a, T: 'a, F>(\n    is_leq: F,\n    left: SliceSrc<'a, T>,\n    right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n    params: &ParamsSeqMergeSortedSlices,\n) where\n    F: Fn(&T, &T) -> bool,\n{\n    // SAFETY: safety requirements are satisfied by safety conditions (i) and (ii)\n    unsafe {\n        match params.streak_search {\n            StreakSearch::None => {\n                seq_merge_streak_none(is_leq, left, right, target, params.put_large_to_left)\n            }\n            StreakSearch::Linear => {\n                seq_merge_streak_linear(is_leq, left, right, target, params.put_large_to_left)\n            }\n            StreakSearch::Binary => {\n                seq_merge_streak_binary(is_leq, left, right, target, params.put_large_to_left)\n            }\n        }\n    }\n}\n\n/// # SAFETY\n///\n/// - (i) `target.len()` must equal `left.len() + right.len()`\n/// - (ii) no pair of `left`, `right` and `target` can be overlapping.\nunsafe fn seq_merge_streak_none<'a, T: 'a, F>(\n    is_leq: F,\n    mut left: SliceSrc<'a, T>,\n    mut right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n    put_large_to_left: bool,\n) where\n    F: Fn(&T, &T) -> bool,\n{\n    let is_large_on_left = left.len() >= right.len();\n    if is_large_on_left != put_large_to_left {\n        (left, right) = (right, left);\n    }\n\n    let mut left = left.into_ptr_iter();\n    let mut right = right.into_ptr_iter();\n    let mut dst = target.into_ptr_iter();\n\n    match (left.current(), right.current()) {\n        (Some(mut l), Some(mut r)) => {\n            loop {\n                match is_leq(l, r) {\n                    true => {\n                        // SAFETY: left still has at least one elem `l`, so must `dst`\n                        unsafe { dst.write_one_from(&mut left) };\n                        match left.current() {\n                            Some(x) => l = x,\n                            None => {\n                                // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n                                unsafe { dst.write_rest_from(&mut right) };\n                                break;\n                            }\n                        }\n                    }\n                    false => {\n                        // SAFETY: right still has at least one elem `r`, so must `dst`\n                        unsafe { dst.write_one_from(&mut right) };\n\n                        match right.current() {\n                            Some(x) => r = x,\n                            None => {\n                                // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n                                unsafe { dst.write_rest_from(&mut left) };\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        (None, None) => {}\n        (None, _) => {\n            // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n            unsafe { dst.write_rest_from(&mut right) };\n        }\n        (_, None) => {\n            // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n            unsafe { dst.write_rest_from(&mut left) };\n        }\n    }\n}\n\n/// # SAFETY\n///\n/// - (i) `target.len()` must equal `left.len() + right.len()`\n/// - (ii) no pair of `left`, `right` and `target` can be overlapping.\nunsafe fn seq_merge_streak_linear<'a, T: 'a, F>(\n    is_leq: F,\n    mut left: SliceSrc<'a, T>,\n    mut right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n    put_large_to_left: bool,\n) where\n    F: Fn(&T, &T) -> bool,\n{\n    let is_large_on_left = left.len() >= right.len();\n    if is_large_on_left != put_large_to_left {\n        (left, right) = (right, left);\n    }\n\n    let mut left = left.into_ptr_iter();\n    let mut right = right.into_ptr_iter();\n    let mut dst = target.into_ptr_iter();\n\n    match (left.current(), right.current()) {\n        (Some(mut l), Some(mut r)) => {\n            loop {\n                match is_leq(l, r) {\n                    true => {\n                        let count = match left.values().position(|x| !is_leq(x, r)) {\n                            Some(idx_bigger) => idx_bigger,\n                            None => left.len(),\n                        };\n                        // SAFETY: left still has at least `count` elements, so must `dst`\n                        unsafe { dst.write_many_from(&mut left, count) };\n\n                        match left.current() {\n                            Some(x) => l = x,\n                            None => {\n                                // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n                                unsafe { dst.write_rest_from(&mut right) };\n                                break;\n                            }\n                        }\n                    }\n                    false => {\n                        let count = match right.values().position(|x| !is_leq(x, l)) {\n                            Some(idx_bigger) => idx_bigger,\n                            None => right.len(),\n                        };\n                        // SAFETY: right still has at least `count` elements, so must `dst`\n                        unsafe { dst.write_many_from(&mut right, count) };\n\n                        match right.current() {\n                            Some(x) => r = x,\n                            None => {\n                                // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n                                unsafe { dst.write_rest_from(&mut left) };\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        (None, _) => {\n            // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n            unsafe { dst.write_rest_from(&mut right) };\n        }\n        (_, None) => {\n            // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n            unsafe { dst.write_rest_from(&mut left) };\n        }\n    }\n}\n\n/// # SAFETY\n///\n/// - (i) `target.len()` must equal `left.len() + right.len()`\n/// - (ii) no pair of `left`, `right` and `target` can be overlapping.\nunsafe fn seq_merge_streak_binary<'a, T: 'a, F>(\n    is_leq: F,\n    mut left: SliceSrc<'a, T>,\n    mut right: SliceSrc<'a, T>,\n    target: SliceDst<'a, T>,\n    put_large_to_left: bool,\n) where\n    F: Fn(&T, &T) -> bool,\n{\n    let is_large_on_left = left.len() >= right.len();\n    if is_large_on_left != put_large_to_left {\n        (left, right) = (right, left);\n    }\n\n    let mut left = left.into_ptr_iter();\n    let mut right = right.into_ptr_iter();\n    let mut dst = target.into_ptr_iter();\n\n    match (left.current(), right.current()) {\n        (Some(mut l), Some(mut r)) => {\n            loop {\n                match is_leq(l, r) {\n                    true => {\n                        let count =\n                            bin_search_idx(left.as_slice().binary_search_by(|x| {\n                                match is_leq(x, r) {\n                                    true => Ordering::Less,\n                                    false => Ordering::Greater,\n                                }\n                            }));\n                        // SAFETY: left still has at least `count` elements, so must `dst`\n                        unsafe { dst.write_many_from(&mut left, count) };\n\n                        match left.current() {\n                            Some(x) => l = x,\n                            None => {\n                                // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n                                unsafe { dst.write_rest_from(&mut right) };\n                                break;\n                            }\n                        }\n                    }\n                    false => {\n                        let count = bin_search_idx(right.as_slice().binary_search_by(|x| {\n                            match is_leq(x, l) {\n                                true => Ordering::Less,\n                                false => Ordering::Greater,\n                            }\n                        }));\n                        // SAFETY: right still has at least `count` elements, so must `dst`\n                        unsafe { dst.write_many_from(&mut right, count) };\n\n                        match right.current() {\n                            Some(x) => r = x,\n                            None => {\n                                // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n                                unsafe { dst.write_rest_from(&mut left) };\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        (None, _) => {\n            // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n            unsafe { dst.write_rest_from(&mut right) };\n        }\n        (_, None) => {\n            // SAFETY: target (i) and (ii) are satisfied by conditions (i) and (ii)\n            unsafe { dst.write_rest_from(&mut left) };\n        }\n    }\n}\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/tests/inputs.rs",
    "content": "use alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse rand::prelude::*;\nuse rand_chacha::ChaCha8Rng;\n\n#[derive(Clone, Copy)]\npub enum SortKind {\n    Sorted,\n    ReverseSorted,\n    Mixed,\n}\n\npub fn sorted_slices(\n    left_len: usize,\n    total_len: usize,\n    sort: SortKind,\n) -> (Vec<String>, Vec<String>, Vec<String>) {\n    let mut all: Vec<_> = (0..total_len).map(|x| x.to_string()).collect();\n    match sort {\n        SortKind::Sorted => all.sort(),\n        SortKind::ReverseSorted => {\n            all.sort();\n            all.reverse();\n        }\n        SortKind::Mixed => {\n            let num_shuffles = 10 * total_len;\n            let mut rng = ChaCha8Rng::seed_from_u64(42);\n            for _ in 0..num_shuffles {\n                let i = rng.random_range(0..total_len);\n                let j = rng.random_range(0..total_len);\n                all.swap(i, j);\n            }\n        }\n    }\n\n    let (left, right) = all.split_at(left_len);\n    let mut left = left.to_vec();\n    let mut right = right.to_vec();\n    left.sort();\n    right.sort();\n    (all, left, right)\n}\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/tests/mod.rs",
    "content": "mod inputs;\nmod par;\nmod seq;\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/tests/par.rs",
    "content": "use super::inputs::{SortKind, sorted_slices};\nuse crate::experiment::algorithms::merge_sorted_slices::par::{\n    ParamsParMergeSortedSlices, PivotSearch, par_merge,\n};\nuse crate::experiment::algorithms::merge_sorted_slices::seq::{\n    ParamsSeqMergeSortedSlices, StreakSearch,\n};\nuse crate::experiment::data_structures::slice_dst::SliceDst;\nuse crate::experiment::data_structures::slice_src::SliceSrc;\nuse crate::{DefaultPool, DefaultRunner, RunnerWithPool};\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn runner() -> RunnerWithPool<DefaultPool> {\n    DefaultRunner::default()\n}\n\nconst PARAMS: &[ParamsSeqMergeSortedSlices] = &[\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::None,\n        put_large_to_left: false,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Linear,\n        put_large_to_left: false,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Binary,\n        put_large_to_left: false,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::None,\n        put_large_to_left: true,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Linear,\n        put_large_to_left: true,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Binary,\n        put_large_to_left: true,\n    },\n];\n\n#[test_matrix(\n    [(0, 0), (0, 5), (5, 5), (4, 20), (10, 20), (14, 20)],\n    [SortKind::Sorted, SortKind::ReverseSorted, SortKind::Mixed],\n    [PARAMS[0],PARAMS[1],PARAMS[2],PARAMS[3],PARAMS[4],PARAMS[5]],\n    [PivotSearch::Linear, PivotSearch::Binary],\n    [0, 1, 64])\n]\nfn merge_sorted_slices_par(\n    (left_len, total_len): (usize, usize),\n    sort: SortKind,\n    seq_params: ParamsSeqMergeSortedSlices,\n    pivot_search: PivotSearch,\n    chunk_size: usize,\n) {\n    let params = ParamsParMergeSortedSlices {\n        seq_params: seq_params,\n        chunk_size,\n        num_threads: 4,\n        pivot_search,\n        put_large_to_left: seq_params.put_large_to_left,\n        min_split_len: 3,\n    };\n\n    run((left_len, total_len), sort, params);\n}\n\n#[test_matrix(\n    [(0, 0), (0, 5), (5, 5), (4, 20), (10, 20), (14, 20)])\n]\nfn merge_sorted_slices_par_single_thread((left_len, total_len): (usize, usize)) {\n    let params = ParamsParMergeSortedSlices {\n        seq_params: PARAMS[5],\n        chunk_size: 1,\n        num_threads: 1,\n        pivot_search: PivotSearch::Binary,\n        put_large_to_left: PARAMS[5].put_large_to_left,\n        min_split_len: 3,\n    };\n\n    run((left_len, total_len), SortKind::Mixed, params);\n}\n\n#[cfg(not(miri))]\n#[test_matrix(\n    [1<<15],\n    [0, 1, 64],\n    [4, 16]\n)]\nfn merge_sorted_slices_par_large(len: usize, num_threads: usize, chunk_size: usize) {\n    let params = ParamsParMergeSortedSlices {\n        seq_params: ParamsSeqMergeSortedSlices {\n            streak_search: StreakSearch::Linear,\n            put_large_to_left: true,\n        },\n        pivot_search: PivotSearch::Binary,\n        put_large_to_left: true,\n        min_split_len: 3,\n        chunk_size,\n        num_threads,\n    };\n\n    run((len / 2, len), SortKind::Mixed, params);\n}\n\nfn run((left_len, total_len): (usize, usize), sort: SortKind, params: ParamsParMergeSortedSlices) {\n    let (mut expected, mut left, mut right) = sorted_slices(left_len, total_len, sort);\n\n    let mut result = Vec::<String>::with_capacity(total_len);\n\n    par_merge(\n        |a, b| a < b,\n        SliceSrc::from_slice(left.as_slice()),\n        SliceSrc::from_slice(right.as_slice()),\n        SliceDst::from_vec(&mut result),\n        &params,\n        runner(),\n    );\n\n    // all elements of left & right are moved to result\n    unsafe {\n        result.set_len(left.len() + right.len());\n        left.set_len(0);\n        right.set_len(0);\n    }\n\n    expected.sort();\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "src/experiment/algorithms/merge_sorted_slices/tests/seq.rs",
    "content": "use super::inputs::{SortKind, sorted_slices};\nuse crate::experiment::algorithms::merge_sorted_slices::seq::{\n    ParamsSeqMergeSortedSlices, StreakSearch, seq_merge,\n};\nuse crate::experiment::data_structures::slice_dst::SliceDst;\nuse crate::experiment::data_structures::slice_src::SliceSrc;\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nconst PARAMS: &[ParamsSeqMergeSortedSlices] = &[\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::None,\n        put_large_to_left: false,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Linear,\n        put_large_to_left: false,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Binary,\n        put_large_to_left: false,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::None,\n        put_large_to_left: true,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Linear,\n        put_large_to_left: true,\n    },\n    ParamsSeqMergeSortedSlices {\n        streak_search: StreakSearch::Binary,\n        put_large_to_left: true,\n    },\n];\n\n#[test_matrix(\n    [(0, 0), (0, 5), (5, 5), (4, 20), (10, 20), (14, 20)],\n    [SortKind::Sorted, SortKind::ReverseSorted, SortKind::Mixed],\n    [PARAMS[0],PARAMS[1],PARAMS[2],PARAMS[3],PARAMS[4],PARAMS[5]])\n]\nfn merge_sorted_slices_seq(\n    (left_len, total_len): (usize, usize),\n    sort: SortKind,\n    params: ParamsSeqMergeSortedSlices,\n) {\n    let (mut expected, mut left, mut right) = sorted_slices(left_len, total_len, sort);\n\n    let mut result = Vec::<String>::with_capacity(total_len);\n\n    seq_merge(\n        |a, b| a < b,\n        SliceSrc::from_slice(left.as_slice()),\n        SliceSrc::from_slice(right.as_slice()),\n        SliceDst::from_vec(&mut result),\n        &params,\n    );\n\n    // all elements of left & right are moved to result\n    unsafe {\n        result.set_len(left.len() + right.len());\n        left.set_len(0);\n        right.set_len(0);\n    }\n\n    expected.sort();\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "src/experiment/algorithms/mod.rs",
    "content": "/// Merge two sorted slices into one sorted slice.\npub mod merge_sorted_slices;\n"
  },
  {
    "path": "src/experiment/data_structures/mod.rs",
    "content": "#[cfg(test)]\nmod tests;\n\n/// A raw slice of contiguous data.\npub mod slice;\n/// A raw slice of contiguous data with un-initialized values.\npub mod slice_dst;\n/// Core structure for iterators over contiguous slices of data.\npub mod slice_iter_ptr;\n/// Iterator over a slice of data that will be completely filled with values before the iterator is consumed.\npub mod slice_iter_ptr_dst;\n/// Iterator over a slice of data that will be completely copied to another slice before the iterator is consumed.\npub mod slice_iter_ptr_src;\n/// A raw slice of contiguous data with initialized values.\npub mod slice_src;\n"
  },
  {
    "path": "src/experiment/data_structures/slice.rs",
    "content": "use core::{marker::PhantomData, ptr::slice_from_raw_parts};\n\n/// A raw slice of contiguous data.\npub struct Slice<'a, T: 'a> {\n    raw: *const [T],\n    phantom: PhantomData<&'a ()>,\n}\n\nimpl<'a, T: 'a> Clone for Slice<'a, T> {\n    fn clone(&self) -> Self {\n        Self {\n            raw: self.raw,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, T: 'a> From<&[T]> for Slice<'a, T> {\n    fn from(value: &[T]) -> Self {\n        Self::new(value.as_ptr(), value.len())\n    }\n}\n\nimpl<'a, T: 'a> Slice<'a, T> {\n    /// Creates a new raw slice.\n    #[inline(always)]\n    pub fn new(data: *const T, len: usize) -> Self {\n        let raw = slice_from_raw_parts(data, len);\n        let phantom = PhantomData;\n        Self { raw, phantom }\n    }\n\n    /// Destructs the slice wrapper and returns the underlying raw slice\n    /// that it is created with.\n    pub fn destruct(self) -> *const [T] {\n        self.raw\n    }\n\n    /// Creates two slices from this slice:\n    ///\n    /// - first slice for positions [0..position)\n    /// - second slice for positions [position..]\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `position` must be less than or equal to `self.len()`\n    pub unsafe fn split_at_unchecked(self, position: usize) -> [Self; 2] {\n        let len_right = self.len() - position;\n        let ptr_left = self.raw as *const T;\n        let left = Self::new(ptr_left, position);\n        // SAFETY: ptr_right is within bounds due to condition (i)\n        let ptr_right = unsafe { ptr_left.add(position) };\n        let right = Self::new(ptr_right, len_right);\n        [left, right]\n    }\n\n    #[inline(always)]\n    pub(super) fn data(&self) -> *const T {\n        self.raw as *const T\n    }\n\n    /// Returns the length of the slice.\n    #[inline(always)]\n    pub fn len(&self) -> usize {\n        self.raw.len()\n    }\n\n    /// Returns true if the slice is empty.\n    pub fn is_empty(&self) -> bool {\n        self.raw.is_empty()\n    }\n\n    /// Returns a reference to the first element of the slice.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) this must have a positive `len`\n    /// - (ii) the first element must be initialized\n    #[inline(always)]\n    pub unsafe fn first_unchecked(&self) -> &'a T {\n        unsafe { &*(self.raw as *const T) }\n    }\n\n    /// # SAFETY\n    ///\n    /// - (i) `self` and `src` must have the same lengths.\n    /// - (ii) `self` and `src` must not be overlapping.\n    pub unsafe fn copy_from_nonoverlapping(&self, src: &Self) {\n        debug_assert_eq!(self.len(), src.len());\n\n        // SAFETY: (i) within bounds and (ii) slices do not overlap\n        let dst = self.raw as *mut T;\n        unsafe { dst.copy_from_nonoverlapping(src.raw as *const T, self.len()) };\n    }\n\n    /// # SAFETY\n    ///\n    /// - (i) all values must be initialized.\n    /// - (ii) the values must not be mutated before the returned slice is dropped.\n    pub unsafe fn as_slice(&self) -> &'a [T] {\n        unsafe { &*self.raw }\n    }\n}\n\n/// A struct holding a reference to a slice, hiding its unsafe methods,\n/// allowing only safe methods.\npub struct SliceSafe<'c, 'a, T: 'a>(&'c Slice<'a, T>);\n\nimpl<'c, 'a, T: 'a> SliceSafe<'c, 'a, T> {\n    /// Creates a safe wrapper over the `slice`.\n    pub fn new(slice: &'c Slice<'a, T>) -> Self {\n        Self(slice)\n    }\n}\n\nimpl<'c, 'a, T: 'a> From<&'c Slice<'a, T>> for SliceSafe<'c, 'a, T> {\n    fn from(value: &'c Slice<'a, T>) -> Self {\n        SliceSafe::new(value)\n    }\n}\n\nimpl<'c, 'a, T: 'a> SliceSafe<'c, 'a, T> {\n    /// Returns true if slices `self` and `other` are non-overlapping.\n    pub fn is_non_overlapping(&self, other: &Self) -> bool {\n        match (self.0.len(), other.0.len()) {\n            (0, _) | (_, 0) => true,\n            (n, m) => {\n                let (left, right) = match self.0.data() >= other.0.data() {\n                    true => (unsafe { other.0.data().add(m - 1) }, self.0.data()),\n                    false => (unsafe { self.0.data().add(n - 1) }, other.0.data()),\n                };\n                left < right\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/experiment/data_structures/slice_dst.rs",
    "content": "use crate::experiment::data_structures::slice::{Slice, SliceSafe};\nuse crate::experiment::data_structures::slice_iter_ptr_dst::SliceIterPtrDst;\nuse alloc::vec::Vec;\n\n/// A raw slice of contiguous data with un-initialized values.\n///\n/// # SAFETY\n///\n/// While constructing this slice, we must guarantee that none of the elements of it\n/// is initialized since they will be overwritten.\n///\n/// This is a write-only slice.\n/// The caller must make sure that there is no other concurrent reads or writes to this slice.\npub struct SliceDst<'a, T>(Slice<'a, T>);\n\nimpl<'a, T> SliceDst<'a, T> {\n    /// Destructs the slice wrapper and returns the underlying raw slice\n    /// that it is created with.\n    pub fn destruct(self) -> *const [T] {\n        self.0.destruct()\n    }\n\n    /// Clones the destination slice.\n    ///\n    /// # SAFETY\n    ///\n    /// The purpose of destination slice is to mutate the underlying memory.\n    /// Therefore, cloning is marked as unsafe.\n    ///\n    /// - (i) assuming the clone will be used to mutate the memory, caller must\n    ///   ensure that `&self` will not be used.\n    pub unsafe fn clone(&self) -> Self {\n        Self(self.0.clone())\n    }\n\n    /// Creates a new slice of un-initialized values.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `data` to `data+len` must be contiguous memory of un-initialized elements\n    pub unsafe fn new(data: *const T, len: usize) -> Self {\n        Self(Slice::new(data, len))\n    }\n\n    /// Creates a new slice for the entire capacity of the vector.\n    ///\n    /// # Panics\n    ///\n    /// - (i) if `vec.len()` is not zero.\n    ///\n    /// # SAFETY\n    ///\n    /// This slice cannot outlive the `vec` it is created for due to the lifetime relation.\n    pub fn from_vec(vec: &'a mut Vec<T>) -> Self {\n        assert!(vec.is_empty());\n\n        // SAFETY: constructing with contiguous un-initialized elements\n        unsafe { Self::new(vec.as_ptr(), vec.capacity()) }\n    }\n\n    /// Length of the slice.\n    #[inline(always)]\n    #[allow(clippy::len_without_is_empty)]\n    pub fn len(&self) -> usize {\n        self.0.len()\n    }\n\n    /// Returns a safe wrapper over this slice.\n    #[inline(always)]\n    pub fn core(&self) -> SliceSafe<'_, 'a, T> {\n        self.into()\n    }\n\n    /// Converts the destination slice into a destination iterator.\n    pub fn into_ptr_iter(self) -> SliceIterPtrDst<'a, T> {\n        SliceIterPtrDst::new(self)\n    }\n\n    /// Creates two slices from this slice:\n    ///\n    /// - first slice for positions [0..position)\n    /// - second slice for positions [position..]\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `position` must be less than or equal to `self.len()`\n    pub unsafe fn split_at_unchecked(self, position: usize) -> [Self; 2] {\n        // SAFETY: req't (i) is satisfied by cond'n (i)\n        unsafe { self.0.split_at_unchecked(position) }.map(Self)\n    }\n}\n\nimpl<'c, 'a, T: 'a> From<&'c SliceDst<'a, T>> for SliceSafe<'c, 'a, T> {\n    fn from(value: &'c SliceDst<'a, T>) -> Self {\n        SliceSafe::new(&value.0)\n    }\n}\n"
  },
  {
    "path": "src/experiment/data_structures/slice_iter_ptr.rs",
    "content": "use core::marker::PhantomData;\n\n/// Core structure for iterators over contiguous slices of data.\npub struct SliceIterPtr<'a, T: 'a> {\n    data: *const T,\n    exclusive_end: *const T,\n    phantom: PhantomData<&'a ()>,\n}\n\nimpl<T> Default for SliceIterPtr<'_, T> {\n    fn default() -> Self {\n        Self {\n            data: core::ptr::null(),\n            exclusive_end: core::ptr::null(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, T: 'a> SliceIterPtr<'a, T> {\n    /// Creates a new iterator for `n` elements starting from the given `ptr`.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) either `ptr` is not-null or `n` is zero.\n    pub unsafe fn new(ptr: *const T, n: usize) -> Self {\n        let exclusive_end = unsafe { ptr.add(n) };\n        Self {\n            data: ptr,\n            exclusive_end,\n            phantom: PhantomData,\n        }\n    }\n\n    /// Returns true if the end of the slice is reached.\n    #[inline(always)]\n    pub fn is_finished(&self) -> bool {\n        self.data == self.exclusive_end\n    }\n\n    /// Returns the remaining number of elements on the slice to be\n    /// iterated.\n    #[inline(always)]\n    fn remaining(&self) -> usize {\n        unsafe { self.exclusive_end.offset_from(self.data) as usize }\n    }\n\n    // non-progressing methods\n\n    /// Returns the current pointer.\n    #[inline(always)]\n    pub fn peek(&self) -> *const T {\n        self.data\n    }\n\n    /// Returns a reference to the current element.\n    /// Returns None if the iterator `is_finished`.\n    ///\n    /// # SAFETY\n    ///\n    /// Bounds check is applied. However, the following safety\n    /// requirement must be satisfied.\n    ///\n    /// - (i) the element must be initialized.\n    #[inline(always)]\n    pub unsafe fn current(&self) -> Option<&'a T> {\n        match !self.is_finished() {\n            // SAFETY: the value is initialized.\n            true => Some(unsafe { &*self.data }),\n            false => None,\n        }\n    }\n\n    /// Returns a reference to the current element.\n    /// Returns None if the iterator `is_finished`.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) the element must be initialized.\n    /// - (ii) the iterator cannot be `is_finished`; otherwise, we\n    ///   will have an UB due to dereferencing an invalid pointer.\n    #[inline(always)]\n    pub unsafe fn current_unchecked(&self) -> &'a T {\n        debug_assert!(!self.is_finished());\n        unsafe { &*self.data }\n    }\n\n    // progressing methods\n\n    /// Returns the current pointer and progresses the iterator to the next.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) the iterator cannot be `is_finished`; otherwise, the\n    ///   obtained pointer does not belong to the slice the iterator\n    ///   is created for.\n    #[inline(always)]\n    pub unsafe fn next_unchecked(&mut self) -> *const T {\n        debug_assert!(!self.is_finished());\n        let value = self.data;\n        self.data = unsafe { self.data.add(1) };\n        value\n    }\n\n    /// Returns the current pointer and progresses by `count` elements.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) the iterator must have at least `count` more elements; i.e.,\n    ///   `self.remaining() >= count`.\n    pub unsafe fn next_n_unchecked(&mut self, count: usize) -> *const T {\n        debug_assert!(self.remaining() >= count);\n        let value = self.data;\n        // SAFETY: by cond'n (i), data + count is within bounds\n        self.data = unsafe { self.data.add(count) };\n        value\n    }\n\n    /// Brings the iterator to the end, skipping the remaining positions.\n    pub fn jump_to_end(&mut self) {\n        self.data = self.exclusive_end\n    }\n}\n\nimpl<'a, T: 'a> Iterator for SliceIterPtr<'a, T> {\n    type Item = *const T;\n\n    #[inline(always)]\n    fn next(&mut self) -> Option<Self::Item> {\n        match !self.is_finished() {\n            true => Some(unsafe { self.next_unchecked() }),\n            false => None,\n        }\n    }\n\n    #[inline(always)]\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        (self.remaining(), Some(self.remaining()))\n    }\n}\n\nimpl<'a, T: 'a> ExactSizeIterator for SliceIterPtr<'a, T> {\n    #[inline(always)]\n    fn len(&self) -> usize {\n        self.remaining()\n    }\n}\n"
  },
  {
    "path": "src/experiment/data_structures/slice_iter_ptr_dst.rs",
    "content": "use crate::experiment::data_structures::slice_iter_ptr_src::SliceIterPtrSrc;\nuse crate::experiment::data_structures::{slice_dst::SliceDst, slice_iter_ptr::SliceIterPtr};\n\n/// Iterator over a slice of data that will be completely filled with values\n/// before the iterator is consumed.\n///\n/// The slice might initially be uninitialized, but will completely be initialized.\npub struct SliceIterPtrDst<'a, T: 'a>(SliceIterPtr<'a, T>);\n\nimpl<T> Default for SliceIterPtrDst<'_, T> {\n    fn default() -> Self {\n        Self(Default::default())\n    }\n}\n\nimpl<'a, T: 'a> SliceIterPtrDst<'a, T> {\n    /// # SAFETY\n    ///\n    /// Since `slice: SliceDst` satisfies that positions of it are not initialized,\n    /// we satisfy the construction condition for this iterator.\n    pub fn new(slice: SliceDst<'a, T>) -> Self {\n        let raw = slice.destruct();\n        // SAFETY: requirement satisfied by `SliceDst`\n        Self(unsafe { SliceIterPtr::new(raw as *const T, raw.len()) })\n    }\n\n    /// Returns true if the end of the slice is reached.\n    #[inline(always)]\n    pub fn is_finished(&self) -> bool {\n        self.0.is_finished()\n    }\n\n    /// Returns the number of remaining positions.\n    #[inline(always)]\n    #[allow(clippy::len_without_is_empty)]\n    pub fn len(&self) -> usize {\n        self.0.len()\n    }\n\n    /// Pulls the next element from `src`, writes it to next position of `self`.\n    ///\n    /// Progresses both `self` and `src` by one element.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `src` cannot be `is_finished`\n    /// - (ii) `self` cannot be `is_finished`\n    /// - (iii) `src` and `self` cannot be overlapping\n    #[inline(always)]\n    pub unsafe fn write_one_from(&mut self, src: &mut SliceIterPtrSrc<'a, T>) {\n        debug_assert!(!self.is_finished() && !src.is_finished());\n\n        // SAFETY: satisfied by (i)\n        let src = unsafe { src.next_unchecked() };\n\n        // SAFETY: satisfied by (ii)\n        let dst = unsafe { self.0.next_unchecked() } as *mut T;\n\n        // SAFETY: satisfied by (iii)\n        unsafe { dst.copy_from_nonoverlapping(src, 1) };\n    }\n\n    /// Pulls the next `count` elements from `src`, writes them to next `count`\n    /// positions of `self`.\n    ///\n    /// Progresses both `self` and `src` by `count` positions.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `src` must have at least `count` positions.\n    /// - (ii) `self` must have at least `count` positions.\n    /// - (iii) `src` and `self` cannot be overlapping\n    pub unsafe fn write_many_from(&mut self, src: &mut SliceIterPtrSrc<'a, T>, count: usize) {\n        debug_assert!(self.len() >= count && src.len() >= count);\n\n        // SAFETY: satisfied by (i)\n        let src = unsafe { src.next_n_unchecked(count) };\n\n        // SAFETY: satisfied by (ii)\n        let dst = unsafe { self.0.next_n_unchecked(count) } as *mut T;\n\n        // SAFETY: satisfied by (iii)\n        unsafe { dst.copy_from_nonoverlapping(src, count) };\n    }\n\n    /// Pulls all remaining elements from `src`, writes them to remaining\n    /// positions of `self`.\n    ///\n    /// Progresses both `self` and `src` to the end.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `src` and `self` mut have equal number of remaining elements\n    /// - (ii) `src` and `self` cannot be overlapping\n    pub unsafe fn write_rest_from(&mut self, src: &mut SliceIterPtrSrc<'a, T>) {\n        debug_assert_eq!(self.len(), src.len());\n\n        if let Some(src) = src.next() {\n            let count = self.len();\n\n            // SAFETY: having same lengths with src by (i), self cannot be finished\n            let dst = unsafe { self.0.next_unchecked() } as *mut T;\n\n            // SAFETY: satisfied by (ii)\n            unsafe { dst.copy_from_nonoverlapping(src, count) };\n        }\n\n        self.0.jump_to_end();\n        src.jump_to_end();\n    }\n}\n"
  },
  {
    "path": "src/experiment/data_structures/slice_iter_ptr_src.rs",
    "content": "use crate::experiment::data_structures::{slice_iter_ptr::SliceIterPtr, slice_src::SliceSrc};\nuse core::slice::from_raw_parts;\n\n/// Iterator over a slice of data that will be completely copied to another slice\n/// before the iterator is consumed.\n///\n/// # SAFETY\n///\n/// While constructing this iterator, we must guarantee that all elements of it\n/// are initialized since it will be used as source of values.\npub struct SliceIterPtrSrc<'a, T: 'a>(SliceIterPtr<'a, T>);\n\nimpl<T> Default for SliceIterPtrSrc<'_, T> {\n    fn default() -> Self {\n        Self(Default::default())\n    }\n}\n\nimpl<'a, T: 'a> SliceIterPtrSrc<'a, T> {\n    /// # SAFETY\n    ///\n    /// Since `slice: SliceSrc` satisfies that all elements of it are initialized,\n    /// we satisfy the construction condition for this iterator.\n    pub fn new(slice: SliceSrc<'a, T>) -> Self {\n        let raw = slice.destruct();\n        // SAFETY: requirement satisfied by `SliceSrc`\n        Self(unsafe { SliceIterPtr::new(raw as *const T, raw.len()) })\n    }\n\n    /// Returns true if the end of the slice is reached.\n    #[inline(always)]\n    pub fn is_finished(&self) -> bool {\n        self.0.is_finished()\n    }\n\n    /// Returns a reference to the current element.\n    /// Returns None if the iterator `is_finished`.\n    #[inline(always)]\n    pub fn current(&self) -> Option<&'a T> {\n        // SAFETY: all elements are initialized\n        unsafe { self.0.current() }\n    }\n\n    /// Returns the current pointer and progresses the iterator to the next.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) the iterator cannot be `is_finished`; otherwise, the\n    ///   obtained pointer does not belong to the slice the iterator\n    ///   is created for.\n    #[inline(always)]\n    pub unsafe fn next_unchecked(&mut self) -> *const T {\n        // SAFETY: matching req't and cond'n (i)\n        unsafe { self.0.next_unchecked() }\n    }\n\n    /// Returns the current pointer and progresses by `count` elements.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) the iterator must have at least `count` more elements; i.e.,\n    ///   `self.remaining() >= count`.\n    pub unsafe fn next_n_unchecked(&mut self, count: usize) -> *const T {\n        // SAFETY: matching req't and cond'n (i)\n        unsafe { self.0.next_n_unchecked(count) }\n    }\n\n    /// Brings the iterator to the end, skipping the remaining positions.\n    pub(super) fn jump_to_end(&mut self) {\n        self.0.jump_to_end();\n    }\n\n    /// Creates an iterator over references to values of the remaining elements\n    /// of this iterator.\n    pub fn values(&self) -> core::slice::Iter<'a, T> {\n        self.as_slice().iter()\n    }\n\n    /// Creates a slice over references to values of the remaining elements\n    /// of this iterator.\n    pub fn as_slice(&self) -> &'a [T] {\n        let ptr = self.0.peek();\n        let n = self.len();\n        // SAFETY: SliceIterPtrSrc guarantees initialized values\n        unsafe { from_raw_parts(ptr, n) }\n    }\n}\n\nimpl<'a, T> Iterator for SliceIterPtrSrc<'a, T> {\n    type Item = *const T;\n\n    /// Returns the current pointer and progresses the iterator to the next;\n    /// returns None if the iterator `is_finished`.\n    #[inline(always)]\n    fn next(&mut self) -> Option<Self::Item> {\n        self.0.next()\n    }\n\n    #[inline(always)]\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        let len = self.0.len();\n        (len, Some(len))\n    }\n}\n\nimpl<'a, T> ExactSizeIterator for SliceIterPtrSrc<'a, T> {\n    #[inline(always)]\n    fn len(&self) -> usize {\n        self.0.len()\n    }\n}\n"
  },
  {
    "path": "src/experiment/data_structures/slice_src.rs",
    "content": "use crate::experiment::data_structures::{\n    slice::{Slice, SliceSafe},\n    slice_iter_ptr_src::SliceIterPtrSrc,\n};\n\n/// A raw slice of contiguous data with initialized values.\n///\n/// # SAFETY\n///\n/// While constructing this slice, we must guarantee that all elements of it\n/// are initialized since it will be used as source of values.\n///\n/// This is a read-only slice.\n/// The caller must make sure that there is no concurrent write to this slice.\npub struct SliceSrc<'a, T>(Slice<'a, T>);\n\nimpl<'a, T> Clone for SliceSrc<'a, T> {\n    fn clone(&self) -> Self {\n        Self(self.0.clone())\n    }\n}\n\nimpl<'a, T> SliceSrc<'a, T> {\n    /// Destructs the slice wrapper and returns the underlying raw slice\n    /// that it is created with.\n    pub fn destruct(self) -> *const [T] {\n        self.0.destruct()\n    }\n\n    /// Creates the source slice from the given `slice`.\n    ///\n    /// # SAFETY\n    ///\n    /// The `slice` guarantees that all elements are initialized.\n    ///\n    /// Further, this slice cannot outlive the `slice` it is created for due to the lifetime relation.\n    pub fn from_slice(slice: &'a [T]) -> Self {\n        Self(Slice::new(slice.as_ptr(), slice.len()))\n    }\n\n    /// Length of the slice.\n    #[inline(always)]\n    #[allow(clippy::len_without_is_empty)]\n    pub fn len(&self) -> usize {\n        self.0.len()\n    }\n\n    /// Returns a safe wrapper over this slice.\n    #[inline(always)]\n    pub fn core(&self) -> SliceSafe<'_, 'a, T> {\n        self.into()\n    }\n\n    /// Returns a reference to the first element of the slice.\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) this must have a positive `len`\n    #[inline(always)]\n    pub unsafe fn first_unchecked(&self) -> &'a T {\n        // SAFETY: req't (i) is satisfied by cond'n (i);\n        // req't (ii) is satisfied by SliceSrc construction.\n        unsafe { self.0.first_unchecked() }\n    }\n\n    /// Converts the source slice into a source iterator.\n    pub fn into_ptr_iter(self) -> SliceIterPtrSrc<'a, T> {\n        SliceIterPtrSrc::new(self)\n    }\n\n    /// Creates two slices from this slice:\n    ///\n    /// - first slice for positions [0..position)\n    /// - second slice for positions [position..]\n    ///\n    /// # SAFETY\n    ///\n    /// - (i) `position` must be less than or equal to `self.len()`\n    pub unsafe fn split_at_unchecked(self, position: usize) -> [Self; 2] {\n        // SAFETY: req't (i) is satisfied by cond'n (i)\n        unsafe { self.0.split_at_unchecked(position) }.map(Self)\n    }\n\n    /// Returns the data as a slice.\n    pub fn as_slice(&self) -> &[T] {\n        // SAFETY: (i) all values are initialized by construction,\n        // (ii) is satisfied by construction by shared reference of the data.\n        unsafe { self.0.as_slice() }\n    }\n\n    /// Creates an iterator over references to values of the slice.\n    pub fn values(&'a self) -> core::slice::Iter<'a, T> {\n        self.as_slice().iter()\n    }\n}\n\nimpl<'c, 'a, T: 'a> From<&'c SliceSrc<'a, T>> for SliceSafe<'c, 'a, T> {\n    fn from(value: &'c SliceSrc<'a, T>) -> Self {\n        SliceSafe::new(&value.0)\n    }\n}\n"
  },
  {
    "path": "src/experiment/data_structures/tests/mod.rs",
    "content": "mod slice;\n"
  },
  {
    "path": "src/experiment/data_structures/tests/slice.rs",
    "content": "use crate::experiment::data_structures::slice::{Slice, SliceSafe};\nuse alloc::vec::Vec;\nuse std::string::ToString;\nuse test_case::test_matrix;\n\n#[test]\nfn slice_overlap() {\n    let a = [1, 2, 3, 4, 5, 6];\n    let b = [7, 8];\n\n    let assert_no_overlap = |x: &[i32], y: &[i32]| {\n        let [x, y] = [x, y].map(Slice::from);\n        let [x, y] = [&x, &y].map(SliceSafe::from);\n        assert!(x.is_non_overlapping(&y));\n        assert!(y.is_non_overlapping(&x));\n    };\n\n    let assert_overlap = |x: &[i32], y: &[i32]| {\n        let [x, y] = [x, y].map(Slice::from);\n        let [x, y] = [&x, &y].map(SliceSafe::from);\n        assert!(!x.is_non_overlapping(&y));\n        assert!(!y.is_non_overlapping(&x));\n    };\n\n    assert_no_overlap(&a[..], &b[..]);\n    assert_no_overlap(&a[0..2], &a[4..]);\n    assert_no_overlap(&a[1..3], &a[3..6]);\n    assert_no_overlap(&a[0..0], &a[..]);\n\n    assert_overlap(&a[..], &a[..]);\n    assert_overlap(&a[0..2], &a[1..3]);\n    assert_overlap(&a[0..2], &a[1..2]);\n}\n\n#[test_matrix([0, 1, 2, 3, 6])]\nfn slice_split_unchecked(len: usize) {\n    let vec: Vec<_> = (1..(1 + len)).map(|x| x.to_string()).collect();\n\n    for i in 0..=vec.len() {\n        let s = Slice::from(vec.as_slice());\n\n        // SAFETY: (i) i <= s.len()\n        let [l, r] = unsafe { s.split_at_unchecked(i) };\n\n        // SAFETY: all initialized & no mutation\n        let left = unsafe { l.as_slice() }.to_vec();\n        let right = unsafe { r.as_slice() }.to_vec();\n        assert_eq!(&left, &vec[0..i]);\n        assert_eq!(&right, &vec[i..]);\n    }\n}\n\n#[test_matrix([1, 6])]\nfn slice_first_unchecked(len: usize) {\n    let vec: Vec<_> = (1..(1 + len)).map(|x| x.to_string()).collect();\n    let s = Slice::from(vec.as_slice());\n    // SAFETY: s.len() > 0\n    assert_eq!(unsafe { s.first_unchecked() }, &\"1\".to_string());\n}\n"
  },
  {
    "path": "src/experiment/mod.rs",
    "content": "/// Data structures used for internal algorithms.\npub mod data_structures;\n\n/// Algorithms.\npub mod algorithms;\n"
  },
  {
    "path": "src/generic_iterator/collect.rs",
    "content": "use super::iter::GenericIterator;\nuse crate::ParIter;\nuse alloc::vec::Vec;\n\nimpl<T, S, R, O> GenericIterator<T, S, R, O>\nwhere\n    T: Send + Sync,\n    S: Iterator<Item = T>,\n    R: rayon::iter::ParallelIterator<Item = T>,\n    O: ParIter<Item = T>,\n{\n    /// Collects the elements of the iterator into a vector.\n    ///\n    /// See [`collect`] for details of the general collect method.\n    ///\n    /// [`collect`]: crate::ParIter::collect\n    pub fn collect_vec(self) -> Vec<T> {\n        match self {\n            GenericIterator::Sequential(x) => x.collect(),\n            GenericIterator::Rayon(x) => x.collect(),\n            GenericIterator::Orx(x) => x.collect(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_iterator/early_exit.rs",
    "content": "use super::iter::GenericIterator;\nuse crate::{IterationOrder, ParIter};\n\nimpl<T, S, R, O> GenericIterator<T, S, R, O>\nwhere\n    T: Send + Sync,\n    S: Iterator<Item = T>,\n    R: rayon::iter::ParallelIterator<Item = T>,\n    O: ParIter<Item = T>,\n{\n    /// Find computation for the generic iterator.\n    ///\n    /// See [`find`] for details.\n    ///\n    /// [`find`]: crate::ParIter::find\n    pub fn find<Predicate>(self, predicate: Predicate) -> Option<T>\n    where\n        Predicate: Fn(&T) -> bool + Send + Sync + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(mut x) => x.find(predicate),\n            GenericIterator::Rayon(x) => x.find_first(predicate),\n            GenericIterator::Orx(x) => x.find(predicate),\n        }\n    }\n\n    /// Find-any computation for the generic iterator.\n    ///\n    /// See [`first`] for details.\n    ///\n    /// [`first`]: crate::ParIter::first\n    pub fn find_any<Predicate>(self, predicate: Predicate) -> Option<T>\n    where\n        Predicate: Fn(&T) -> bool + Send + Sync + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(mut x) => x.find(predicate),\n            GenericIterator::Rayon(x) => x.find_any(predicate),\n            GenericIterator::Orx(x) => x.iteration_order(IterationOrder::Arbitrary).find(predicate),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_iterator/iter.rs",
    "content": "use crate::ParIter;\n\n/// An iterator that generalizes over:\n///\n/// * sequential iterators,\n/// * rayon's parallel iterators, and\n/// * orx-parallel's parallel iterators.\n///\n/// This is particularly useful for enabling a convenient way to run experiments\n/// using these different computation approaches.\npub enum GenericIterator<T, S, R, O>\nwhere\n    T: Send + Sync,\n    S: Iterator<Item = T>,\n    R: rayon::iter::ParallelIterator<Item = T>,\n    O: ParIter<Item = T>,\n{\n    /// Sequential, or regular, iterator.\n    Sequential(S),\n    /// rayon's parallel iterator.\n    Rayon(R),\n    /// orx-parallel's parallel iterator.\n    Orx(O),\n}\n\nimpl<T, S> GenericIterator<T, S, rayon::iter::Empty<T>, crate::iter::ParEmpty<T>>\nwhere\n    T: Send + Sync,\n    S: Iterator<Item = T>,\n{\n    /// Creates the generic iterator from sequential iterator variant.\n    pub fn sequential(iter: S) -> Self {\n        Self::Sequential(iter)\n    }\n}\n\nimpl<T, R> GenericIterator<T, core::iter::Empty<T>, R, crate::iter::ParEmpty<T>>\nwhere\n    T: Send + Sync,\n    R: rayon::iter::ParallelIterator<Item = T>,\n{\n    /// Creates the generic iterator from rayon iterator variant.\n    pub fn rayon(iter: R) -> Self {\n        Self::Rayon(iter)\n    }\n}\n\nimpl<T, O> GenericIterator<T, core::iter::Empty<T>, rayon::iter::Empty<T>, O>\nwhere\n    T: Send + Sync,\n    O: ParIter<Item = T>,\n{\n    /// Creates the generic iterator from orx-parallel iterator variant.\n    pub fn orx(iter: O) -> Self {\n        Self::Orx(iter)\n    }\n}\n"
  },
  {
    "path": "src/generic_iterator/mod.rs",
    "content": "mod collect;\nmod early_exit;\nmod iter;\nmod reduce;\nmod transformations;\n\npub use iter::GenericIterator;\n"
  },
  {
    "path": "src/generic_iterator/reduce.rs",
    "content": "use super::iter::GenericIterator;\nuse crate::ParIter;\nuse core::cmp::Ordering;\n\nimpl<T, S, R, O> GenericIterator<T, S, R, O>\nwhere\n    T: Send + Sync,\n    S: Iterator<Item = T>,\n    R: rayon::iter::ParallelIterator<Item = T>,\n    O: ParIter<Item = T>,\n{\n    /// Reduction for the generic iterator.\n    ///\n    /// See [`reduce`] for details.\n    ///\n    /// [`reduce`]: crate::ParIter::reduce\n    pub fn reduce<Reduce>(self, reduce: Reduce) -> Option<T>\n    where\n        Reduce: Fn(T, T) -> T + Send + Sync,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.reduce(reduce),\n            GenericIterator::Rayon(x) => x.reduce_with(reduce),\n            GenericIterator::Orx(x) => x.reduce(reduce),\n        }\n    }\n\n    /// Count reduction for the generic iterator.\n    ///\n    /// See [`count`] for details.\n    ///\n    /// [`count`]: crate::ParIter::count\n    pub fn count(self) -> usize {\n        match self {\n            GenericIterator::Sequential(x) => x.count(),\n            GenericIterator::Rayon(x) => x.count(),\n            GenericIterator::Orx(x) => x.count(),\n        }\n    }\n\n    /// For-each iteration for the generic iterator.\n    ///\n    /// See [`for_each`] for details.\n    ///\n    /// [`for_each`]: crate::ParIter::for_each\n    pub fn for_each<Operation>(self, operation: Operation)\n    where\n        Operation: Fn(T) + Sync + Send,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.for_each(operation),\n            GenericIterator::Rayon(x) => x.for_each(operation),\n            GenericIterator::Orx(x) => x.for_each(operation),\n        }\n    }\n\n    /// Max reduction for the generic iterator.\n    ///\n    /// See [`max`] for details.\n    ///\n    /// [`max`]: crate::ParIter::max\n    pub fn max(self) -> Option<T>\n    where\n        T: Ord,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.max(),\n            GenericIterator::Rayon(x) => x.max(),\n            GenericIterator::Orx(x) => x.max(),\n        }\n    }\n\n    /// Max-by reduction for the generic iterator.\n    ///\n    /// See [`max_by`] for details.\n    ///\n    /// [`max_by`]: crate::ParIter::max_by\n    pub fn max_by<Compare>(self, compare: Compare) -> Option<T>\n    where\n        Compare: Fn(&T, &T) -> Ordering + Sync + Send,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.max_by(compare),\n            GenericIterator::Rayon(x) => x.max_by(compare),\n            GenericIterator::Orx(x) => x.max_by(compare),\n        }\n    }\n\n    /// Max-by-key reduction for the generic iterator.\n    ///\n    /// See [`max_by_key`] for details.\n    ///\n    /// [`max_by_key`]: crate::ParIter::max_by_key\n    pub fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<T>\n    where\n        Key: Ord + Send,\n        GetKey: Fn(&T) -> Key + Sync + Send,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.max_by_key(key),\n            GenericIterator::Rayon(x) => x.max_by_key(key),\n            GenericIterator::Orx(x) => x.max_by_key(key),\n        }\n    }\n\n    /// Min reduction for the generic iterator.\n    ///\n    /// See [`min`] for details.\n    ///\n    /// [`min`]: crate::ParIter::min\n    pub fn min(self) -> Option<T>\n    where\n        T: Ord,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.min(),\n            GenericIterator::Rayon(x) => x.min(),\n            GenericIterator::Orx(x) => x.min(),\n        }\n    }\n\n    /// Min-by reduction for the generic iterator.\n    ///\n    /// See [`min_by`] for details.\n    ///\n    /// [`min_by`]: crate::ParIter::min_by\n    pub fn min_by<Compare>(self, compare: Compare) -> Option<T>\n    where\n        Compare: Fn(&T, &T) -> Ordering + Sync + Send,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.min_by(compare),\n            GenericIterator::Rayon(x) => x.min_by(compare),\n            GenericIterator::Orx(x) => x.min_by(compare),\n        }\n    }\n\n    /// Min-by-key reduction for the generic iterator.\n    ///\n    /// See [`min_by_key`] for details.\n    ///\n    /// [`min_by_key`]: crate::ParIter::min_by_key\n    pub fn min_by_key<Key, GetKey>(self, key: GetKey) -> Option<T>\n    where\n        Key: Ord + Send,\n        GetKey: Fn(&T) -> Key + Sync + Send,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.min_by_key(key),\n            GenericIterator::Rayon(x) => x.min_by_key(key),\n            GenericIterator::Orx(x) => x.min_by_key(key),\n        }\n    }\n\n    /// Sum reduction for the generic iterator.\n    ///\n    /// See [`sum`] for details.\n    ///\n    /// [`sum`]: crate::ParIter::sum\n    pub fn sum(self) -> T\n    where\n        T: crate::special_type_sets::Sum<T> + core::iter::Sum<T>,\n    {\n        match self {\n            GenericIterator::Sequential(x) => x.sum(),\n            GenericIterator::Rayon(x) => x.sum(),\n            GenericIterator::Orx(x) => x.sum(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_iterator/transformations.rs",
    "content": "use super::iter::GenericIterator;\nuse crate::ParIter;\n\nimpl<T, S, R, O> GenericIterator<T, S, R, O>\nwhere\n    T: Send + Sync,\n    S: Iterator<Item = T>,\n    R: rayon::iter::ParallelIterator<Item = T>,\n    O: ParIter<Item = T>,\n{\n    // computation transformations\n\n    /// Map transformation for the generic iterator.\n    ///\n    /// See [`map`] for details.\n    ///\n    /// [`map`]: crate::ParIter::map\n    pub fn map<Out, Map>(\n        self,\n        map: Map,\n    ) -> GenericIterator<\n        Out,\n        impl Iterator<Item = Out>,\n        impl rayon::iter::ParallelIterator<Item = Out>,\n        impl ParIter<Item = Out>,\n    >\n    where\n        Out: Send + Sync,\n        Map: Fn(T) -> Out + Send + Sync + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.map(map)),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.map(map)),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.map(map)),\n        }\n    }\n\n    /// Filter transformation for the generic iterator.\n    ///\n    /// See [`filter`] for details.\n    ///\n    /// [`filter`]: crate::ParIter::filter\n    pub fn filter<Filter>(\n        self,\n        filter: Filter,\n    ) -> GenericIterator<\n        T,\n        impl Iterator<Item = T>,\n        impl rayon::iter::ParallelIterator<Item = T>,\n        impl ParIter<Item = T>,\n    >\n    where\n        Filter: Fn(&T) -> bool + Send + Sync + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.filter(filter)),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.filter(filter)),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.filter(filter)),\n        }\n    }\n\n    /// Flat-map transformation for the generic iterator.\n    ///\n    /// See [`flat_map`] for details.\n    ///\n    /// [`flat_map`]: crate::ParIter::flat_map\n    pub fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> GenericIterator<\n        <IOut as IntoIterator>::Item,\n        impl Iterator<Item = <IOut as IntoIterator>::Item>,\n        impl rayon::iter::ParallelIterator<Item = <IOut as IntoIterator>::Item>,\n        impl ParIter<Item = <IOut as IntoIterator>::Item>,\n    >\n    where\n        IOut: IntoIterator\n            + Send\n            + Sync\n            + rayon::iter::IntoParallelIterator<Item = <IOut as IntoIterator>::Item>,\n        <IOut as IntoIterator>::IntoIter: Send + Sync,\n        <IOut as IntoIterator>::Item: Send + Sync,\n        FlatMap: Fn(T) -> IOut + Send + Sync + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.flat_map(flat_map)),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.flat_map(flat_map)),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.flat_map(flat_map)),\n        }\n    }\n\n    /// Filter-map transformation for the generic iterator.\n    ///\n    /// See [`filter_map`] for details.\n    ///\n    /// [`filter_map`]: crate::ParIter::filter_map\n    pub fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> GenericIterator<\n        Out,\n        impl Iterator<Item = Out>,\n        impl rayon::iter::ParallelIterator<Item = Out>,\n        impl ParIter<Item = Out>,\n    >\n    where\n        Out: Send + Sync,\n        FilterMap: Fn(T) -> Option<Out> + Send + Sync + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.filter_map(filter_map)),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.filter_map(filter_map)),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.filter_map(filter_map)),\n        }\n    }\n\n    /// Inspect transformation for the generic iterator.\n    ///\n    /// See [`inspect`] for details.\n    ///\n    /// [`inspect`]: crate::ParIter::inspect\n    pub fn inspect<Operation>(\n        self,\n        operation: Operation,\n    ) -> GenericIterator<\n        T,\n        impl Iterator<Item = T>,\n        impl rayon::iter::ParallelIterator<Item = T>,\n        impl ParIter<Item = T>,\n    >\n    where\n        Operation: Fn(&T) + Sync + Send + Clone,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.inspect(operation)),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.inspect(operation)),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.inspect(operation)),\n        }\n    }\n\n    // special item transformations\n\n    /// Flatten transformation for the generic iterator.\n    ///\n    /// See [`flatten`] for details.\n    ///\n    /// [`flatten`]: crate::ParIter::flatten\n    pub fn flatten(\n        self,\n    ) -> GenericIterator<\n        <T as IntoIterator>::Item,\n        impl Iterator<Item = <T as IntoIterator>::Item>,\n        impl rayon::iter::ParallelIterator<Item = <T as IntoIterator>::Item>,\n        impl ParIter<Item = <T as IntoIterator>::Item>,\n    >\n    where\n        T: IntoIterator + rayon::iter::IntoParallelIterator<Item = <T as IntoIterator>::Item>,\n        <T as IntoIterator>::IntoIter: Send + Sync,\n        <T as IntoIterator>::Item: Send + Sync,\n        R: Send + Sync,\n        Self: Send + Sync,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.flatten()),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.flatten()),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.flatten()),\n        }\n    }\n}\n\n// special item transformations\n\nimpl<'a, T, S, R, O> GenericIterator<&'a T, S, R, O>\nwhere\n    &'a T: Send + Sync,\n    S: Iterator<Item = &'a T>,\n    R: rayon::iter::ParallelIterator<Item = &'a T>,\n    O: ParIter<Item = &'a T>,\n{\n    /// Copied transformation for the generic iterator.\n    ///\n    /// See [`copied`] for details.\n    ///\n    /// [`copied`]: crate::ParIter::copied\n    pub fn copied(\n        self,\n    ) -> GenericIterator<\n        T,\n        impl Iterator<Item = T> + use<'a, T, S, R, O>,\n        impl rayon::iter::ParallelIterator<Item = T> + use<'a, T, S, R, O>,\n        impl ParIter<Item = T> + use<'a, T, S, R, O>,\n    >\n    where\n        T: Copy + Send + Sync + 'a,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.copied()),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.copied()),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.copied()),\n        }\n    }\n\n    /// Cloned transformation for the generic iterator.\n    ///\n    /// See [`cloned`] for details.\n    ///\n    /// [`cloned`]: crate::ParIter::cloned\n    pub fn cloned(\n        self,\n    ) -> GenericIterator<\n        T,\n        impl Iterator<Item = T> + use<'a, T, S, R, O>,\n        impl rayon::iter::ParallelIterator<Item = T> + use<'a, T, S, R, O>,\n        impl ParIter<Item = T> + use<'a, T, S, R, O>,\n    >\n    where\n        T: Clone + Send + Sync + 'a,\n    {\n        match self {\n            GenericIterator::Sequential(x) => GenericIterator::Sequential(x.cloned()),\n            GenericIterator::Rayon(x) => GenericIterator::Rayon(x.cloned()),\n            GenericIterator::Orx(x) => GenericIterator::Orx(x.cloned()),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/fallible_iterators/mod.rs",
    "content": "mod result_of_iter;\n\npub use result_of_iter::ResultOfIter;\n"
  },
  {
    "path": "src/generic_values/fallible_iterators/result_of_iter.rs",
    "content": "pub struct ResultOfIter<I, E>\nwhere\n    I: Iterator,\n{\n    iter: Option<I>,\n    error: Option<E>,\n}\n\nimpl<I, E> ResultOfIter<I, E>\nwhere\n    I: Iterator,\n{\n    pub fn ok(iter: I) -> Self {\n        Self {\n            iter: Some(iter),\n            error: None,\n        }\n    }\n\n    pub fn err(error: E) -> Self {\n        Self {\n            iter: None,\n            error: Some(error),\n        }\n    }\n}\n\nimpl<I, E> Iterator for ResultOfIter<I, E>\nwhere\n    I: Iterator,\n{\n    type Item = Result<I::Item, E>;\n\n    #[inline]\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.iter.as_mut() {\n            Some(iter) => iter.next().map(|x| Ok(x)),\n            None => self.error.take().map(|e| Err(e)),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/mod.rs",
    "content": "pub mod fallible_iterators;\nmod option;\nmod option_result;\nmod result;\npub(crate) mod runner_results;\nmod transformable_values;\nmod values;\nmod vector;\nmod vector_result;\nmod whilst_atom;\nmod whilst_atom_result;\nmod whilst_iterators;\nmod whilst_option;\nmod whilst_option_result;\nmod whilst_vector;\nmod whilst_vector_result;\n\npub use transformable_values::TransformableValues;\npub use values::Values;\npub use vector::Vector;\npub use vector_result::VectorResult;\npub use whilst_atom::WhilstAtom;\npub use whilst_option::WhilstOption;\npub use whilst_vector::WhilstVector;\n"
  },
  {
    "path": "src/generic_values/option.rs",
    "content": "use super::{TransformableValues, Vector};\nuse crate::generic_values::Values;\nuse crate::generic_values::{\n    option_result::OptionResult,\n    runner_results::{\n        ArbitraryPush, Fallible, Infallible, Next, OrderedPush, Reduce, SequentialPush,\n    },\n    whilst_option::WhilstOption,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\nimpl<T> Values for Option<T> {\n    type Item = T;\n\n    type Fallibility = Infallible;\n\n    #[inline(always)]\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        if let Some(x) = self {\n            vector.push(x)\n        }\n        SequentialPush::Done\n    }\n\n    #[inline(always)]\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        if let Some(x) = self {\n            vec.push((idx, x));\n        }\n        OrderedPush::Done\n    }\n\n    #[inline(always)]\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        if let Some(x) = self {\n            bag.push(x);\n        }\n        ArbitraryPush::Done\n    }\n\n    #[inline(always)]\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        Reduce::Done {\n            acc: match (acc, self) {\n                (Some(x), Some(y)) => Some(reduce(x, y)),\n                (Some(x), None) => Some(x),\n                (None, Some(y)) => Some(y),\n                (None, None) => None,\n            },\n        }\n    }\n\n    #[inline(always)]\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        Reduce::Done {\n            acc: match (acc, self) {\n                (Some(x), Some(y)) => Some(reduce(u, x, y)),\n                (Some(x), None) => Some(x),\n                (None, Some(y)) => Some(y),\n                (None, None) => None,\n            },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        Next::Done { value: self }\n    }\n}\n\nimpl<T> TransformableValues for Option<T> {\n    #[inline(always)]\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O,\n    {\n        self.map(map)\n    }\n\n    #[inline(always)]\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool,\n    {\n        self.filter(filter)\n    }\n\n    #[inline(always)]\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo,\n    {\n        Vector(self.into_iter().flat_map(flat_map))\n    }\n\n    #[inline(always)]\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>,\n    {\n        match self {\n            Some(x) => filter_map(x),\n            _ => None,\n        }\n    }\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        Self: Sized,\n    {\n        match self {\n            Some(x) => match whilst(&x) {\n                true => WhilstOption::ContinueSome(x),\n                false => WhilstOption::Stop,\n            },\n            _ => WhilstOption::ContinueNone,\n        }\n    }\n\n    fn map_while_ok<Mr, O, E>(self, map_res: Mr) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send,\n    {\n        let opt_res = self.map(map_res);\n        OptionResult(opt_res)\n    }\n\n    #[inline(always)]\n    fn u_map<U, M, O>(\n        self,\n        u: *mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(*mut U, Self::Item) -> O,\n    {\n        self.map(|x| map(u, x))\n    }\n\n    #[inline(always)]\n    fn u_filter<U, F>(\n        self,\n        u: *mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(*mut U, &Self::Item) -> bool,\n    {\n        self.filter(|x| filter(u, x))\n    }\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: *mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(*mut U, Self::Item) -> Vo,\n    {\n        Vector(self.into_iter().flat_map(move |x| flat_map(u, x)))\n    }\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: *mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(*mut U, Self::Item) -> Option<O>,\n    {\n        match self {\n            Some(x) => filter_map(u, x),\n            _ => None,\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/option_result.rs",
    "content": "use crate::generic_values::Values;\nuse crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\npub struct OptionResult<T, E>(pub(crate) Option<Result<T, E>>)\nwhere\n    E: Send;\n\nimpl<T, E> Values for OptionResult<T, E>\nwhere\n    E: Send,\n{\n    type Item = T;\n\n    type Fallibility = Fallible<E>;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        match self.0 {\n            Some(Ok(x)) => {\n                vector.push(x);\n                SequentialPush::Done\n            }\n            Some(Err(error)) => SequentialPush::StoppedByError { error },\n            None => SequentialPush::Done,\n        }\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        match self.0 {\n            Some(Ok(x)) => {\n                vec.push((idx, x));\n                OrderedPush::Done\n            }\n            Some(Err(error)) => OrderedPush::StoppedByError { idx, error },\n            None => OrderedPush::Done,\n        }\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        match self.0 {\n            Some(Ok(x)) => {\n                _ = bag.push(x);\n                ArbitraryPush::Done\n            }\n            Some(Err(error)) => ArbitraryPush::StoppedByError { error },\n            None => ArbitraryPush::Done,\n        }\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        match self.0 {\n            Some(Ok(x)) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(y) => reduce(y, x),\n                    None => x,\n                }),\n            },\n            None => Reduce::Done { acc },\n            Some(Err(error)) => Reduce::StoppedByError { error },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        match self.0 {\n            Some(Ok(x)) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(y) => reduce(u, y, x),\n                    None => x,\n                }),\n            },\n            None => Reduce::Done { acc },\n            Some(Err(error)) => Reduce::StoppedByError { error },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self.0 {\n            Some(Ok(value)) => Next::Done { value: Some(value) },\n            None => Next::Done { value: None },\n            Some(Err(error)) => Next::StoppedByError { error },\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/result.rs",
    "content": "use crate::generic_values::Values;\nuse crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\n/// Represents scalar value for early stopping error cases:\n///\n/// * Whenever computation creates an error at any point, all computed values are irrelevant,\n///   the only relevant value is the created error.\n/// * Computed values are relevant iff entire inputs result in an Ok variant.\n/// * Therefore, observation of an error case allows to immediately stop computation.\nimpl<T, E> Values for Result<T, E>\nwhere\n    E: Send,\n{\n    type Item = T;\n\n    type Fallibility = Fallible<E>;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        match self {\n            Ok(x) => {\n                vector.push(x);\n                SequentialPush::Done\n            }\n            Err(error) => SequentialPush::StoppedByError { error },\n        }\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        match self {\n            Ok(x) => {\n                vec.push((idx, x));\n                OrderedPush::Done\n            }\n            Err(error) => OrderedPush::StoppedByError { idx, error },\n        }\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        match self {\n            Ok(x) => {\n                bag.push(x);\n                ArbitraryPush::Done\n            }\n            Err(error) => ArbitraryPush::StoppedByError { error },\n        }\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Ok(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(acc, x),\n                    None => x,\n                }),\n            },\n            Err(error) => Reduce::StoppedByError { error },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Ok(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(u, acc, x),\n                    None => x,\n                }),\n            },\n            Err(error) => Reduce::StoppedByError { error },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self {\n            Ok(x) => Next::Done { value: Some(x) },\n            Err(error) => Next::StoppedByError { error },\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/runner_results/collect_arbitrary.rs",
    "content": "use crate::generic_values::{Values, runner_results::Fallibility};\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub enum ArbitraryPush<F: Fallibility> {\n    Done,\n    StoppedByWhileCondition,\n    StoppedByError { error: F::Error },\n}\n\npub enum ThreadCollectArbitrary<F>\nwhere\n    F: Fallibility,\n{\n    AllCollected,\n    StoppedByWhileCondition,\n    StoppedByError { error: F::Error },\n}\n\nimpl<F: Fallibility> ThreadCollectArbitrary<F> {\n    pub fn into_result(self) -> Result<(), F::Error> {\n        match self {\n            Self::StoppedByError { error } => Err(error),\n            _ => Ok(()),\n        }\n    }\n}\n\nimpl<F: Fallibility> core::fmt::Debug for ThreadCollectArbitrary<F> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::AllCollected => write!(f, \"AllCollected\"),\n            Self::StoppedByWhileCondition => write!(f, \"StoppedByWhileCondition\"),\n            Self::StoppedByError { error: _ } => f.debug_struct(\"StoppedByError\").finish(),\n        }\n    }\n}\n\npub enum ParallelCollectArbitrary<V, P>\nwhere\n    V: Values,\n    P: IntoConcurrentPinnedVec<V::Item>,\n{\n    AllOrUntilWhileCollected {\n        pinned_vec: P,\n    },\n\n    StoppedByError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n\nimpl<V, P> core::fmt::Debug for ParallelCollectArbitrary<V, P>\nwhere\n    V: Values,\n    P: IntoConcurrentPinnedVec<V::Item>,\n{\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::AllOrUntilWhileCollected { pinned_vec } => f\n                .debug_struct(\"AllCollected\")\n                .field(\"pinned_vec.len()\", &pinned_vec.len())\n                .finish(),\n            Self::StoppedByError { error: _ } => f.debug_struct(\"StoppedByError\").finish(),\n        }\n    }\n}\n\nimpl<V, P> ParallelCollectArbitrary<V, P>\nwhere\n    V: Values,\n    P: IntoConcurrentPinnedVec<V::Item>,\n{\n    pub fn into_result(self) -> Result<P, <V::Fallibility as Fallibility>::Error> {\n        match self {\n            Self::AllOrUntilWhileCollected { pinned_vec } => Ok(pinned_vec),\n            Self::StoppedByError { error } => Err(error),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/runner_results/collect_ordered.rs",
    "content": "use crate::{\n    generic_values::{Values, runner_results::Fallibility},\n    heap_sort::heap_sort_into,\n};\nuse alloc::vec::Vec;\nuse core::fmt::Debug;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub enum OrderedPush<F: Fallibility> {\n    Done,\n    StoppedByWhileCondition { idx: usize },\n    StoppedByError { idx: usize, error: F::Error },\n}\n\npub enum ThreadCollect<V>\nwhere\n    V: Values,\n{\n    AllCollected {\n        vec: Vec<(usize, V::Item)>,\n    },\n    StoppedByWhileCondition {\n        vec: Vec<(usize, V::Item)>,\n        stopped_idx: usize,\n    },\n    StoppedByError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n\nimpl<V: Values> Debug for ThreadCollect<V> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::AllCollected { vec } => f\n                .debug_struct(\"AllCollected\")\n                .field(\"vec-len\", &vec.len())\n                .finish(),\n            Self::StoppedByWhileCondition { vec, stopped_idx } => f\n                .debug_struct(\"StoppedByWhileCondition\")\n                .field(\"vec-len\", &vec.len())\n                .field(\"stopped_idx\", stopped_idx)\n                .finish(),\n            Self::StoppedByError { error: _ } => f.debug_struct(\"StoppedByError\").finish(),\n        }\n    }\n}\n\nimpl<V: Values> ThreadCollect<V> {\n    pub fn into_result(self) -> Result<Self, <V::Fallibility as Fallibility>::Error> {\n        match self {\n            Self::StoppedByError { error } => Err(error),\n            _ => Ok(self),\n        }\n    }\n}\n\npub enum ParallelCollect<V, P>\nwhere\n    V: Values,\n    P: IntoConcurrentPinnedVec<V::Item>,\n{\n    AllCollected {\n        pinned_vec: P,\n    },\n    StoppedByWhileCondition {\n        pinned_vec: P,\n        stopped_idx: usize,\n    },\n    StoppedByError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n\nimpl<V, P> core::fmt::Debug for ParallelCollect<V, P>\nwhere\n    V: Values,\n    P: IntoConcurrentPinnedVec<V::Item>,\n{\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::AllCollected { pinned_vec } => f\n                .debug_struct(\"AllCollected\")\n                .field(\"pinned_vec.len()\", &pinned_vec.len())\n                .finish(),\n            Self::StoppedByWhileCondition {\n                pinned_vec,\n                stopped_idx,\n            } => f\n                .debug_struct(\"StoppedByWhileCondition\")\n                .field(\"pinned_vec.len()\", &pinned_vec.len())\n                .field(\"stopped_idx\", stopped_idx)\n                .finish(),\n            Self::StoppedByError { error: _ } => f.debug_struct(\"StoppedByError\").finish(),\n        }\n    }\n}\n\nimpl<V, P> ParallelCollect<V, P>\nwhere\n    V: Values,\n    P: IntoConcurrentPinnedVec<V::Item>,\n{\n    pub fn reduce(results: Vec<ThreadCollect<V>>, mut pinned_vec: P) -> Self {\n        let mut vectors = Vec::with_capacity(results.len());\n        let mut min_stopped_idx = None;\n\n        for x in results {\n            match x {\n                ThreadCollect::AllCollected { vec } => vectors.push(vec),\n                ThreadCollect::StoppedByWhileCondition { vec, stopped_idx } => {\n                    min_stopped_idx = match min_stopped_idx {\n                        Some(x) => Some(core::cmp::min(x, stopped_idx)),\n                        None => Some(stopped_idx),\n                    };\n                    vectors.push(vec);\n                }\n                ThreadCollect::StoppedByError { error } => return Self::StoppedByError { error },\n            }\n        }\n\n        heap_sort_into(vectors, min_stopped_idx, &mut pinned_vec);\n\n        match min_stopped_idx {\n            Some(stopped_idx) => Self::StoppedByWhileCondition {\n                pinned_vec,\n                stopped_idx,\n            },\n            None => Self::AllCollected { pinned_vec },\n        }\n    }\n\n    pub fn into_result(self) -> Result<P, <V::Fallibility as Fallibility>::Error> {\n        match self {\n            Self::AllCollected { pinned_vec } => Ok(pinned_vec),\n            Self::StoppedByWhileCondition {\n                pinned_vec,\n                stopped_idx: _,\n            } => Ok(pinned_vec),\n            Self::StoppedByError { error } => Err(error),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/runner_results/collect_sequential.rs",
    "content": "use crate::generic_values::runner_results::{\n    Fallibility, Fallible, Infallible, Stop, fallibility::Never,\n};\n\npub enum SequentialPush<F: Fallibility> {\n    Done,\n    StoppedByWhileCondition,\n    StoppedByError { error: F::Error },\n}\n\nimpl SequentialPush<Infallible> {\n    pub fn sequential_push_to_stop(self) -> Option<Stop<Never>> {\n        match self {\n            SequentialPush::StoppedByWhileCondition => Some(Stop::DueToWhile),\n            _ => None,\n        }\n    }\n}\n\nimpl<E: Send> SequentialPush<Fallible<E>> {\n    pub fn sequential_push_to_stop(self) -> Option<Stop<E>> {\n        match self {\n            SequentialPush::Done => None,\n            SequentialPush::StoppedByWhileCondition => Some(Stop::DueToWhile),\n            SequentialPush::StoppedByError { error } => Some(Stop::DueToError { error }),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/runner_results/fallibility.rs",
    "content": "use crate::generic_values::{\n    Values,\n    runner_results::{\n        ArbitraryPush, OrderedPush, Reduce, SequentialPush, Stop, StopWithIdx, stop::StopReduce,\n    },\n};\nuse alloc::vec::Vec;\nuse core::marker::PhantomData;\n\npub trait Fallibility: Sized {\n    type Error: Send;\n\n    fn ordered_push_to_stop(ordered_push: OrderedPush<Self>) -> Option<StopWithIdx<Self::Error>>;\n\n    fn arbitrary_push_to_stop(arbitrary_push: ArbitraryPush<Self>) -> Option<Stop<Self::Error>>;\n\n    fn sequential_push_to_stop(sequential_push: SequentialPush<Self>) -> Option<Stop<Self::Error>>;\n\n    fn reduce_to_stop<V>(reduce: Reduce<V>) -> Result<Option<V::Item>, StopReduce<V>>\n    where\n        V: Values<Fallibility = Self>;\n\n    fn reduce_results<T>(results: Vec<Result<T, Self::Error>>) -> Result<Vec<T>, Self::Error>;\n}\n\npub struct Infallible;\n\nimpl Fallibility for Infallible {\n    type Error = Never;\n\n    #[inline(always)]\n    fn ordered_push_to_stop(ordered_push: OrderedPush<Self>) -> Option<StopWithIdx<Self::Error>> {\n        match ordered_push {\n            OrderedPush::Done => None,\n            OrderedPush::StoppedByWhileCondition { idx } => Some(StopWithIdx::DueToWhile { idx }),\n        }\n    }\n\n    #[inline(always)]\n    fn arbitrary_push_to_stop(arbitrary_push: ArbitraryPush<Self>) -> Option<Stop<Self::Error>> {\n        match arbitrary_push {\n            ArbitraryPush::Done => None,\n            ArbitraryPush::StoppedByWhileCondition => Some(Stop::DueToWhile),\n        }\n    }\n\n    #[inline(always)]\n    fn sequential_push_to_stop(sequential_push: SequentialPush<Self>) -> Option<Stop<Self::Error>> {\n        match sequential_push {\n            SequentialPush::StoppedByWhileCondition => Some(Stop::DueToWhile),\n            _ => None,\n        }\n    }\n\n    #[inline(always)]\n    fn reduce_to_stop<V>(reduce: Reduce<V>) -> Result<Option<V::Item>, StopReduce<V>>\n    where\n        V: Values<Fallibility = Self>,\n    {\n        match reduce {\n            Reduce::Done { acc } => Ok(acc),\n            Reduce::StoppedByWhileCondition { acc } => Err(StopReduce::DueToWhile { acc }),\n        }\n    }\n\n    fn reduce_results<T>(results: Vec<Result<T, Self::Error>>) -> Result<Vec<T>, Self::Error> {\n        Ok(results\n            .into_iter()\n            .map(|x| match x {\n                Ok(x) => x,\n            })\n            .collect())\n    }\n}\n\npub struct Fallible<E>(PhantomData<E>);\n\nimpl<E: Send> Fallibility for Fallible<E> {\n    type Error = E;\n\n    #[inline(always)]\n    fn ordered_push_to_stop(ordered_push: OrderedPush<Self>) -> Option<StopWithIdx<Self::Error>> {\n        match ordered_push {\n            OrderedPush::Done => None,\n            OrderedPush::StoppedByWhileCondition { idx } => Some(StopWithIdx::DueToWhile { idx }),\n            OrderedPush::StoppedByError { idx, error } => {\n                Some(StopWithIdx::DueToError { idx, error })\n            }\n        }\n    }\n\n    #[inline(always)]\n    fn arbitrary_push_to_stop(arbitrary_push: ArbitraryPush<Self>) -> Option<Stop<Self::Error>> {\n        match arbitrary_push {\n            ArbitraryPush::Done => None,\n            ArbitraryPush::StoppedByWhileCondition => Some(Stop::DueToWhile),\n            ArbitraryPush::StoppedByError { error } => Some(Stop::DueToError { error }),\n        }\n    }\n\n    #[inline(always)]\n    fn sequential_push_to_stop(sequential_push: SequentialPush<Self>) -> Option<Stop<Self::Error>> {\n        match sequential_push {\n            SequentialPush::Done => None,\n            SequentialPush::StoppedByWhileCondition => Some(Stop::DueToWhile),\n            SequentialPush::StoppedByError { error } => Some(Stop::DueToError { error }),\n        }\n    }\n\n    #[inline(always)]\n    fn reduce_to_stop<V>(reduce: Reduce<V>) -> Result<Option<V::Item>, StopReduce<V>>\n    where\n        V: Values<Fallibility = Self>,\n    {\n        match reduce {\n            Reduce::Done { acc } => Ok(acc),\n            Reduce::StoppedByWhileCondition { acc } => Err(StopReduce::DueToWhile { acc }),\n            Reduce::StoppedByError { error } => Err(StopReduce::DueToError { error }),\n        }\n    }\n\n    fn reduce_results<T>(results: Vec<Result<T, Self::Error>>) -> Result<Vec<T>, Self::Error> {\n        let mut ok_results = Vec::with_capacity(results.len());\n        for result in results {\n            match result {\n                Ok(x) => ok_results.push(x),\n                Err(e) => return Err(e),\n            }\n        }\n        Ok(ok_results)\n    }\n}\n\npub enum Never {}\n"
  },
  {
    "path": "src/generic_values/runner_results/mod.rs",
    "content": "mod collect_arbitrary;\nmod collect_ordered;\nmod collect_sequential;\nmod fallibility;\nmod next;\nmod reduce;\nmod stop;\n\npub use collect_arbitrary::{ArbitraryPush, ParallelCollectArbitrary, ThreadCollectArbitrary};\npub use collect_ordered::{OrderedPush, ParallelCollect, ThreadCollect};\npub use collect_sequential::SequentialPush;\npub use fallibility::{Fallibility, Fallible, Infallible, Never};\npub use next::{Next, NextSuccess, NextWithIdx};\npub use reduce::Reduce;\npub use stop::{Stop, StopReduce, StopWithIdx};\n"
  },
  {
    "path": "src/generic_values/runner_results/next.rs",
    "content": "use crate::generic_values::{Values, runner_results::Fallibility};\n\npub enum Next<V: Values> {\n    Done {\n        value: Option<V::Item>,\n    },\n    StoppedByWhileCondition,\n    StoppedByError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n\npub enum NextWithIdx<V: Values> {\n    Found {\n        idx: usize,\n        value: V::Item,\n    },\n    NotFound,\n    StoppedByWhileCondition {\n        idx: usize,\n    },\n    StoppedByError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n\npub enum NextSuccess<T> {\n    Found { idx: usize, value: T },\n    StoppedByWhileCondition { idx: usize },\n}\n\nimpl<T> NextSuccess<T> {\n    pub fn reduce(results: impl IntoIterator<Item = Self>) -> Option<(usize, T)> {\n        let mut result = None;\n        let mut idx_bound = usize::MAX;\n        for x in results {\n            match x {\n                NextSuccess::Found { idx, value } if idx < idx_bound => {\n                    idx_bound = idx;\n                    result = Some((idx, value));\n                }\n                NextSuccess::StoppedByWhileCondition { idx } if idx < idx_bound => {\n                    idx_bound = idx;\n                }\n                _ => {}\n            }\n        }\n\n        result.and_then(|(idx, value)| match idx <= idx_bound {\n            true => Some((idx, value)),\n            false => None, // found value was found after stopped\n        })\n    }\n}\n"
  },
  {
    "path": "src/generic_values/runner_results/reduce.rs",
    "content": "use crate::generic_values::{Values, runner_results::Fallibility};\n\npub enum Reduce<V: Values> {\n    Done {\n        acc: Option<V::Item>,\n    },\n    StoppedByWhileCondition {\n        acc: Option<V::Item>,\n    },\n    StoppedByError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n\nimpl<V: Values> Reduce<V> {\n    pub fn into_result(self) -> Result<Option<V::Item>, <V::Fallibility as Fallibility>::Error> {\n        match self {\n            Reduce::Done { acc } => Ok(acc),\n            Reduce::StoppedByWhileCondition { acc } => Ok(acc),\n            Reduce::StoppedByError { error } => Err(error),\n        }\n    }\n}\n\nimpl<V: Values> core::fmt::Debug for Reduce<V> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::Done { acc: _ } => f.debug_struct(\"Done\").finish(),\n            Self::StoppedByWhileCondition { acc: _ } => {\n                f.debug_struct(\"StoppedByWhileCondition\").finish()\n            }\n            Self::StoppedByError { error: _ } => f.debug_struct(\"StoppedByError\").finish(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/runner_results/stop.rs",
    "content": "use crate::generic_values::{Values, runner_results::Fallibility};\n\npub enum Stop<E> {\n    DueToWhile,\n    DueToError { error: E },\n}\n\npub enum StopWithIdx<E> {\n    DueToWhile { idx: usize },\n    DueToError { idx: usize, error: E },\n}\n\npub enum StopReduce<V: Values> {\n    DueToWhile {\n        acc: Option<V::Item>,\n    },\n    DueToError {\n        error: <V::Fallibility as Fallibility>::Error,\n    },\n}\n"
  },
  {
    "path": "src/generic_values/transformable_values.rs",
    "content": "use crate::generic_values::{Values, runner_results::Fallible};\n\npub trait TransformableValues: Values {\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O + Clone;\n\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool + Clone;\n\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo + Clone;\n\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>;\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>;\n\n    fn map_while_ok<Mr, O, E>(\n        self,\n        map_res: Mr,\n    ) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send;\n\n    fn u_map<U, M, O>(\n        self,\n        u: *mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(*mut U, Self::Item) -> O;\n\n    fn u_filter<U, F>(\n        self,\n        u: *mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(*mut U, &Self::Item) -> bool;\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: *mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(*mut U, Self::Item) -> Vo;\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: *mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(*mut U, Self::Item) -> Option<O>;\n}\n"
  },
  {
    "path": "src/generic_values/values.rs",
    "content": "use crate::generic_values::runner_results::{\n    ArbitraryPush, Fallibility, Next, OrderedPush, Reduce, SequentialPush, Stop, StopReduce,\n    StopWithIdx,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\nuse orx_pinned_vec::PinnedVec;\n\npub trait Values: Sized {\n    type Item;\n\n    type Fallibility: Fallibility;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>;\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility>;\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send;\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item;\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item;\n\n    fn next(self) -> Next<Self>;\n\n    // provided\n\n    #[inline(always)]\n    fn ordered_push_to_stop(\n        ordered_push: OrderedPush<Self::Fallibility>,\n    ) -> Option<StopWithIdx<<Self::Fallibility as Fallibility>::Error>> {\n        <Self::Fallibility as Fallibility>::ordered_push_to_stop(ordered_push)\n    }\n\n    #[inline(always)]\n    fn arbitrary_push_to_stop(\n        arbitrary_push: ArbitraryPush<Self::Fallibility>,\n    ) -> Option<Stop<<Self::Fallibility as Fallibility>::Error>> {\n        <Self::Fallibility as Fallibility>::arbitrary_push_to_stop(arbitrary_push)\n    }\n\n    #[inline(always)]\n    fn sequential_push_to_stop(\n        sequential_push: SequentialPush<Self::Fallibility>,\n    ) -> Option<Stop<<Self::Fallibility as Fallibility>::Error>> {\n        <Self::Fallibility as Fallibility>::sequential_push_to_stop(sequential_push)\n    }\n\n    #[inline(always)]\n    fn reduce_to_stop(reduce: Reduce<Self>) -> Result<Option<Self::Item>, StopReduce<Self>> {\n        <Self::Fallibility as Fallibility>::reduce_to_stop(reduce)\n    }\n}\n"
  },
  {
    "path": "src/generic_values/vector.rs",
    "content": "use super::transformable_values::TransformableValues;\nuse crate::generic_values::{\n    Values, VectorResult, WhilstAtom, WhilstVector,\n    runner_results::{\n        ArbitraryPush, Fallible, Infallible, Next, OrderedPush, Reduce, SequentialPush,\n    },\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\nuse orx_pinned_vec::PinnedVec;\n\npub struct Vector<I>(pub I)\nwhere\n    I: IntoIterator;\n\nimpl<I> Values for Vector<I>\nwhere\n    I: IntoIterator,\n{\n    type Item = I::Item;\n\n    type Fallibility = Infallible;\n\n    #[inline(always)]\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        for x in self.0 {\n            vector.push(x);\n        }\n        SequentialPush::Done\n    }\n\n    #[inline(always)]\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        for x in self.0 {\n            vec.push((idx, x));\n        }\n        OrderedPush::Done\n    }\n\n    #[inline(always)]\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        for x in self.0 {\n            bag.push(x);\n        }\n        ArbitraryPush::Done\n    }\n\n    #[inline(always)]\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        let reduced = self.0.into_iter().reduce(&reduce);\n\n        Reduce::Done {\n            acc: match (acc, reduced) {\n                (Some(x), Some(y)) => Some(reduce(x, y)),\n                (Some(x), None) => Some(x),\n                (None, Some(y)) => Some(y),\n                (None, None) => None,\n            },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        let reduced = self.0.into_iter().reduce(|a, b| reduce(u, a, b));\n\n        Reduce::Done {\n            acc: match (acc, reduced) {\n                (Some(x), Some(y)) => Some(reduce(u, x, y)),\n                (Some(x), None) => Some(x),\n                (None, Some(y)) => Some(y),\n                (None, None) => None,\n            },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        Next::Done {\n            value: self.0.into_iter().next(),\n        }\n    }\n}\n\nimpl<I> TransformableValues for Vector<I>\nwhere\n    I: IntoIterator,\n{\n    #[inline(always)]\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O,\n    {\n        Vector(self.0.into_iter().map(map))\n    }\n\n    #[inline(always)]\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool,\n    {\n        Vector(self.0.into_iter().filter(filter))\n    }\n\n    #[inline(always)]\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo,\n    {\n        Vector(self.0.into_iter().flat_map(flat_map))\n    }\n\n    #[inline(always)]\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>,\n    {\n        Vector(self.0.into_iter().filter_map(filter_map))\n    }\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        Self: Sized,\n    {\n        let iter = self.0.into_iter().map(move |x| match whilst(&x) {\n            true => WhilstAtom::Continue(x),\n            false => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn map_while_ok<Mr, O, E>(self, map_res: Mr) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send,\n    {\n        let iter_res = self.0.into_iter().map(map_res);\n        VectorResult(iter_res)\n    }\n\n    fn u_map<U, M, O>(\n        self,\n        u: *mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(*mut U, Self::Item) -> O,\n    {\n        Vector(self.0.into_iter().map(move |x| map(u, x)))\n    }\n\n    fn u_filter<U, F>(\n        self,\n        u: *mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(*mut U, &Self::Item) -> bool,\n    {\n        Vector(self.0.into_iter().filter(move |x| filter(u, x)))\n    }\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: *mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(*mut U, Self::Item) -> Vo,\n    {\n        Vector(self.0.into_iter().flat_map(move |x| flat_map(u, x)))\n    }\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: *mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(*mut U, Self::Item) -> Option<O>,\n    {\n        Vector(self.0.into_iter().filter_map(move |x| filter_map(u, x)))\n    }\n}\n"
  },
  {
    "path": "src/generic_values/vector_result.rs",
    "content": "use crate::generic_values::Values;\nuse crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\nuse orx_pinned_vec::PinnedVec;\n\npub struct VectorResult<I, T, E>(pub(crate) I)\nwhere\n    I: IntoIterator<Item = Result<T, E>>,\n    E: Send;\n\nimpl<I, T, E> Values for VectorResult<I, T, E>\nwhere\n    I: IntoIterator<Item = Result<T, E>>,\n    E: Send,\n{\n    type Item = T;\n\n    type Fallibility = Fallible<E>;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        for x in self.0 {\n            match x {\n                Ok(x) => vector.push(x),\n                Err(error) => return SequentialPush::StoppedByError { error },\n            }\n        }\n        SequentialPush::Done\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        for x in self.0 {\n            match x {\n                Ok(x) => vec.push((idx, x)),\n                Err(error) => return OrderedPush::StoppedByError { idx, error },\n            }\n        }\n        OrderedPush::Done\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        for x in self.0 {\n            match x {\n                Ok(x) => _ = bag.push(x),\n                Err(error) => return ArbitraryPush::StoppedByError { error },\n            }\n        }\n        ArbitraryPush::Done\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(x) => match x {\n                        Ok(x) => x,\n                        Err(error) => return Reduce::StoppedByError { error }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                Ok(x) => acc = reduce(acc, x),\n                Err(error) => return Reduce::StoppedByError { error },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(x) => match x {\n                        Ok(x) => x,\n                        Err(error) => return Reduce::StoppedByError { error }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                Ok(x) => acc = reduce(u, acc, x),\n                Err(error) => return Reduce::StoppedByError { error },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self.0.into_iter().next() {\n            Some(x) => match x {\n                Ok(x) => Next::Done { value: Some(x) },\n                Err(error) => Next::StoppedByError { error },\n            },\n            None => Next::Done { value: None },\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_atom.rs",
    "content": "use crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Infallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse crate::generic_values::whilst_atom_result::WhilstAtomResult;\nuse crate::generic_values::whilst_iterators::WhilstAtomFlatMapIter;\nuse crate::generic_values::{TransformableValues, Values, WhilstOption, WhilstVector};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\npub enum WhilstAtom<T> {\n    Continue(T),\n    Stop,\n}\n\nimpl<T> WhilstAtom<T> {\n    #[inline(always)]\n    pub fn new(value: T, whilst: impl Fn(&T) -> bool) -> Self {\n        match whilst(&value) {\n            true => Self::Continue(value),\n            false => Self::Stop,\n        }\n    }\n}\n\nimpl<T> Values for WhilstAtom<T> {\n    type Item = T;\n\n    type Fallibility = Infallible;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        match self {\n            Self::Continue(x) => {\n                vector.push(x);\n                SequentialPush::Done\n            }\n            Self::Stop => SequentialPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        match self {\n            Self::Continue(x) => {\n                vec.push((idx, x));\n                OrderedPush::Done\n            }\n            Self::Stop => OrderedPush::StoppedByWhileCondition { idx },\n        }\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        match self {\n            Self::Continue(x) => {\n                bag.push(x);\n                ArbitraryPush::Done\n            }\n            Self::Stop => ArbitraryPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::Continue(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(acc, x),\n                    None => x,\n                }),\n            },\n            Self::Stop => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::Continue(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(u, acc, x),\n                    None => x,\n                }),\n            },\n            Self::Stop => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self {\n            Self::Continue(x) => Next::Done { value: Some(x) },\n            Self::Stop => Next::StoppedByWhileCondition,\n        }\n    }\n}\n\nimpl<T> TransformableValues for WhilstAtom<T> {\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O + Clone,\n    {\n        match self {\n            Self::Continue(x) => WhilstAtom::Continue(map(x)),\n            Self::Stop => WhilstAtom::Stop,\n        }\n    }\n\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool + Clone,\n    {\n        match self {\n            Self::Continue(x) => match filter(&x) {\n                true => WhilstOption::ContinueSome(x),\n                false => WhilstOption::ContinueNone,\n            },\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo + Clone,\n    {\n        let iter = WhilstAtomFlatMapIter::from_atom(self, &flat_map);\n        WhilstVector(iter)\n    }\n\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>,\n    {\n        match self {\n            Self::Continue(x) => match filter_map(x) {\n                Some(x) => WhilstOption::ContinueSome(x),\n                None => WhilstOption::ContinueNone,\n            },\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        Self: Sized,\n    {\n        match self {\n            Self::Continue(x) => match whilst(&x) {\n                true => Self::Continue(x),\n                false => Self::Stop,\n            },\n            Self::Stop => Self::Stop,\n        }\n    }\n\n    fn map_while_ok<Mr, O, E>(self, map_res: Mr) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send,\n    {\n        match self {\n            Self::Continue(x) => match map_res(x) {\n                Ok(x) => WhilstAtomResult::ContinueOk(x),\n                Err(e) => WhilstAtomResult::StopErr(e),\n            },\n            Self::Stop => WhilstAtomResult::StopWhile,\n        }\n    }\n\n    fn u_map<U, M, O>(\n        self,\n        u: *mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(*mut U, Self::Item) -> O,\n    {\n        match self {\n            Self::Continue(x) => WhilstAtom::Continue(map(u, x)),\n            Self::Stop => WhilstAtom::Stop,\n        }\n    }\n\n    fn u_filter<U, F>(\n        self,\n        u: *mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(*mut U, &Self::Item) -> bool,\n    {\n        match self {\n            Self::Continue(x) => match filter(u, &x) {\n                true => WhilstOption::ContinueSome(x),\n                false => WhilstOption::ContinueNone,\n            },\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: *mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(*mut U, Self::Item) -> Vo,\n    {\n        let iter = WhilstAtomFlatMapIter::u_from_atom(u, self, &flat_map);\n        WhilstVector(iter)\n    }\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: *mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(*mut U, Self::Item) -> Option<O>,\n    {\n        match self {\n            Self::Continue(x) => match filter_map(u, x) {\n                Some(x) => WhilstOption::ContinueSome(x),\n                None => WhilstOption::ContinueNone,\n            },\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_atom_result.rs",
    "content": "use crate::generic_values::Values;\nuse crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\npub enum WhilstAtomResult<T, E>\nwhere\n    E: Send,\n{\n    ContinueOk(T),\n    StopErr(E),\n    StopWhile,\n}\n\nimpl<T, E> Values for WhilstAtomResult<T, E>\nwhere\n    E: Send,\n{\n    type Item = T;\n\n    type Fallibility = Fallible<E>;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        match self {\n            Self::ContinueOk(x) => {\n                vector.push(x);\n                SequentialPush::Done\n            }\n            Self::StopErr(error) => SequentialPush::StoppedByError { error },\n            Self::StopWhile => SequentialPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        match self {\n            Self::ContinueOk(x) => {\n                vec.push((idx, x));\n                OrderedPush::Done\n            }\n            Self::StopErr(error) => OrderedPush::StoppedByError { idx, error },\n            Self::StopWhile => OrderedPush::StoppedByWhileCondition { idx },\n        }\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        match self {\n            Self::ContinueOk(x) => {\n                bag.push(x);\n                ArbitraryPush::Done\n            }\n            Self::StopErr(error) => ArbitraryPush::StoppedByError { error },\n            Self::StopWhile => ArbitraryPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::ContinueOk(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(acc, x),\n                    None => x,\n                }),\n            },\n            Self::StopErr(error) => Reduce::StoppedByError { error },\n            Self::StopWhile => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::ContinueOk(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(u, acc, x),\n                    None => x,\n                }),\n            },\n            Self::StopErr(error) => Reduce::StoppedByError { error },\n            Self::StopWhile => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self {\n            Self::ContinueOk(x) => Next::Done { value: Some(x) },\n            Self::StopErr(error) => Next::StoppedByError { error },\n            Self::StopWhile => Next::StoppedByWhileCondition,\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_iterators/mod.rs",
    "content": "mod whilst_atom_flat_map;\nmod whilst_option_flat_map;\n\npub use whilst_atom_flat_map::WhilstAtomFlatMapIter;\npub use whilst_option_flat_map::WhilstOptionFlatMapIter;\n"
  },
  {
    "path": "src/generic_values/whilst_iterators/whilst_atom_flat_map.rs",
    "content": "use crate::generic_values::whilst_atom::WhilstAtom;\n\npub struct WhilstAtomFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    current_iter: WhilstAtom<Vo::IntoIter>,\n}\n\nimpl<Vo> WhilstAtomFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    pub fn from_atom<T, Fm>(atom: WhilstAtom<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(flat_map(x).into_iter()),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        };\n        Self { current_iter }\n    }\n\n    pub fn u_from_atom<U, T, Fm>(u: *mut U, atom: WhilstAtom<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(*mut U, T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(flat_map(u, x).into_iter()),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        };\n        Self { current_iter }\n    }\n}\n\nimpl<Vo> Iterator for WhilstAtomFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    type Item = WhilstAtom<Vo::Item>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match &mut self.current_iter {\n            WhilstAtom::Continue(x) => x.next().map(WhilstAtom::Continue), // None if flat-map iterator is consumed\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),                    // input is Stop\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_iterators/whilst_option_flat_map.rs",
    "content": "use crate::generic_values::{WhilstAtom, WhilstOption};\n\npub struct WhilstOptionFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    current_iter: WhilstOption<Vo::IntoIter>,\n}\n\nimpl<Vo> WhilstOptionFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    pub fn from_option<T, Fm>(atom: WhilstOption<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstOption::ContinueSome(x) => WhilstOption::ContinueSome(flat_map(x).into_iter()),\n            WhilstOption::ContinueNone => WhilstOption::ContinueNone,\n            WhilstOption::Stop => WhilstOption::Stop,\n        };\n        Self { current_iter }\n    }\n\n    pub fn u_from_option<U, T, Fm>(u: *mut U, atom: WhilstOption<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(*mut U, T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstOption::ContinueSome(x) => WhilstOption::ContinueSome(flat_map(u, x).into_iter()),\n            WhilstOption::ContinueNone => WhilstOption::ContinueNone,\n            WhilstOption::Stop => WhilstOption::Stop,\n        };\n        Self { current_iter }\n    }\n}\n\nimpl<Vo> Iterator for WhilstOptionFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    type Item = WhilstAtom<Vo::Item>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match &mut self.current_iter {\n            WhilstOption::ContinueSome(x) => x.next().map(WhilstAtom::Continue), // None if flat-map iterator is consumed\n            WhilstOption::ContinueNone => None, // flat-map is created on None => empty iterator\n            WhilstOption::Stop => Some(WhilstAtom::Stop), // input is Stop\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_option.rs",
    "content": "use crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Infallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse crate::generic_values::whilst_iterators::WhilstOptionFlatMapIter;\nuse crate::generic_values::whilst_option_result::WhilstOptionResult;\nuse crate::generic_values::{TransformableValues, Values, WhilstVector};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\npub enum WhilstOption<T> {\n    ContinueSome(T),\n    ContinueNone,\n    Stop,\n}\n\nimpl<T> Values for WhilstOption<T> {\n    type Item = T;\n\n    type Fallibility = Infallible;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        match self {\n            Self::ContinueSome(x) => {\n                vector.push(x);\n                SequentialPush::Done\n            }\n            Self::ContinueNone => SequentialPush::Done,\n            Self::Stop => SequentialPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        match self {\n            Self::ContinueSome(x) => {\n                vec.push((idx, x));\n                OrderedPush::Done\n            }\n            Self::ContinueNone => OrderedPush::Done,\n            Self::Stop => OrderedPush::StoppedByWhileCondition { idx },\n        }\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        match self {\n            Self::ContinueSome(x) => {\n                bag.push(x);\n                ArbitraryPush::Done\n            }\n            Self::ContinueNone => ArbitraryPush::Done,\n            Self::Stop => ArbitraryPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::ContinueSome(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(acc, x),\n                    None => x,\n                }),\n            },\n            Self::ContinueNone => Reduce::Done { acc },\n            Self::Stop => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::ContinueSome(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(u, acc, x),\n                    None => x,\n                }),\n            },\n            Self::ContinueNone => Reduce::Done { acc },\n            Self::Stop => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self {\n            Self::ContinueSome(x) => Next::Done { value: Some(x) },\n            Self::ContinueNone => Next::Done { value: None },\n            Self::Stop => Next::StoppedByWhileCondition,\n        }\n    }\n}\n\nimpl<T> TransformableValues for WhilstOption<T> {\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O + Clone,\n    {\n        match self {\n            Self::ContinueSome(x) => WhilstOption::ContinueSome(map(x)),\n            Self::ContinueNone => WhilstOption::ContinueNone,\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool + Clone,\n    {\n        match self {\n            Self::ContinueSome(x) => match filter(&x) {\n                true => Self::ContinueSome(x),\n                false => Self::ContinueNone,\n            },\n            Self::ContinueNone => Self::ContinueNone,\n            Self::Stop => Self::Stop,\n        }\n    }\n\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo + Clone,\n    {\n        let iter = WhilstOptionFlatMapIter::from_option(self, &flat_map);\n        WhilstVector(iter)\n    }\n\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>,\n    {\n        match self {\n            Self::ContinueSome(x) => match filter_map(x) {\n                Some(x) => WhilstOption::ContinueSome(x),\n                None => WhilstOption::ContinueNone,\n            },\n            Self::ContinueNone => WhilstOption::ContinueNone,\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        Self: Sized,\n    {\n        match self {\n            Self::ContinueSome(x) => match whilst(&x) {\n                true => Self::ContinueSome(x),\n                false => Self::Stop,\n            },\n            Self::ContinueNone => Self::ContinueNone,\n            Self::Stop => Self::Stop,\n        }\n    }\n\n    fn map_while_ok<Mr, O, E>(self, map_res: Mr) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send,\n    {\n        match self {\n            Self::ContinueSome(x) => match map_res(x) {\n                Ok(x) => WhilstOptionResult::ContinueSomeOk(x),\n                Err(e) => WhilstOptionResult::StopErr(e),\n            },\n            Self::ContinueNone => WhilstOptionResult::ContinueNone,\n            Self::Stop => WhilstOptionResult::StopWhile,\n        }\n    }\n\n    fn u_map<U, M, O>(\n        self,\n        u: *mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(*mut U, Self::Item) -> O,\n    {\n        match self {\n            Self::ContinueSome(x) => WhilstOption::ContinueSome(map(u, x)),\n            Self::ContinueNone => WhilstOption::ContinueNone,\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n\n    fn u_filter<U, F>(\n        self,\n        u: *mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(*mut U, &Self::Item) -> bool,\n    {\n        match self {\n            Self::ContinueSome(x) => match filter(u, &x) {\n                true => Self::ContinueSome(x),\n                false => Self::ContinueNone,\n            },\n            Self::ContinueNone => Self::ContinueNone,\n            Self::Stop => Self::Stop,\n        }\n    }\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: *mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(*mut U, Self::Item) -> Vo,\n    {\n        let iter = WhilstOptionFlatMapIter::u_from_option(u, self, &flat_map);\n        WhilstVector(iter)\n    }\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: *mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(*mut U, Self::Item) -> Option<O>,\n    {\n        match self {\n            Self::ContinueSome(x) => match filter_map(u, x) {\n                Some(x) => WhilstOption::ContinueSome(x),\n                None => WhilstOption::ContinueNone,\n            },\n            Self::ContinueNone => WhilstOption::ContinueNone,\n            Self::Stop => WhilstOption::Stop,\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_option_result.rs",
    "content": "use crate::generic_values::Values;\nuse crate::generic_values::runner_results::{\n    ArbitraryPush, Fallible, Next, OrderedPush, Reduce, SequentialPush,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_pinned_vec::{IntoConcurrentPinnedVec, PinnedVec};\n\npub enum WhilstOptionResult<T, E>\nwhere\n    E: Send,\n{\n    ContinueSomeOk(T),\n    ContinueNone,\n    StopErr(E),\n    StopWhile,\n}\n\nimpl<T, E> Values for WhilstOptionResult<T, E>\nwhere\n    E: Send,\n{\n    type Item = T;\n\n    type Fallibility = Fallible<E>;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        match self {\n            Self::ContinueSomeOk(x) => {\n                vector.push(x);\n                SequentialPush::Done\n            }\n            Self::ContinueNone => SequentialPush::Done,\n            Self::StopErr(error) => SequentialPush::StoppedByError { error },\n            Self::StopWhile => SequentialPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        match self {\n            Self::ContinueSomeOk(x) => {\n                vec.push((idx, x));\n                OrderedPush::Done\n            }\n            Self::ContinueNone => OrderedPush::Done,\n            Self::StopErr(error) => OrderedPush::StoppedByError { idx, error },\n            Self::StopWhile => OrderedPush::StoppedByWhileCondition { idx },\n        }\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        match self {\n            Self::ContinueSomeOk(x) => {\n                bag.push(x);\n                ArbitraryPush::Done\n            }\n            Self::ContinueNone => ArbitraryPush::Done,\n            Self::StopErr(error) => ArbitraryPush::StoppedByError { error },\n            Self::StopWhile => ArbitraryPush::StoppedByWhileCondition,\n        }\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::ContinueSomeOk(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(acc, x),\n                    None => x,\n                }),\n            },\n            Self::ContinueNone => Reduce::Done { acc },\n            Self::StopErr(error) => Reduce::StoppedByError { error },\n            Self::StopWhile => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        match self {\n            Self::ContinueSomeOk(x) => Reduce::Done {\n                acc: Some(match acc {\n                    Some(acc) => reduce(u, acc, x),\n                    None => x,\n                }),\n            },\n            Self::ContinueNone => Reduce::Done { acc },\n            Self::StopErr(error) => Reduce::StoppedByError { error },\n            Self::StopWhile => Reduce::StoppedByWhileCondition { acc },\n        }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self {\n            Self::ContinueSomeOk(x) => Next::Done { value: Some(x) },\n            Self::ContinueNone => Next::Done { value: None },\n            Self::StopErr(error) => Next::StoppedByError { error },\n            Self::StopWhile => Next::StoppedByWhileCondition,\n        }\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_vector.rs",
    "content": "use super::transformable_values::TransformableValues;\nuse crate::generic_values::{\n    Values, WhilstAtom,\n    runner_results::{\n        ArbitraryPush, Fallible, Infallible, Next, OrderedPush, Reduce, SequentialPush,\n    },\n    whilst_iterators::WhilstAtomFlatMapIter,\n    whilst_vector_result::WhilstVectorResult,\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\nuse orx_pinned_vec::PinnedVec;\n\npub struct WhilstVector<I, T>(pub(crate) I)\nwhere\n    I: IntoIterator<Item = WhilstAtom<T>>;\n\nimpl<I, T> Values for WhilstVector<I, T>\nwhere\n    I: IntoIterator<Item = WhilstAtom<T>>,\n{\n    type Item = T;\n\n    type Fallibility = Infallible;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(x) => vector.push(x),\n                WhilstAtom::Stop => return SequentialPush::StoppedByWhileCondition,\n            }\n        }\n        SequentialPush::Done\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(x) => vec.push((idx, x)),\n                WhilstAtom::Stop => return OrderedPush::StoppedByWhileCondition { idx },\n            }\n        }\n        OrderedPush::Done\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(x) => _ = bag.push(x),\n                WhilstAtom::Stop => return ArbitraryPush::StoppedByWhileCondition,\n            }\n        }\n        ArbitraryPush::Done\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(x) => match x {\n                        WhilstAtom::Continue(x) => x,\n                        WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: None }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                WhilstAtom::Continue(x) => acc = reduce(acc, x),\n                WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: Some(acc) },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(x) => match x {\n                        WhilstAtom::Continue(x) => x,\n                        WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: None }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                WhilstAtom::Continue(x) => acc = reduce(u, acc, x),\n                WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: Some(acc) },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self.0.into_iter().next() {\n            Some(x) => match x {\n                WhilstAtom::Continue(x) => Next::Done { value: Some(x) },\n                WhilstAtom::Stop => Next::StoppedByWhileCondition,\n            },\n            None => Next::Done { value: None },\n        }\n    }\n}\n\nimpl<I, T> TransformableValues for WhilstVector<I, T>\nwhere\n    I: IntoIterator<Item = WhilstAtom<T>>,\n{\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(map(x)),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool + Clone,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => match filter(&x) {\n                true => Some(WhilstAtom::Continue(x)),\n                false => None,\n            },\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo,\n    {\n        let iter = self\n            .0\n            .into_iter()\n            .flat_map(move |atom| WhilstAtomFlatMapIter::from_atom(atom, &flat_map));\n        WhilstVector(iter)\n    }\n\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => filter_map(x).map(WhilstAtom::Continue),\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        Self: Sized,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => match whilst(&x) {\n                true => WhilstAtom::Continue(x),\n                false => WhilstAtom::Stop,\n            },\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn map_while_ok<Mr, O, E>(self, map_res: Mr) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(map_res(x)),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVectorResult(iter)\n    }\n\n    fn u_map<U, M, O>(\n        self,\n        u: *mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(*mut U, Self::Item) -> O,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(map(u, x)),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn u_filter<U, F>(\n        self,\n        u: *mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(*mut U, &Self::Item) -> bool,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => match filter(u, &x) {\n                true => Some(WhilstAtom::Continue(x)),\n                false => None,\n            },\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: *mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(*mut U, Self::Item) -> Vo,\n    {\n        let iter = self\n            .0\n            .into_iter()\n            .flat_map(move |atom| WhilstAtomFlatMapIter::u_from_atom(u, atom, &flat_map));\n        WhilstVector(iter)\n    }\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: *mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(*mut U, Self::Item) -> Option<O>,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => filter_map(u, x).map(WhilstAtom::Continue),\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n}\n"
  },
  {
    "path": "src/generic_values/whilst_vector_result.rs",
    "content": "use crate::generic_values::{\n    Values, WhilstAtom,\n    runner_results::{ArbitraryPush, Fallible, Next, OrderedPush, Reduce, SequentialPush},\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\nuse orx_pinned_vec::PinnedVec;\n\npub struct WhilstVectorResult<I, T, E>(pub(crate) I)\nwhere\n    I: IntoIterator<Item = WhilstAtom<Result<T, E>>>,\n    E: Send;\n\nimpl<I, T, E> Values for WhilstVectorResult<I, T, E>\nwhere\n    I: IntoIterator<Item = WhilstAtom<Result<T, E>>>,\n    E: Send,\n{\n    type Item = T;\n\n    type Fallibility = Fallible<E>;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(Ok(x)) => vector.push(x),\n                WhilstAtom::Continue(Err(error)) => {\n                    return SequentialPush::StoppedByError { error };\n                }\n                WhilstAtom::Stop => return SequentialPush::StoppedByWhileCondition,\n            }\n        }\n        SequentialPush::Done\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(Ok(x)) => vec.push((idx, x)),\n                WhilstAtom::Continue(Err(error)) => {\n                    return OrderedPush::StoppedByError { idx, error };\n                }\n                WhilstAtom::Stop => return OrderedPush::StoppedByWhileCondition { idx },\n            }\n        }\n        OrderedPush::Done\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(Ok(x)) => _ = bag.push(x),\n                WhilstAtom::Continue(Err(error)) => return ArbitraryPush::StoppedByError { error },\n                WhilstAtom::Stop => return ArbitraryPush::StoppedByWhileCondition,\n            }\n        }\n        ArbitraryPush::Done\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(first) => match first {\n                        WhilstAtom::Continue(Ok(x)) => x,\n                        WhilstAtom::Continue(Err(error)) => {\n                            return Reduce::StoppedByError { error };\n                        }\n                        WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: None }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                WhilstAtom::Continue(Ok(x)) => acc = reduce(acc, x),\n                WhilstAtom::Continue(Err(error)) => return Reduce::StoppedByError { error },\n                WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: Some(acc) },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: *mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(*mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(first) => match first {\n                        WhilstAtom::Continue(Ok(x)) => x,\n                        WhilstAtom::Continue(Err(error)) => {\n                            return Reduce::StoppedByError { error };\n                        }\n                        WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: None }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                WhilstAtom::Continue(Ok(x)) => acc = reduce(u, acc, x),\n                WhilstAtom::Continue(Err(error)) => return Reduce::StoppedByError { error },\n                WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: Some(acc) },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self.0.into_iter().next() {\n            Some(x) => match x {\n                WhilstAtom::Continue(Ok(x)) => Next::Done { value: Some(x) },\n                WhilstAtom::Continue(Err(error)) => Next::StoppedByError { error },\n                WhilstAtom::Stop => Next::StoppedByWhileCondition,\n            },\n            None => Next::Done { value: None },\n        }\n    }\n}\n"
  },
  {
    "path": "src/heap_sort.rs",
    "content": "use alloc::vec;\nuse alloc::vec::Vec;\nuse orx_pinned_vec::PinnedVec;\nuse orx_priority_queue::{BinaryHeap, PriorityQueue};\n\npub fn heap_sort_into<T, P>(\n    mut vectors: Vec<Vec<(usize, T)>>,\n    max_idx_inc: Option<usize>,\n    output: &mut P,\n) where\n    P: PinnedVec<T>,\n{\n    let mut queue = BinaryHeap::with_capacity(vectors.len());\n    let mut indices = vec![0; vectors.len()];\n\n    let max_idx_or_inf = max_idx_inc.unwrap_or(usize::MAX);\n    for (v, vec) in vectors.iter().enumerate() {\n        if let Some(x) = vec.get(indices[v])\n            && x.0 <= max_idx_or_inf\n        {\n            queue.push(v, x.0);\n        }\n    }\n    let mut curr_v = queue.pop_node();\n\n    match max_idx_inc {\n        None => {\n            while let Some(v) = curr_v {\n                let idx = indices[v];\n                indices[v] += 1;\n\n                curr_v = match vectors[v].get(indices[v]) {\n                    Some(x) => Some(queue.push_then_pop(v, x.0).0),\n                    None => queue.pop_node(),\n                };\n\n                let ptr = vectors[v].as_ptr();\n                output.push(unsafe { ptr.add(idx).read().1 });\n            }\n        }\n        Some(max_idx) => {\n            while let Some(v) = curr_v {\n                let idx = indices[v];\n                indices[v] += 1;\n\n                curr_v = match vectors[v].get(indices[v]) {\n                    Some(x) if x.0 <= max_idx => Some(queue.push_then_pop(v, x.0).0),\n                    _ => queue.pop_node(),\n                };\n\n                let ptr = vectors[v].as_ptr();\n                output.push(unsafe { ptr.add(idx).read().1 });\n            }\n        }\n    }\n\n    for vec in vectors.iter_mut() {\n        // SAFETY: this prevents to drop the elements which are already moved to pinned_vec\n        // allocation within vec.capacity() will still be reclaimed; however, as uninitialized memory\n        unsafe { vec.set_len(0) };\n    }\n}\n"
  },
  {
    "path": "src/into_par_iter.rs",
    "content": "use crate::{Params, computational_variants::Par, runner::DefaultRunner};\nuse orx_concurrent_iter::{ConcurrentIter, IntoConcurrentIter};\n\n/// Trait to convert a source (collection or generator) into a parallel iterator; i.e., [`ParIter`],\n/// using its [`into_par`] method.\n///\n/// It can be considered as the *concurrent counterpart* of the [`IntoIterator`] trait.\n///\n/// Note that every [`IntoConcurrentIter`] type automatically implements [`IntoParIter`].\n///\n/// [`into_par`]: crate::IntoParIter::into_par\n/// [`IntoConcurrentIter`]: orx_concurrent_iter::IntoConcurrentIter\n/// [`ParIter`]: crate::ParIter\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// // Vec<T>: IntoParIter<Item = T>\n/// let vec = vec![1, 2, 3, 4];\n/// assert_eq!(vec.into_par().max(), Some(4));\n///\n/// // Range<T>: IntoParIter<Item = T>\n/// let range = 1..5;\n/// assert_eq!(range.into_par().max(), Some(4));\n/// ```\npub trait IntoParIter: IntoConcurrentIter {\n    /// Trait to convert a source (collection or generator) into a parallel iterator; i.e., [`ParIter`],\n    /// using its [`into_par`] method.\n    ///\n    /// It can be considered as the *concurrent counterpart* of the [`IntoIterator`] trait.\n    ///\n    /// [`into_par`]: crate::IntoParIter::into_par\n    /// [`ParIter`]: crate::ParIter\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // Vec<T>: IntoParIter<Item = T>\n    /// let vec = vec![1, 2, 3, 4];\n    /// assert_eq!(vec.into_par().max(), Some(4));\n    ///\n    /// // Range<T>: IntoParIter<Item = T>\n    /// let range = 1..5;\n    /// assert_eq!(range.into_par().max(), Some(4));\n    /// ```\n    fn into_par(self) -> Par<Self::IntoIter, DefaultRunner>;\n}\n\nimpl<I> IntoParIter for I\nwhere\n    I: IntoConcurrentIter,\n{\n    fn into_par(self) -> Par<Self::IntoIter, DefaultRunner> {\n        Par::new(Default::default(), Params::default(), self.into_con_iter())\n    }\n}\n\nimpl<I: ConcurrentIter> IntoConcurrentIter for Par<I, DefaultRunner> {\n    type Item = I::Item;\n\n    type IntoIter = I;\n\n    fn into_con_iter(self) -> Self::IntoIter {\n        let (_, _, iter) = self.destruct();\n        iter\n    }\n}\n"
  },
  {
    "path": "src/iter/mod.rs",
    "content": "mod recursive;\nmod special_iterators;\n\npub use recursive::IntoParIterRec;\npub use special_iterators::{ParEmpty, empty};\n"
  },
  {
    "path": "src/iter/recursive/into_par_rec_iter.rs",
    "content": "use crate::{DefaultRunner, Params, computational_variants::Par};\nuse orx_concurrent_recursive_iter::{ConcurrentRecursiveIter, Queue};\n\n// unknown size\n\n/// Trait to convert an iterator into a recursive parallel iterator together with the `extend` method.\n/// Recursive iterators are most useful for defining parallel computations over non-linear data structures\n/// such as trees or graphs.\n///\n/// Created parallel iterator is a regular parallel iterator; i.e., we have access to all [`ParIter`] features.\n///\n/// It is recursive due to the extension. The recursive parallel iterator will yield\n/// * all initial elements contained in this iterator,\n/// * all elements dynamically added to the queue with the `extend` method while processing the elements.\n///\n/// You may read more about the [`ConcurrentRecursiveIter`].\n///\n/// [`ParIter`]: crate::ParIter\npub trait IntoParIterRec\nwhere\n    Self: IntoIterator,\n    Self::Item: Send,\n{\n    /// Converts this iterator into a recursive parallel iterator together with the `extend` method.\n    /// Recursive iterators are most useful for defining parallel computations over non-linear data structures\n    /// such as trees or graphs.\n    ///\n    /// Created parallel iterator is a regular parallel iterator; i.e., we have access to all [`ParIter`] features.\n    ///\n    /// It is recursive due to the extension. The recursive parallel iterator will yield\n    /// * all initial elements contained in this iterator,\n    /// * all elements dynamically added to the queue with the `extend` method while processing the elements.\n    ///\n    /// You may read more about the [`ConcurrentRecursiveIter`].\n    ///\n    /// The `extend` function defines the recursive expansion behavior. It takes two arguments:\n    /// * `element: &Self::Item` is the item being processed.\n    /// * `queue: Queue<Self::Item, P>` is the queue of remaining elements/tasks which exposes two methods:\n    ///   * `push(item)` allows us to add one item to the queue,\n    ///   * `extend(items)` allows us to add all of the items to the queue. Here `items` must have a known\n    ///     size (`ExactSizeIterator`).\n    ///\n    /// Adding children one-by-one with `push` or all together with `extend` might be the extreme options.\n    /// Actually, any intermediate approach is also possible. For instance, we can choose to `extend` in\n    /// chunks of say 50 tasks. If the item happens to create 140 children, we can handle this with four\n    /// `extend` calls.\n    ///\n    /// Using either of the methods might be beneficial for different use cases.\n    ///\n    /// Pushing children one by one makes the new task available for other threads as fast as possible. Further,\n    /// when we don't know the exact number of children ahead of time, and we don't want to use heap allocation\n    /// to store the children in a vec before adding them to the queue just to make it sized, we can add the\n    /// elements one-by-one with the `queue.push(item)` method. On the other hand, this approach will have more\n    /// parallelization overhead.\n    ///\n    /// When we extending children all at once using `queue.extend(items)`, we minimize the parallelization overhead\n    /// for adding tasks to the queue. On the other hand, the children will be available only when writing of all\n    /// children to the queue is complete which might cause idleness when tasks are scarce. Still, the recommendation\n    /// is to try to `extend` first whenever possible due to the following: (i) if we extend with a lot of children,\n    /// the tasks will not be scarce; (ii) and if we extend with only a few of items, the delay of making the tasks\n    /// available for other threads will be short.\n    ///\n    /// The decision is use-case specific and best to benchmark for the specific input.\n    ///\n    /// This crate makes use of the [`ConcurrentRecursiveIter`] for this computation and provides three ways to execute\n    /// this computation in parallel.\n    ///\n    /// ## A. Recursive Iterator with Exact Length\n    ///\n    /// If we know, or if it is possible and sufficiently cheap to find out, the exact length of the iterator,\n    /// it is recommended to work with exact length recursive iterator. Note that the exact length of an\n    /// iterator is the total of all elements that will be created. This gives the parallel executor\n    /// opportunity to optimize the chunk sizes.\n    ///\n    /// We can use `initial_elements.into_par_rec_exact(extend, count)` to create the iterator with exact length.\n    ///\n    /// ## B. Recursive Iterator with Unknown Length\n    ///\n    /// If we cannot know or it is expensive to know the exact length of the iterator ahead of time, we can\n    /// still create a recursive parallel iterator. In these cases; however, it is recommended to provide\n    /// chunk size explicitly depending on the number of threads that will be used and any estimate on the exact\n    /// length.\n    ///\n    /// We can use `initial_elements.into_par_rec(extend)` to create the iterator without length information.\n    ///\n    /// ## C. Linearization\n    ///\n    /// Even with exact length, a recursive parallel iterator is much more dynamic than a flat parallel\n    /// iterator. This dynamic nature of shrinking and growing concurrently requires a greater parallelization\n    /// overhead. An alternative approach is to eagerly discover all tasks and then perform the parallel\n    /// computation over the flattened input of tasks using [`linearize`] transformation.\n    ///\n    /// We can use `initial_elements.into_par_rec(extend).linearize()` to create the flattened iterator.\n    ///\n    /// [`ParIter`]: crate::ParIter\n    /// [`ConcurrentRecursiveIter`]: orx_concurrent_recursive_iter::ConcurrentRecursiveIter\n    /// [`linearize`]: crate::computational_variants::Par::linearize\n    ///\n    /// ## Examples\n    ///\n    /// In the following example we perform some parallel computations over a tree.\n    /// It demonstrates that a \"recursive parallel iterator\" is just a parallel iterator with\n    /// access to all [`ParIter`] methods.\n    /// Once we create the recursive parallel iterator with the `extend` definition, we can use it as\n    /// a regular parallel iterator.\n    ///\n    /// Unfortunately, the example requires a long set up for completeness. Note that the relevant\n    /// code blocks begin after line `// parallel reduction`.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use rand::{Rng, SeedableRng};\n    /// use rand_chacha::ChaCha8Rng;\n    /// use std::{collections::HashSet, ops::Range};\n    ///\n    /// pub struct Node<T> {\n    ///     pub idx: usize,\n    ///     pub data: T,\n    ///     pub children: Vec<Node<T>>,\n    /// }\n    ///\n    /// impl<T> Node<T> {\n    ///     fn create_node(out_edges: &[Vec<usize>], idx: usize, data: fn(usize) -> T) -> Node<T> {\n    ///         Node {\n    ///             idx,\n    ///             data: data(idx),\n    ///             children: out_edges[idx]\n    ///                 .iter()\n    ///                 .map(|child_idx| Self::create_node(out_edges, *child_idx, data))\n    ///                 .collect(),\n    ///         }\n    ///     }\n    ///\n    ///     pub fn new_tree(\n    ///         num_nodes: usize,\n    ///         degree: Range<usize>,\n    ///         data: fn(usize) -> T,\n    ///         rng: &mut impl Rng,\n    ///     ) -> Node<T> {\n    ///         assert!(num_nodes >= 2);\n    ///\n    ///         let mut leaves = vec![0];\n    ///         let mut remaining: Vec<_> = (1..num_nodes).collect();\n    ///         let mut edges = vec![];\n    ///         let mut out_edges = vec![vec![]; num_nodes];\n    ///\n    ///         while !remaining.is_empty() {\n    ///             let leaf_idx = rng.random_range(0..leaves.len());\n    ///             let leaf = leaves.remove(leaf_idx);\n    ///\n    ///             let degree = rng.random_range(degree.clone());\n    ///             match degree == 0 {\n    ///                 true => leaves.push(leaf),\n    ///                 false => {\n    ///                     let children_indices: HashSet<_> = (0..degree)\n    ///                         .map(|_| rng.random_range(0..remaining.len()))\n    ///                         .collect();\n    ///\n    ///                     let mut sorted: Vec<_> = children_indices.iter().copied().collect();\n    ///                     sorted.sort();\n    ///\n    ///                     edges.extend(children_indices.iter().map(|c| (leaf, remaining[*c])));\n    ///                     out_edges[leaf] = children_indices.iter().map(|c| remaining[*c]).collect();\n    ///                     leaves.extend(children_indices.iter().map(|c| remaining[*c]));\n    ///\n    ///                     for idx in sorted.into_iter().rev() {\n    ///                         remaining.remove(idx);\n    ///                     }\n    ///                 }\n    ///             }\n    ///         }\n    ///\n    ///         Self::create_node(&out_edges, 0, data)\n    ///     }\n    /// }\n    ///\n    /// let num_nodes = 1_000;\n    /// let out_degree = 0..100;\n    /// let mut rng = ChaCha8Rng::seed_from_u64(42);\n    /// let data = |idx: usize| idx.to_string();\n    /// let root = Node::new_tree(num_nodes, out_degree, data, &mut rng);\n    ///\n    /// let compute = |node: &Node<String>| node.data.parse::<u64>().unwrap();\n    ///\n    /// // parallel reduction\n    ///\n    /// fn extend<'a, T: Sync>(node: &&'a Node<T>, queue: &Queue<&'a Node<T>>) {\n    ///     queue.extend(&node.children);\n    /// }\n    ///\n    /// let sum = [&root].into_par_rec(extend).map(compute).sum();\n    /// assert_eq!(sum, 499500);\n    ///\n    /// // or any parallel computation such as map->filter->collect\n    ///\n    /// let result: Vec<_> = [&root]\n    ///     .into_par_rec(extend)\n    ///     .map(compute)\n    ///     .filter(|x| x.is_multiple_of(7))\n    ///     .collect();\n    /// assert_eq!(result.len(), 143);\n    ///\n    /// // or filter during extension\n    /// fn extend_filtered<'a>(node: &&'a Node<String>, queue: &Queue<&'a Node<String>>) {\n    ///     for child in &node.children {\n    ///         if child.idx != 42 {\n    ///             queue.push(child);\n    ///         }\n    ///     }\n    /// }\n    ///\n    /// let sum = [&root].into_par_rec(extend_filtered).map(compute).sum();\n    /// ```\n    fn into_par_rec<E>(\n        self,\n        extend: E,\n    ) -> Par<ConcurrentRecursiveIter<Self::Item, E>, DefaultRunner>\n    where\n        E: Fn(&Self::Item, &Queue<Self::Item>) + Sync;\n\n    /// Converts this iterator into a recursive parallel iterator together with the `extend` method.\n    /// Recursive iterators are most useful for defining parallel computations over non-linear data structures\n    /// such as trees or graphs.\n    ///\n    /// Created parallel iterator is a regular parallel iterator; i.e., we have access to all [`ParIter`] features.\n    ///\n    /// It is recursive due to the extension. The recursive parallel iterator will yield\n    /// * all initial elements contained in this iterator,\n    /// * all elements dynamically added to the queue with the `extend` method while processing the elements.\n    ///\n    /// You may read more about the [`ConcurrentRecursiveIter`].\n    ///\n    /// The `extend` function defines the recursive expansion behavior. It takes two arguments:\n    /// * `element: &Self::Item` is the item being processed.\n    /// * `queue: Queue<Self::Item, P>` is the queue of remaining elements/tasks which exposes two methods:\n    ///   * `push(item)` allows us to add one item to the queue,\n    ///   * `extend(items)` allows us to add all of the items to the queue. Here `items` must have a known\n    ///     size (`ExactSizeIterator`).\n    ///\n    /// Adding children one-by-one with `push` or all together with `extend` might be the extreme options.\n    /// Actually, any intermediate approach is also possible. For instance, we can choose to `extend` in\n    /// chunks of say 50 tasks. If the item happens to create 140 children, we can handle this with four\n    /// `extend` calls.\n    ///\n    /// Using either of the methods might be beneficial for different use cases.\n    ///\n    /// Pushing children one by one makes the new task available for other threads as fast as possible. Further,\n    /// when we don't know the exact number of children ahead of time, and we don't want to use heap allocation\n    /// to store the children in a vec before adding them to the queue just to make it sized, we can add the\n    /// elements one-by-one with the `queue.push(item)` method. On the other hand, this approach will have more\n    /// parallelization overhead.\n    ///\n    /// When we extending children all at once using `queue.extend(items)`, we minimize the parallelization overhead\n    /// for adding tasks to the queue. On the other hand, the children will be available only when writing of all\n    /// children to the queue is complete which might cause idleness when tasks are scarce. Still, the recommendation\n    /// is to try to `extend` first whenever possible due to the following: (i) if we extend with a lot of children,\n    /// the tasks will not be scarce; (ii) and if we extend with only a few of items, the delay of making the tasks\n    /// available for other threads will be short.\n    ///\n    /// The decision is use-case specific and best to benchmark for the specific input.\n    ///\n    /// This crate makes use of the [`ConcurrentRecursiveIter`] for this computation and provides three ways to execute\n    /// this computation in parallel.\n    ///\n    /// ## A. Recursive Iterator with Exact Length\n    ///\n    /// If we know, or if it is possible and sufficiently cheap to find out, the exact length of the iterator,\n    /// it is recommended to work with exact length recursive iterator. Note that the exact length of an\n    /// iterator is the total of all elements that will be created. This gives the parallel executor\n    /// opportunity to optimize the chunk sizes.\n    ///\n    /// We can use `initial_elements.into_par_rec_exact(extend, count)` to create the iterator with exact length.\n    ///\n    /// ## B. Recursive Iterator with Unknown Length\n    ///\n    /// If we cannot know or it is expensive to know the exact length of the iterator ahead of time, we can\n    /// still create a recursive parallel iterator. In these cases; however, it is recommended to provide\n    /// chunk size explicitly depending on the number of threads that will be used and any estimate on the exact\n    /// length.\n    ///\n    /// We can use `initial_elements.into_par_rec(extend)` to create the iterator without length information.\n    ///\n    /// ## C. Linearization\n    ///\n    /// Even with exact length, a recursive parallel iterator is much more dynamic than a flat parallel\n    /// iterator. This dynamic nature of shrinking and growing concurrently requires a greater parallelization\n    /// overhead. An alternative approach is to eagerly discover all tasks and then perform the parallel\n    /// computation over the flattened input of tasks using [`linearize`] transformation.\n    ///\n    /// We can use `initial_elements.into_par_rec(extend).linearize()` to create the flattened iterator.\n    ///\n    /// [`ParIter`]: crate::ParIter\n    /// [`ConcurrentRecursiveIter`]: orx_concurrent_recursive_iter::ConcurrentRecursiveIter\n    /// [`linearize`]: crate::computational_variants::Par::linearize\n    ///\n    /// ## Examples\n    ///\n    /// In the following example we perform some parallel computations over a tree.\n    /// It demonstrates that a \"recursive parallel iterator\" is just a parallel iterator with\n    /// access to all [`ParIter`] methods.\n    /// Once we create the recursive parallel iterator with the `extend` definition, we can use it as\n    /// a regular parallel iterator.\n    ///\n    /// Unfortunately, the example requires a long set up for completeness. Note that the relevant\n    /// code blocks begin after line `// parallel reduction`.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use rand::{Rng, SeedableRng};\n    /// use rand_chacha::ChaCha8Rng;\n    /// use std::{collections::HashSet, ops::Range};\n    ///\n    /// pub struct Node<T> {\n    ///     pub idx: usize,\n    ///     pub data: T,\n    ///     pub children: Vec<Node<T>>,\n    /// }\n    ///\n    /// impl<T> Node<T> {\n    ///     fn create_node(out_edges: &[Vec<usize>], idx: usize, data: fn(usize) -> T) -> Node<T> {\n    ///         Node {\n    ///             idx,\n    ///             data: data(idx),\n    ///             children: out_edges[idx]\n    ///                 .iter()\n    ///                 .map(|child_idx| Self::create_node(out_edges, *child_idx, data))\n    ///                 .collect(),\n    ///         }\n    ///     }\n    ///\n    ///     pub fn new_tree(\n    ///         num_nodes: usize,\n    ///         degree: Range<usize>,\n    ///         data: fn(usize) -> T,\n    ///         rng: &mut impl Rng,\n    ///     ) -> Node<T> {\n    ///         assert!(num_nodes >= 2);\n    ///\n    ///         let mut leaves = vec![0];\n    ///         let mut remaining: Vec<_> = (1..num_nodes).collect();\n    ///         let mut edges = vec![];\n    ///         let mut out_edges = vec![vec![]; num_nodes];\n    ///\n    ///         while !remaining.is_empty() {\n    ///             let leaf_idx = rng.random_range(0..leaves.len());\n    ///             let leaf = leaves.remove(leaf_idx);\n    ///\n    ///             let degree = rng.random_range(degree.clone());\n    ///             match degree == 0 {\n    ///                 true => leaves.push(leaf),\n    ///                 false => {\n    ///                     let children_indices: HashSet<_> = (0..degree)\n    ///                         .map(|_| rng.random_range(0..remaining.len()))\n    ///                         .collect();\n    ///\n    ///                     let mut sorted: Vec<_> = children_indices.iter().copied().collect();\n    ///                     sorted.sort();\n    ///\n    ///                     edges.extend(children_indices.iter().map(|c| (leaf, remaining[*c])));\n    ///                     out_edges[leaf] = children_indices.iter().map(|c| remaining[*c]).collect();\n    ///                     leaves.extend(children_indices.iter().map(|c| remaining[*c]));\n    ///\n    ///                     for idx in sorted.into_iter().rev() {\n    ///                         remaining.remove(idx);\n    ///                     }\n    ///                 }\n    ///             }\n    ///         }\n    ///\n    ///         Self::create_node(&out_edges, 0, data)\n    ///     }\n    /// }\n    ///\n    /// let num_nodes = 1_000;\n    /// let out_degree = 0..100;\n    /// let mut rng = ChaCha8Rng::seed_from_u64(42);\n    /// let data = |idx: usize| idx.to_string();\n    /// let root = Node::new_tree(num_nodes, out_degree, data, &mut rng);\n    ///\n    /// let compute = |node: &Node<String>| node.data.parse::<u64>().unwrap();\n    ///\n    /// // parallel reduction\n    ///\n    /// fn extend<'a, T: Sync>(node: &&'a Node<T>, queue: &Queue<&'a Node<T>>) {\n    ///     queue.extend(&node.children);\n    /// }\n    ///\n    /// let sum = [&root].into_par_rec(extend).map(compute).sum();\n    /// assert_eq!(sum, 499500);\n    ///\n    /// // or any parallel computation such as map->filter->collect\n    ///\n    /// let result: Vec<_> = [&root]\n    ///     .into_par_rec(extend)\n    ///     .map(compute)\n    ///     .filter(|x| x.is_multiple_of(7))\n    ///     .collect();\n    /// assert_eq!(result.len(), 143);\n    ///\n    /// // or filter during extension\n    /// fn extend_filtered<'a>(node: &&'a Node<String>, queue: &Queue<&'a Node<String>>) {\n    ///     for child in &node.children {\n    ///         if child.idx != 42 {\n    ///             queue.push(child);\n    ///         }\n    ///     }\n    /// }\n    ///\n    /// let sum = [&root].into_par_rec(extend_filtered).map(compute).sum();\n    /// ```\n    fn into_par_rec_exact<E>(\n        self,\n        extend: E,\n        exact_len: usize,\n    ) -> Par<ConcurrentRecursiveIter<Self::Item, E>, DefaultRunner>\n    where\n        E: Fn(&Self::Item, &Queue<Self::Item>) + Sync;\n}\n\nimpl<X> IntoParIterRec for X\nwhere\n    X: IntoIterator,\n    X::Item: Send,\n{\n    fn into_par_rec<E>(\n        self,\n        extend: E,\n    ) -> Par<ConcurrentRecursiveIter<Self::Item, E>, DefaultRunner>\n    where\n        E: Fn(&Self::Item, &Queue<Self::Item>) + Sync,\n    {\n        let con_rec_iter = ConcurrentRecursiveIter::new(self, extend);\n        Par::new(DefaultRunner::default(), Params::default(), con_rec_iter)\n    }\n\n    fn into_par_rec_exact<E>(\n        self,\n        extend: E,\n        exact_len: usize,\n    ) -> Par<ConcurrentRecursiveIter<Self::Item, E>, DefaultRunner>\n    where\n        E: Fn(&Self::Item, &Queue<Self::Item>) + Sync,\n    {\n        let con_rec_iter = ConcurrentRecursiveIter::new_exact(self, extend, exact_len);\n        Par::new(DefaultRunner::default(), Params::default(), con_rec_iter)\n    }\n}\n"
  },
  {
    "path": "src/iter/recursive/mod.rs",
    "content": "mod into_par_rec_iter;\nmod rec_par_iter;\n\npub use into_par_rec_iter::IntoParIterRec;\n"
  },
  {
    "path": "src/iter/recursive/rec_par_iter.rs",
    "content": "use crate::{\n    ParIter, ParallelRunner,\n    computational_variants::{Par, ParMap, ParXap},\n    generic_values::{TransformableValues, runner_results::Infallible},\n};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::{IntoConcurrentIter, implementations::ConIterVec};\nuse orx_concurrent_recursive_iter::{ConcurrentRecursiveIter, Queue};\n\ntype Rec<T, E> = ConcurrentRecursiveIter<T, E>;\n\nimpl<E, T, R> Par<Rec<T, E>, R>\nwhere\n    T: Send + Sync,\n    E: Fn(&T, &Queue<T>) + Sync,\n    R: ParallelRunner + Clone,\n{\n    /// Even with exact length, a recursive parallel iterator is much more dynamic than a flat parallel\n    /// iterator. This dynamic nature of shrinking and growing concurrently requires a greater parallelization\n    /// overhead. An alternative approach is to eagerly discover all tasks and then perform the parallel\n    /// computation over the flattened input of tasks.\n    ///\n    /// The `linearize` approach works in two parallelization phases:\n    /// * first phase to linearize the inputs in parallel over the non-linear data, and\n    /// * second phase to perform the computation in parallel over the linear data.\n    ///\n    /// See [`into_par_rec`] and [`into_par_rec_exact`] for examples.\n    ///\n    /// [`into_par_rec`]: crate::IntoParIterRec::into_par_rec\n    /// [`into_par_rec_exact`]: crate::IntoParIterRec::into_par_rec_exact\n    pub fn linearize(self) -> Par<ConIterVec<T>, R> {\n        let params = self.params();\n        let orchestrator = self.orchestrator().clone();\n        let items: Vec<_> = self.collect();\n        let iter = items.into_con_iter();\n        Par::new(orchestrator, params, iter)\n    }\n}\n\nimpl<E, T, R, O, M1> ParMap<Rec<T, E>, O, M1, R>\nwhere\n    T: Send + Sync,\n    E: Fn(&T, &Queue<T>) + Sync,\n    R: ParallelRunner + Clone,\n    M1: Fn(T) -> O + Sync,\n{\n    /// Even with exact length, a recursive parallel iterator is much more dynamic than a flat parallel\n    /// iterator. This dynamic nature of shrinking and growing concurrently requires a greater parallelization\n    /// overhead. An alternative approach is to eagerly discover all tasks and then perform the parallel\n    /// computation over the flattened input of tasks.\n    ///\n    /// The `linearize` approach works in two parallelization phases:\n    /// * first phase to linearize the inputs in parallel over the non-linear data, and\n    /// * second phase to perform the computation in parallel over the linear data.\n    ///\n    /// See [`into_par_rec`] and [`into_par_rec_exact`] for examples.\n    ///\n    /// [`into_par_rec`]: crate::IntoParIterRec::into_par_rec\n    /// [`into_par_rec_exact`]: crate::IntoParIterRec::into_par_rec_exact\n    pub fn linearize(self) -> ParMap<ConIterVec<T>, O, M1, R> {\n        let (orchestrator, params, iter, map1) = self.destruct();\n        let par = Par::new(orchestrator.clone(), params, iter);\n        let items: Vec<_> = par.collect();\n        let iter = items.into_con_iter();\n        ParMap::new(orchestrator, params, iter, map1)\n    }\n}\n\nimpl<E, T, R, Vo, X1> ParXap<Rec<T, E>, Vo, X1, R>\nwhere\n    T: Send + Sync,\n    E: Fn(&T, &Queue<T>) + Sync,\n    R: ParallelRunner + Clone,\n    X1: Fn(T) -> Vo + Sync,\n    Vo: TransformableValues<Fallibility = Infallible>,\n{\n    /// Even with exact length, a recursive parallel iterator is much more dynamic than a flat parallel\n    /// iterator. This dynamic nature of shrinking and growing concurrently requires a greater parallelization\n    /// overhead. An alternative approach is to eagerly discover all tasks and then perform the parallel\n    /// computation over the flattened input of tasks.\n    ///\n    /// The `linearize` approach works in two parallelization phases:\n    /// * first phase to linearize the inputs in parallel over the non-linear data, and\n    /// * second phase to perform the computation in parallel over the linear data.\n    ///\n    /// See [`into_par_rec`] and [`into_par_rec_exact`] for examples.\n    ///\n    /// [`into_par_rec`]: crate::IntoParIterRec::into_par_rec\n    /// [`into_par_rec_exact`]: crate::IntoParIterRec::into_par_rec_exact\n    pub fn linearize(self) -> ParXap<ConIterVec<T>, Vo, X1, R> {\n        let (orchestrator, params, iter, xap1) = self.destruct();\n        let par = Par::new(orchestrator.clone(), params, iter);\n        let items: Vec<_> = par.collect();\n        let iter = items.into_con_iter();\n        ParXap::new(orchestrator, params, iter, xap1)\n    }\n}\n"
  },
  {
    "path": "src/iter/special_iterators.rs",
    "content": "use crate::{computational_variants::Par, runner::DefaultRunner};\nuse orx_concurrent_iter::implementations::ConIterEmpty;\n\n/// An empty parallel iterator which does not yield any elements.\npub type ParEmpty<T, R = DefaultRunner> = Par<ConIterEmpty<T>, R>;\n\n/// Creates an empty parallel iterator which does not yield any elements.\npub fn empty<T: Send + Sync>() -> ParEmpty<T> {\n    ParEmpty::new(Default::default(), Default::default(), Default::default())\n}\n"
  },
  {
    "path": "src/iter_into_par_iter.rs",
    "content": "use crate::{Params, computational_variants::Par, runner::DefaultRunner};\nuse orx_concurrent_iter::{IterIntoConcurrentIter, implementations::ConIterOfIter};\n\n/// Any regular iterator implements [`IterIntoParIter`] trait allowing them to be used\n/// as a parallel iterator; i.e., [`ParIter`], by calling [`iter_into_par`].\n///\n/// Pulling of elements from the iterator are synchronized and safely shared to threads.\n///\n/// Therefore, converting an iterator into a parallel iterator is most useful whenever\n/// the work to be done on each element is a larger task than just yielding elements by the\n/// underlying collection or generator.\n///\n/// Note that every [`IterIntoConcurrentIter`] type automatically implements [`IterIntoParIter`].\n///\n/// [`iter_into_par`]: crate::IterIntoParIter::iter_into_par\n/// [`ParIter`]: crate::ParIter\n/// [`IterIntoConcurrentIter`]: orx_concurrent_iter::IterIntoConcurrentIter\n///\n/// # Examples\n///\n/// In the following example, an arbitrary iterator is converted into a parallel iterator\n/// and shared with multiple threads as a shared reference.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// let data: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///\n/// // an arbitrary iterator\n/// let iter = data\n///     .into_iter()\n///     .filter(|x| !x.starts_with('3'))\n///     .map(|x| format!(\"{x}!\"));\n///\n/// // convert arbitrary iterator into ParIter\n/// let par_iter = iter.iter_into_par();\n/// let num_characters = par_iter.map(|x| x.len()).sum();\n///\n/// assert_eq!(num_characters, 258);\n/// ```\n///\n/// Similarly, in the following example, computation over elements of a generic\n/// iterator are distributed into multiple threads.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// let data: Vec<_> = (0..123).collect();\n///\n/// // arbitrary iterator\n/// let iter = data.iter().filter(|x| *x % 2 == 0).map(|x| x.to_string());\n///\n/// // parallel computation\n/// let sum_evens = iter\n///     .iter_into_par()\n///     .map(|x| x.parse::<u64>().unwrap())\n///     .sum();\n///\n/// assert_eq!(sum_evens, 3782);\n/// ```\npub trait IterIntoParIter: Iterator {\n    /// Any regular iterator implements [`IterIntoParIter`] trait allowing them to be used\n    /// as a parallel iterator; i.e., [`ParIter`], by calling [`iter_into_par`].\n    ///\n    /// Pulling of elements from the iterator are synchronized and safely shared to threads.\n    ///\n    /// Therefore, converting an iterator into a parallel iterator is most useful whenever\n    /// the work to be done on each element is a larger task than just yielding elements by the\n    /// underlying collection or generator.\n    ///\n    /// Note that every [`IterIntoConcurrentIter`] type automatically implements [`IterIntoParIter`].\n    ///\n    /// [`iter_into_par`]: crate::IterIntoParIter::iter_into_par\n    /// [`ParIter`]: crate::ParIter\n    /// [`IterIntoConcurrentIter`]: orx_concurrent_iter::IterIntoConcurrentIter\n    ///\n    /// # Examples\n    ///\n    /// In the following example, an arbitrary iterator is converted into a parallel iterator\n    /// and shared with multiple threads as a shared reference.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let data: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n    ///\n    /// // an arbitrary iterator\n    /// let iter = data\n    ///     .into_iter()\n    ///     .filter(|x| !x.starts_with('3'))\n    ///     .map(|x| format!(\"{x}!\"));\n    ///\n    /// // convert arbitrary iterator into ParIter\n    /// let par_iter = iter.iter_into_par();\n    /// let num_characters = par_iter.map(|x| x.len()).sum();\n    ///\n    /// assert_eq!(num_characters, 258);\n    /// ```\n    ///\n    /// Similarly, in the following example, computation over elements of a generic\n    /// iterator are distributed into multiple threads.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let data: Vec<_> = (0..123).collect();\n    ///\n    /// // arbitrary iterator\n    /// let iter = data.iter().filter(|x| *x % 2 == 0).map(|x| x.to_string());\n    ///\n    /// // parallel computation\n    /// let sum_evens = iter\n    ///     .iter_into_par()\n    ///     .map(|x| x.parse::<u64>().unwrap())\n    ///     .sum();\n    ///\n    /// assert_eq!(sum_evens, 3782);\n    /// ```\n    fn iter_into_par(self) -> Par<ConIterOfIter<Self>, DefaultRunner>\n    where\n        Self: Sized,\n        Self::Item: Send;\n}\n\nimpl<I> IterIntoParIter for I\nwhere\n    I: Iterator,\n    I::Item: Send + Sync,\n{\n    fn iter_into_par(self) -> Par<ConIterOfIter<Self>, DefaultRunner> {\n        Par::new(\n            Default::default(),\n            Params::default(),\n            self.iter_into_con_iter(),\n        )\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![doc = include_str!(\"../README.md\")]\n#![warn(\n    missing_docs,\n    clippy::unwrap_in_result,\n    clippy::unwrap_used,\n    clippy::panic,\n    clippy::panic_in_result_fn,\n    clippy::float_cmp,\n    clippy::float_cmp_const,\n    clippy::missing_panics_doc,\n    clippy::todo\n)]\n#![no_std]\n\nextern crate alloc;\n\n#[cfg(any(test, feature = \"std\"))]\nextern crate std;\n\nmod collect_into;\n/// Module containing variants of parallel iterators.\npub mod computational_variants;\nmod default_fns;\nmod enumerate;\nmod env;\n/// Module defining the parallel runner trait and the default parallel runner.\npub mod executor;\nmod generic_values;\nmod heap_sort;\nmod into_par_iter;\n/// Module for creating special iterators.\npub mod iter;\nmod iter_into_par_iter;\nmod par_iter;\nmod par_iter_option;\nmod par_iter_result;\nmod par_thread_pool;\nmod parallel_drainable;\nmod parallelizable;\nmod parallelizable_collection;\nmod parallelizable_collection_mut;\nmod parameters;\n/// ParallelRunner for parallel execution and managing threads.\npub mod runner;\nmod special_type_sets;\n/// Module defining parallel iterators with mutable access to values distributed to each thread.\npub mod using;\n\n/// Module defining the GenericIterator which is a generalization over\n/// sequential iterator, rayon's parallel iterator and orx-parallel's\n/// parallel iterator.\n/// This is particularly useful for running experiments and comparing\n/// results of computations with different methods.\n#[cfg(feature = \"generic_iterator\")]\npub mod generic_iterator;\n\n/// Module containing experiments for new algorithms, computations or factorial analysis.\n#[cfg(feature = \"experiment\")]\npub mod experiment;\n\n/// Module with utility methods for testing.\n#[cfg(test)]\nmod test_utils;\n\n// re-export\npub use orx_concurrent_recursive_iter::Queue;\n\n// export\n\npub use collect_into::ParCollectInto;\npub use enumerate::ParEnumerate;\npub use executor::{DefaultExecutor, ParallelExecutor, ThreadExecutor};\npub use into_par_iter::IntoParIter;\npub use iter::IntoParIterRec;\npub use iter_into_par_iter::IterIntoParIter;\npub use par_iter::ParIter;\npub use par_iter_option::ParIterOption;\npub use par_iter_result::ParIterResult;\npub use par_thread_pool::ParThreadPool;\npub use parallel_drainable::ParallelDrainableOverSlice;\npub use parallelizable::Parallelizable;\npub use parallelizable_collection::ParallelizableCollection;\npub use parallelizable_collection_mut::ParallelizableCollectionMut;\npub use parameters::{ChunkSize, IterationOrder, NumThreads, Params};\npub use runner::{DefaultPool, DefaultRunner, ParallelRunner, RunnerWithPool, SequentialPool};\npub use special_type_sets::Sum;\npub use using::ParIterOptionUsing;\npub use using::ParIterResultUsing;\npub use using::ParIterUsing;\n\n#[cfg(feature = \"std\")]\npub use executor::ParallelExecutorWithDiagnostics;\n\n#[cfg(feature = \"pond\")]\npub use runner::PondPool;\n#[cfg(feature = \"std\")]\npub use runner::StdDefaultPool;\n#[cfg(feature = \"yastl\")]\npub use runner::YastlPool;\n"
  },
  {
    "path": "src/par_iter.rs",
    "content": "use crate::computational_variants::fallible_option::ParOption;\nuse crate::par_iter_option::{IntoOption, ParIterOption};\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::{UsingClone, UsingFun};\nuse crate::{ParIterResult, ParThreadPool, RunnerWithPool};\nuse crate::{\n    ParIterUsing, Params,\n    collect_into::ParCollectInto,\n    default_fns::{map_clone, map_copy, map_count, reduce_sum, reduce_unit},\n    parameters::{ChunkSize, IterationOrder, NumThreads},\n    special_type_sets::Sum,\n};\nuse core::cmp::Ordering;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// Parallel iterator.\npub trait ParIter<R = DefaultRunner>: Sized + Send + Sync\nwhere\n    R: ParallelRunner,\n{\n    /// Element type of the parallel iterator.\n    type Item;\n\n    /// Returns a reference to the input concurrent iterator.\n    fn con_iter(&self) -> &impl ConcurrentIter;\n\n    /// Parameters of the parallel iterator.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::num::NonZero;\n    ///\n    /// let vec = vec![1, 2, 3, 4];\n    ///\n    /// assert_eq!(\n    ///     vec.par().params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(0).chunk_size(0).params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(1).params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(1).unwrap()),\n    ///         ChunkSize::Auto,\n    ///         IterationOrder::Ordered\n    ///     )\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(4).chunk_size(64).params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(4).unwrap()),\n    ///         ChunkSize::Exact(NonZero::new(64).unwrap()),\n    ///         IterationOrder::Ordered\n    ///     )\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par()\n    ///         .num_threads(8)\n    ///         .chunk_size(ChunkSize::Min(NonZero::new(16).unwrap()))\n    ///         .iteration_order(IterationOrder::Arbitrary)\n    ///         .params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(8).unwrap()),\n    ///         ChunkSize::Min(NonZero::new(16).unwrap()),\n    ///         IterationOrder::Arbitrary\n    ///     )\n    /// );\n    /// ```\n    fn params(&self) -> Params;\n\n    // params transformations\n\n    /// Sets the number of threads to be used in the parallel execution.\n    /// Integers can be used as the argument with the following mapping:\n    ///\n    /// * `0` -> `NumThreads::Auto`\n    /// * `1` -> `NumThreads::sequential()`\n    /// * `n > 0` -> `NumThreads::Max(n)`\n    ///\n    /// See [`NumThreads`] for details.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::num::NonZero;\n    ///\n    /// let vec = vec![1, 2, 3, 4];\n    ///\n    /// // all available threads can be used\n    ///\n    /// assert_eq!(\n    ///     vec.par().params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(0).chunk_size(0).params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// // computation will be executed sequentially on the main thread, no parallelization\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(1).params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(1).unwrap()),\n    ///         ChunkSize::Auto,\n    ///         IterationOrder::Ordered\n    ///     )\n    /// );\n    ///\n    /// // maximum 4 threads can be used\n    /// assert_eq!(\n    ///     vec.par().num_threads(4).chunk_size(64).params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(4).unwrap()),\n    ///         ChunkSize::Exact(NonZero::new(64).unwrap()),\n    ///         IterationOrder::Ordered\n    ///     )\n    /// );\n    ///\n    /// // maximum 8 threads can be used\n    /// assert_eq!(\n    ///     vec.par()\n    ///         .num_threads(8)\n    ///         .chunk_size(ChunkSize::Min(NonZero::new(16).unwrap()))\n    ///         .iteration_order(IterationOrder::Arbitrary)\n    ///         .params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(8).unwrap()),\n    ///         ChunkSize::Min(NonZero::new(16).unwrap()),\n    ///         IterationOrder::Arbitrary\n    ///     )\n    /// );\n    /// ```\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;\n\n    /// Sets the number of elements to be pulled from the concurrent iterator during the\n    /// parallel execution. When integers are used as argument, the following mapping applies:\n    ///\n    /// * `0` -> `ChunkSize::Auto`\n    /// * `n > 0` -> `ChunkSize::Exact(n)`\n    ///\n    /// Please use the default enum constructor for creating `ChunkSize::Min` variant.\n    ///\n    /// See [`ChunkSize`] for details.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::num::NonZero;\n    ///\n    /// let vec = vec![1, 2, 3, 4];\n    ///\n    /// // chunk sizes will be dynamically decided by the parallel runner\n    ///\n    /// assert_eq!(\n    ///     vec.par().params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(0).chunk_size(0).params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(1).params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(1).unwrap()),\n    ///         ChunkSize::Auto,\n    ///         IterationOrder::Ordered\n    ///     )\n    /// );\n    ///\n    /// // chunk size will always be 64, parallel runner cannot change\n    ///\n    /// assert_eq!(\n    ///     vec.par().num_threads(4).chunk_size(64).params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(4).unwrap()),\n    ///         ChunkSize::Exact(NonZero::new(64).unwrap()),\n    ///         IterationOrder::Ordered\n    ///     )\n    /// );\n    ///\n    /// // minimum chunk size will be 16, but can be dynamically increased by the parallel runner\n    ///\n    /// assert_eq!(\n    ///     vec.par()\n    ///         .num_threads(8)\n    ///         .chunk_size(ChunkSize::Min(NonZero::new(16).unwrap()))\n    ///         .iteration_order(IterationOrder::Arbitrary)\n    ///         .params(),\n    ///     Params::new(\n    ///         NumThreads::Max(NonZero::new(8).unwrap()),\n    ///         ChunkSize::Min(NonZero::new(16).unwrap()),\n    ///         IterationOrder::Arbitrary\n    ///     )\n    /// );\n    /// ```\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;\n\n    /// Sets the iteration order of the parallel computation.\n    ///\n    /// See [`IterationOrder`] for details.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let vec = vec![1, 2, 3, 4];\n    ///\n    /// // results are collected in order consistent to the input order,\n    /// // or find returns the first element satisfying the predicate\n    ///\n    /// assert_eq!(\n    ///     vec.par().params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// assert_eq!(\n    ///     vec.par().iteration_order(IterationOrder::Ordered).params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Ordered)\n    /// );\n    ///\n    /// // results might be collected in arbitrary order\n    /// // or find returns the any of the elements satisfying the predicate\n    ///\n    /// assert_eq!(\n    ///     vec.par().iteration_order(IterationOrder::Arbitrary).params(),\n    ///     Params::new(NumThreads::Auto, ChunkSize::Auto, IterationOrder::Arbitrary)\n    /// );\n    /// ```\n    fn iteration_order(self, order: IterationOrder) -> Self;\n\n    /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].\n    ///\n    /// See also [`with_pool`].\n    ///\n    /// Parallel runner of each computation can be independently specified using `with_runner`.\n    ///\n    /// When not specified the default runner is used, which is:\n    /// * [`RunnerWithPool`] with [`StdDefaultPool`] when \"std\" feature is enabled,\n    /// * [`RunnerWithPool`] with [`SequentialPool`] when \"std\" feature is disabled.\n    ///\n    /// Note that [`StdDefaultPool`] uses standard native threads.\n    ///\n    /// When working in a no-std environment, the default runner falls back to sequential.\n    /// In this case, `RunnerWithPool` using a particular thread pool must be passed in using `with_runner`\n    /// transformation to achieve parallel computation.\n    ///\n    /// [`RunnerWithPool`]: crate::RunnerWithPool\n    /// [`StdDefaultPool`]: crate::StdDefaultPool\n    /// [`SequentialPool`]: crate::SequentialPool\n    /// [`with_pool`]: crate::ParIter::with_pool\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let inputs: Vec<_> = (0..42).collect();\n    ///\n    /// // uses the DefaultRunner\n    /// // assuming \"std\" enabled, RunnerWithPool<StdDefaultPool> will be used; i.e., native threads\n    /// let sum = inputs.par().sum();\n    ///\n    /// // equivalent to:\n    /// #[cfg(feature = \"std\")]\n    /// {\n    ///     let sum2 = inputs.par().with_runner(RunnerWithPool::from(StdDefaultPool::default())).sum();\n    ///     assert_eq!(sum, sum2);\n    /// }\n    ///\n    /// #[cfg(not(miri))]\n    /// #[cfg(feature = \"scoped_threadpool\")]\n    /// {\n    ///     let mut pool = scoped_threadpool::Pool::new(8);\n    ///\n    ///     // uses the scoped_threadpool::Pool created with 8 threads\n    ///     let sum2 = inputs.par().with_runner(RunnerWithPool::from(&mut pool)).sum();\n    ///     assert_eq!(sum, sum2);\n    /// }\n    ///\n    /// #[cfg(not(miri))]\n    /// #[cfg(feature = \"rayon-core\")]\n    /// {\n    ///     let pool = rayon_core::ThreadPoolBuilder::new()\n    ///         .num_threads(8)\n    ///         .build()\n    ///         .unwrap();\n    ///\n    ///     // uses the rayon-core::ThreadPool created with 8 threads\n    ///     let sum2 = inputs.par().with_runner(RunnerWithPool::from(&pool)).sum();\n    ///     assert_eq!(sum, sum2);\n    /// }\n    /// ```\n    fn with_runner<Q: ParallelRunner>(self, runner: Q) -> impl ParIter<Q, Item = Self::Item>;\n\n    /// Rather than [`DefaultPool`], uses the parallel runner with the given `pool` implementing\n    /// [`ParThreadPool`].\n    ///\n    /// See also [`with_runner`].\n    ///\n    /// Thread pool of each computation can be independently specified using `with_pool`.\n    ///\n    /// When not specified the default pool is used, which is:\n    /// * [`StdDefaultPool`] when \"std\" feature is enabled,\n    /// * [`SequentialPool`] when \"std\" feature is disabled.\n    ///\n    /// Note that [`StdDefaultPool`] uses standard native threads.\n    ///\n    /// When working in a no-std environment, the default pool falls back to sequential.\n    /// In this case, a thread pool must be passed in using `with_pool` transformation to achieve parallel computation.\n    ///\n    /// Note that if a thread pool, say `pool`, is of a type that implements [`ParThreadPool`]; then:\n    /// * `with_pool` can be called with owned value `with_pool(pool)` for all implementors; but also,\n    /// * with a shared reference `with_pool(&pool)` for most of the implementations (eg: rayon-core, yastl), and\n    /// * with a mutable reference `with_pool(&mut pool)` for others (eg: scoped_threadpool).\n    ///\n    /// [`DefaultPool`]: crate::DefaultPool\n    /// [`RunnerWithPool`]: crate::RunnerWithPool\n    /// [`StdDefaultPool`]: crate::StdDefaultPool\n    /// [`SequentialPool`]: crate::SequentialPool\n    /// [`with_runner`]: crate::ParIter::with_runner\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let inputs: Vec<_> = (0..42).collect();\n    ///\n    /// // uses the DefaultPool\n    /// // assuming \"std\" enabled, StdDefaultPool will be used; i.e., native threads\n    /// let sum = inputs.par().sum();\n    ///\n    /// // equivalent to:\n    /// #[cfg(feature = \"std\")]\n    /// {\n    ///     let sum2 = inputs.par().with_pool(StdDefaultPool::default()).sum();\n    ///     assert_eq!(sum, sum2);\n    /// }\n    ///\n    /// #[cfg(not(miri))]\n    /// #[cfg(feature = \"scoped_threadpool\")]\n    /// {\n    ///     let mut pool = scoped_threadpool::Pool::new(8);\n    ///\n    ///     // uses the scoped_threadpool::Pool created with 8 threads\n    ///     let sum2 = inputs.par().with_pool(&mut pool).sum();\n    ///     assert_eq!(sum, sum2);\n    /// }\n    ///\n    /// #[cfg(not(miri))]\n    /// #[cfg(feature = \"rayon-core\")]\n    /// {\n    ///     let pool = rayon_core::ThreadPoolBuilder::new()\n    ///         .num_threads(8)\n    ///         .build()\n    ///         .unwrap();\n    ///\n    ///     // uses the rayon-core::ThreadPool created with 8 threads\n    ///     let sum2 = inputs.par().with_pool(&pool).sum();\n    ///     assert_eq!(sum, sum2);\n    /// }\n    /// ```\n    fn with_pool<P: ParThreadPool>(\n        self,\n        pool: P,\n    ) -> impl ParIter<RunnerWithPool<P, R::Executor>, Item = Self::Item> {\n        let runner = RunnerWithPool::from(pool).with_executor::<R::Executor>();\n        self.with_runner(runner)\n    }\n\n    // using transformations\n\n    /// Converts the [`ParIter`] into [`ParIterUsing`] which will have access to a mutable reference of the\n    /// used variable throughout the computation.\n    ///\n    /// Note that each used thread will obtain exactly one instance of the variable.\n    ///\n    /// The signature of the `using` closure is `(thread_idx: usize) -> U` which will create an instance of\n    /// `U` with respect to the `thread_idx`. The `thread_idx` is the order of the spawned thread; i.e.,\n    /// if the parallel computation uses 8 threads, the thread indices will be 0, 1, ..., 7.\n    ///\n    /// Details of the **using transformation** can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    ///\n    /// # Examples\n    ///\n    /// ## Example 1: Channels\n    ///\n    /// The following example is taken from rayon's `for_each_with` documentation and converted to using transformation:\n    ///\n    /// ```ignore\n    /// use orx_parallel::*;\n    /// use std::sync::mpsc::channel;\n    ///\n    /// let (sender, receiver) = channel();\n    ///\n    /// (0..5)\n    ///     .into_par()\n    ///     .using(|_thread_idx| sender.clone())\n    ///     .for_each(|s, x| s.send(x).unwrap());\n    ///\n    /// let mut res: Vec<_> = receiver.iter().collect();\n    ///\n    /// res.sort();\n    ///\n    /// assert_eq!(&res[..], &[0, 1, 2, 3, 4])\n    /// ```\n    ///\n    /// ## Example 2: Random Number Generator\n    ///\n    /// Random number generator is one of the common use cases that is important for a certain class of algorithms.\n    ///\n    /// The following example demonstrates how to safely generate random numbers through mutable references within\n    /// a parallel computation.\n    ///\n    /// Notice the differences between sequential and parallel computation.\n    /// * In sequential computation, a mutable reference to `rng` is captured, while in parallel computation, we\n    ///   explicitly define that we will be `using` a random number generator.\n    /// * Parallel iterator does not mutable capture any variable from the scope; however, using transformation\n    ///   converts the `ParIter` into `ParIterUsing` which allows mutable access within all iterator methods.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use rand::{Rng, SeedableRng};\n    /// use rand_chacha::ChaCha20Rng;\n    ///\n    /// fn random_walk(rng: &mut impl Rng, position: i64, num_steps: usize) -> i64 {\n    ///     (0..num_steps).fold(position, |p, _| random_step(rng, p))\n    /// }\n    ///\n    /// fn random_step(rng: &mut impl Rng, position: i64) -> i64 {\n    ///     match rng.random_bool(0.5) {\n    ///         true => position + 1,  // to right\n    ///         false => position - 1, // to left\n    ///     }\n    /// }\n    ///\n    /// fn input_positions() -> Vec<i64> {\n    ///     (-100..=100).collect()\n    /// }\n    ///\n    /// fn sequential() {\n    ///     let positions = input_positions();\n    ///\n    ///     let mut rng = ChaCha20Rng::seed_from_u64(42);\n    ///     let final_positions: Vec<_> = positions\n    ///         .iter()\n    ///         .copied()\n    ///         .map(|position| random_walk(&mut rng, position, 10))\n    ///         .collect();\n    ///     let sum_final_positions = final_positions.iter().sum::<i64>();\n    /// }\n    ///\n    /// fn parallel() {\n    ///     let positions = input_positions();\n    ///\n    ///     let final_positions: Vec<_> = positions\n    ///         .par()\n    ///         .copied()\n    ///         .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64))\n    ///         .map(|rng, position| random_walk(rng, position, 10))\n    ///         .collect();\n    ///     let sum_final_positions = final_positions.iter().sum::<i64>();\n    /// }\n    ///\n    /// sequential();\n    /// parallel();\n    /// ```\n    ///\n    /// ## Example 3: Metrics Collection\n    ///\n    /// The following example demonstrates how to collect metrics about a parallel computation with `using` transformation and\n    /// some `unsafe` help with interior mutability.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::cell::UnsafeCell;\n    ///\n    /// const N: u64 = 1_000;\n    /// const MAX_NUM_THREADS: usize = 4;\n    ///\n    /// // just some work\n    /// fn fibonacci(n: u64) -> u64 {\n    ///     let mut a = 0;\n    ///     let mut b = 1;\n    ///     for _ in 0..n {\n    ///         let c = a + b;\n    ///         a = b;\n    ///         b = c;\n    ///     }\n    ///     a\n    /// }\n    ///\n    /// #[derive(Default, Debug)]\n    /// struct ThreadMetrics {\n    ///     thread_idx: usize,\n    ///     num_items_handled: usize,\n    ///     handled_42: bool,\n    ///     num_filtered_out: usize,\n    /// }\n    ///\n    /// struct ThreadMetricsWriter<'a> {\n    ///     metrics_ref: &'a mut ThreadMetrics,\n    /// }\n    ///\n    /// struct ComputationMetrics {\n    ///     thread_metrics: UnsafeCell<[ThreadMetrics; MAX_NUM_THREADS]>,\n    /// }\n    /// unsafe impl Sync for ComputationMetrics {}\n    /// impl ComputationMetrics {\n    ///     fn new() -> Self {\n    ///         let mut thread_metrics: [ThreadMetrics; MAX_NUM_THREADS] = Default::default();\n    ///         for i in 0..MAX_NUM_THREADS {\n    ///             thread_metrics[i].thread_idx = i;\n    ///         }\n    ///         Self {\n    ///             thread_metrics: UnsafeCell::new(thread_metrics),\n    ///         }\n    ///     }\n    /// }\n    ///\n    /// impl ComputationMetrics {\n    ///     unsafe fn create_for_thread<'a>(&self, thread_idx: usize) -> ThreadMetricsWriter<'a> {\n    ///         // SAFETY: here we create a mutable variable to the thread_idx-th metrics\n    ///         // * If we call this method multiple times with the same index,\n    ///         //   we create multiple mutable references to the same ThreadMetrics,\n    ///         //   which would lead to a race condition.\n    ///         // * We must make sure that `create_for_thread` is called only once per thread.\n    ///         // * If we use `create_for_thread` within the `using` call to create mutable values\n    ///         //   used by the threads, we are certain that the parallel computation\n    ///         //   will only call this method once per thread; hence, it will not\n    ///         //   cause the race condition.\n    ///         // * On the other hand, we must ensure that we do not call this method\n    ///         //   externally.\n    ///         let array = unsafe { &mut *self.thread_metrics.get() };\n    ///         ThreadMetricsWriter {\n    ///             metrics_ref: &mut array[thread_idx],\n    ///         }\n    ///     }\n    /// }\n    ///\n    /// let mut metrics = ComputationMetrics::new();\n    ///\n    /// let input: Vec<u64> = (0..N).collect();\n    ///\n    /// let sum = input\n    ///     .par()\n    ///     // SAFETY: we do not call `create_for_thread` externally;\n    ///     // it is safe if it is called only by the parallel computation.\n    ///     // Since we unsafely implement Sync for ComputationMetrics,\n    ///     // we must ensure that ComputationMetrics is not used elsewhere.\n    ///     .using(|t| unsafe { metrics.create_for_thread(t) })\n    ///     .map(|m: &mut ThreadMetricsWriter<'_>, i| {\n    ///         // collect some useful metrics\n    ///         m.metrics_ref.num_items_handled += 1;\n    ///         m.metrics_ref.handled_42 |= *i == 42;\n    ///\n    ///         // actual work\n    ///         fibonacci((*i % 20) + 1) % 100\n    ///     })\n    ///     .filter(|m, i| {\n    ///         let is_even = i % 2 == 0;\n    ///\n    ///         if !is_even {\n    ///             m.metrics_ref.num_filtered_out += 1;\n    ///         }\n    ///\n    ///         is_even\n    ///     })\n    ///     .num_threads(MAX_NUM_THREADS)\n    ///     .sum();\n    ///\n    /// assert_eq!(sum, 9100);\n    ///\n    /// let total_by_metrics: usize = metrics\n    ///     .thread_metrics\n    ///     .get_mut()\n    ///     .iter()\n    ///     .map(|x| x.num_items_handled)\n    ///     .sum();\n    ///\n    /// assert_eq!(N as usize, total_by_metrics);\n    /// ```\n    ///\n    fn using<'using, U, F>(\n        self,\n        using: F,\n    ) -> impl ParIterUsing<'using, UsingFun<F, U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: 'using,\n        F: Fn(usize) -> U + Sync;\n\n    /// Converts the [`ParIter`] into [`ParIterUsing`] which will have access to a mutable reference of the\n    /// used variable throughout the computation.\n    ///\n    /// Note that each used thread will obtain exactly one instance of the variable.\n    ///\n    /// Each used thread receives a clone of the provided `value`.\n    /// Note that, `using_clone(value)` can be considered as a shorthand for `using(|_thread_idx| value.clone())`.\n    ///\n    /// Please see [`using`] for examples.\n    ///\n    /// Details of the **using transformation** can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    ///\n    /// [`using`]: crate::ParIter::using\n    fn using_clone<U>(\n        self,\n        value: U,\n    ) -> impl ParIterUsing<'static, UsingClone<U>, R, Item = <Self as ParIter<R>>::Item>\n    where\n        U: Clone + 'static;\n\n    // transformations into fallible computations\n\n    /// Transforms a parallel iterator where elements are of the result type; i.e., `ParIter<R, Item = Result<T, E>>`,\n    ///  into fallible parallel iterator with item type `T` and error type `E`; i.e., into `ParIterResult<R, Item = T, Err = E>`.\n    ///\n    /// `ParIterResult` is also a parallel iterator; however, with methods specialized for handling fallible computations\n    /// as follows:\n    ///\n    /// * All of its methods are based on the success path with item type of `T`.\n    /// * However, computations short-circuit and immediately return the observed error if any of the items\n    ///   is of the `Err` variant of the result enum.\n    ///\n    /// See [`ParIterResult`] for details.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    ///\n    /// let result_doubled: Result<Vec<i32>, _> = [\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())  // ParIter with Item=Result<i32, ParseIntError>\n    ///     .into_fallible_result()     // ParIterResult with Item=i32 and Err=ParseIntError\n    ///     .map(|x| x * 2)             // methods focus on the success path with Item=i32\n    ///     .collect();                 // methods return Result<_, Err>\n    ///                                 // where the Ok variant depends on the computation\n    ///\n    /// assert_eq!(result_doubled, Ok(vec![2, 4, 6]));\n    ///\n    /// // at least one fails\n    ///\n    /// let result_doubled: Result<Vec<i32>, _> = [\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 2)\n    ///     .collect();\n    ///\n    /// assert!(result_doubled.is_err());\n    /// ```\n    fn into_fallible_result<T, E>(self) -> impl ParIterResult<R, Item = T, Err = E>\n    where\n        Self::Item: IntoResult<T, E>;\n\n    /// Transforms a parallel iterator where elements are of the option type; i.e., `ParIter<R, Item = Option<T>>`,\n    ///  into fallible parallel iterator with item type `T`; i.e., into `ParIterOption<R, Item = T>`.\n    ///\n    /// `ParIterOption` is also a parallel iterator; however, with methods specialized for handling fallible computations\n    /// as follows:\n    ///\n    /// * All of its methods are based on the success path with item type of `T`.\n    /// * However, computations short-circuit and immediately return None if any of the items\n    ///   is of the `None` variant of the option enum.\n    ///\n    /// See [`ParIterResult`] for details.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    ///\n    /// let result_doubled: Option<Vec<i32>> = [\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())     // ParIter with Item=Option<i32>\n    ///     .into_fallible_option()             // ParIterOption with Item=i32\n    ///     .map(|x| x * 2)                     // methods focus on the success path with Item=i32\n    ///     .collect();                         // methods return Option<T>\n    ///                                         // where T depends on the computation\n    ///\n    /// assert_eq!(result_doubled, Some(vec![2, 4, 6]));\n    ///\n    /// // at least one fails\n    ///\n    /// let result_doubled: Option<Vec<i32>> = [\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 2)\n    ///     .collect();\n    ///\n    /// assert_eq!(result_doubled, None);\n    /// ```\n    fn into_fallible_option<T>(self) -> impl ParIterOption<R, Item = T>\n    where\n        Self::Item: IntoOption<T>,\n    {\n        ParOption::new(\n            self.map(|x| x.into_result_with_unit_err())\n                .into_fallible_result(),\n        )\n    }\n\n    // computation transformations\n\n    /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = [1, 2, 3];\n    ///\n    /// let iter = a.into_par().map(|x| 2 * x);\n    ///\n    /// let b: Vec<_> = iter.collect();\n    /// assert_eq!(b, &[2, 4, 6]);\n    /// ```\n    fn map<Out, Map>(self, map: Map) -> impl ParIter<R, Item = Out>\n    where\n        Map: Fn(Self::Item) -> Out + Sync + Clone;\n\n    /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = [1, 2, 3];\n    ///\n    /// let iter = a.into_par().filter(|x| *x % 2 == 1).copied();\n    ///\n    /// let b: Vec<_> = iter.collect();\n    /// assert_eq!(b, &[1, 3]);\n    /// ```\n    fn filter<Filter>(self, filter: Filter) -> impl ParIter<R, Item = Self::Item>\n    where\n        Filter: Fn(&Self::Item) -> bool + Sync + Clone;\n\n    /// Creates an iterator that works like map, but flattens nested structure.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let words = [\"alpha\", \"beta\", \"gamma\"];\n    ///\n    /// // chars() returns an iterator\n    /// let all_chars: Vec<_> = words.into_par().flat_map(|s| s.chars()).collect();\n    ///\n    /// let merged: String = all_chars.iter().collect();\n    /// assert_eq!(merged, \"alphabetagamma\");\n    /// ```\n    fn flat_map<IOut, FlatMap>(self, flat_map: FlatMap) -> impl ParIter<R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(Self::Item) -> IOut + Sync + Clone;\n\n    /// Creates an iterator that both filters and maps.\n    ///\n    /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.\n    ///\n    /// `filter_map` can be used to make chains of `filter` and `map` more concise.\n    /// The example below shows how a `map().filter().map()` can be shortened to a single call to `filter_map`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = [\"1\", \"two\", \"NaN\", \"four\", \"5\"];\n    ///\n    /// let numbers: Vec<_> = a\n    ///     .into_par()\n    ///     .filter_map(|s| s.parse::<usize>().ok())\n    ///     .collect();\n    ///\n    /// assert_eq!(numbers, [1, 5]);\n    /// ```\n    fn filter_map<Out, FilterMap>(self, filter_map: FilterMap) -> impl ParIter<R, Item = Out>\n    where\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync + Clone;\n\n    /// Does something with each element of an iterator, passing the value on.\n    ///\n    /// When using iterators, you’ll often chain several of them together.\n    /// While working on such code, you might want to check out what’s happening at various parts in the pipeline.\n    /// To do that, insert a call to `inspect()`.\n    ///\n    /// It’s more common for `inspect()` to be used as a debugging tool than to exist in your final code,\n    /// but applications may find it useful in certain situations when errors need to be logged before being discarded.\n    ///\n    /// It is often convenient to use thread-safe collections such as [`ConcurrentBag`] and\n    /// [`ConcurrentVec`](https://crates.io/crates/orx-concurrent-vec) to\n    /// collect some intermediate values during parallel execution for further inspection.\n    /// The following example demonstrates such a use case.\n    ///\n    /// [`ConcurrentBag`]: orx_concurrent_bag::ConcurrentBag\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use orx_concurrent_bag::*;\n    ///\n    /// let a = vec![1, 4, 2, 3];\n    ///\n    /// // let's add some inspect() calls to investigate what's happening\n    /// // - log some events\n    /// // - use a concurrent bag to collect and investigate numbers contributing to the sum\n    /// let bag = ConcurrentBag::new();\n    ///\n    /// let sum = a\n    ///     .par()\n    ///     .copied()\n    ///     .inspect(|x| println!(\"about to filter: {x}\"))\n    ///     .filter(|x| x % 2 == 0)\n    ///     .inspect(|x| {\n    ///         bag.push(*x);\n    ///         println!(\"made it through filter: {x}\");\n    ///     })\n    ///     .sum();\n    /// println!(\"{sum}\");\n    ///\n    /// let mut values_made_through = bag.into_inner();\n    /// values_made_through.sort();\n    /// assert_eq!(values_made_through, [2, 4]);\n    /// ```\n    ///\n    /// This will print:\n    ///\n    /// ```console\n    /// about to filter: 1\n    /// about to filter: 4\n    /// made it through filter: 4\n    /// about to filter: 2\n    /// made it through filter: 2\n    /// about to filter: 3\n    /// 6\n    /// ```\n    fn inspect<Operation>(self, operation: Operation) -> impl ParIter<R, Item = Self::Item>\n    where\n        Operation: Fn(&Self::Item) + Sync + Clone,\n    {\n        let map = move |x| {\n            operation(&x);\n            x\n        };\n        self.map(map)\n    }\n\n    // while transformations\n\n    /// Creates an iterator that yields elements based on the predicate `take_while`.\n    ///\n    /// It will call this closure on each element of the iterator, and yield elements while it returns true.\n    ///\n    /// After false is returned, take_while’s job is over, and the rest of the elements are ignored.\n    ///\n    /// Unlike regular sequential iterators, the result is not always deterministic due to parallel execution.\n    ///\n    /// However, as demonstrated in the example below, `collect` with ordered execution makes sure that all\n    /// elements before the predicate returns false are collected in the correct order; and hence, the result\n    /// is deterministic.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let iter = (0..10_000).par().take_while(|x| *x != 5_000);\n    /// let b: Vec<_> = iter.collect();\n    ///\n    /// assert_eq!(b, (0..5_000).collect::<Vec<_>>());\n    /// ```\n    fn take_while<While>(self, take_while: While) -> impl ParIter<R, Item = Self::Item>\n    where\n        While: Fn(&Self::Item) -> bool + Sync + Clone;\n\n    /// Creates an iterator that both yields elements based on the predicate `map_while` and maps.\n    ///\n    /// `map_while` takes a closure as an argument.\n    /// It will call this closure on each element of the iterator, and yield elements while it returns Some(_).\n    ///\n    /// After None is returned, map_while job is over, and the rest of the elements are ignored.\n    ///\n    /// Unlike regular sequential iterators, the result is not always deterministic due to parallel execution.\n    ///\n    /// However, as demonstrated in the example below, `collect` with ordered execution makes sure that all\n    /// elements before the predicate returns None are collected in the correct order; and hence, the result\n    /// is deterministic.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let iter = (0..10_000)\n    ///     .par()\n    ///     .map(|x| x as i32 - 5_000) // -5_000..10_000\n    ///     .map_while(|x| 16i32.checked_div(x));\n    /// let b: Vec<_> = iter.collect();\n    ///\n    /// assert_eq!(b, (-5_000..0).map(|x| 16 / x).collect::<Vec<_>>());\n    /// ```\n    fn map_while<Out, MapWhile>(self, map_while: MapWhile) -> impl ParIter<R, Item = Out>\n    where\n        MapWhile: Fn(Self::Item) -> Option<Out> + Sync + Clone,\n    {\n        self.map(map_while).take_while(|x| x.is_some()).map(|x| {\n            // SAFETY: since x passed the whilst(is-some) check, unwrap_unchecked\n            unsafe { x.unwrap_unchecked() }\n        })\n    }\n\n    // special item transformations\n\n    /// Creates an iterator which copies all of its elements.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    ///\n    /// let v_copied: Vec<_> = a.par().copied().collect();\n    ///\n    /// // copied is the same as .map(|&x| x)\n    /// let v_map: Vec<_> = a.par().map(|&x| x).collect();\n    ///\n    /// assert_eq!(v_copied, vec![1, 2, 3]);\n    /// assert_eq!(v_map, vec![1, 2, 3]);\n    /// ```\n    fn copied<'a, T>(self) -> impl ParIter<R, Item = T>\n    where\n        T: 'a + Copy,\n        Self: ParIter<R, Item = &'a T>,\n    {\n        self.map(map_copy)\n    }\n\n    /// Creates an iterator which clones all of its elements.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<_> = [1, 2, 3].map(|x| x.to_string()).into_iter().collect();\n    ///\n    /// let v_cloned: Vec<_> = a.par().cloned().collect();\n    ///\n    /// // cloned is the same as .map(|x| x.clone())\n    /// let v_map: Vec<_> = a.par().map(|x| x.clone()).collect();\n    ///\n    /// assert_eq!(\n    ///     v_cloned,\n    ///     vec![String::from(\"1\"), String::from(\"2\"), String::from(\"3\")]\n    /// );\n    /// assert_eq!(\n    ///     v_map,\n    ///     vec![String::from(\"1\"), String::from(\"2\"), String::from(\"3\")]\n    /// );\n    /// ```\n    fn cloned<'a, T>(self) -> impl ParIter<R, Item = T>\n    where\n        T: 'a + Clone,\n        Self: ParIter<R, Item = &'a T>,\n    {\n        self.map(map_clone)\n    }\n\n    /// Creates an iterator that flattens nested structure.\n    ///\n    /// This is useful when you have an iterator of iterators or an iterator of things that can be\n    /// turned into iterators and you want to remove one level of indirection.\n    ///\n    /// # Examples\n    ///\n    /// Basic usage.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];\n    /// let flattened = data.into_par().flatten().collect::<Vec<u8>>();\n    /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]);\n    /// ```\n    ///\n    /// Mapping and then flattening:\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let words = vec![\"alpha\", \"beta\", \"gamma\"];\n    ///\n    /// // chars() returns an iterator\n    /// let all_characters: Vec<_> = words.par().map(|s| s.chars()).flatten().collect();\n    /// let merged: String = all_characters.into_iter().collect();\n    /// assert_eq!(merged, \"alphabetagamma\");\n    /// ```\n    ///\n    /// But actually, you can write this in terms of `flat_map`,\n    /// which is preferable in this case since it conveys intent more clearly:\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let words = vec![\"alpha\", \"beta\", \"gamma\"];\n    ///\n    /// // chars() returns an iterator\n    /// let all_characters: Vec<_> = words.par().flat_map(|s| s.chars()).collect();\n    /// let merged: String = all_characters.into_iter().collect();\n    /// assert_eq!(merged, \"alphabetagamma\");\n    /// ```\n    fn flatten(self) -> impl ParIter<R, Item = <Self::Item as IntoIterator>::Item>\n    where\n        Self::Item: IntoIterator,\n    {\n        let map = |e: Self::Item| e.into_iter();\n        self.flat_map(map)\n    }\n\n    // collect\n\n    /// Collects all the items from an iterator into a collection.\n    ///\n    /// This is useful when you already have a collection and want to add the iterator items to it.\n    ///\n    /// The collection is passed in as owned value, and returned back with the additional elements.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    ///\n    /// let vec: Vec<i32> = vec![0, 1];\n    /// let vec = a.par().map(|&x| x * 2).collect_into(vec);\n    /// let vec = a.par().map(|&x| x * 10).collect_into(vec);\n    ///\n    /// assert_eq!(vec, vec![0, 1, 2, 4, 6, 10, 20, 30]);\n    /// ```\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>;\n\n    /// Transforms an iterator into a collection.\n    ///\n    /// Similar to [`Iterator::collect`], the type annotation on the left-hand-side determines\n    /// the type of the result collection; or turbofish annotation can be used.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    ///\n    /// let doubled: Vec<i32> = a.par().map(|&x| x * 2).collect();\n    ///\n    /// assert_eq!(vec![2, 4, 6], doubled);\n    /// ```\n    fn collect<C>(self) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let output = C::empty(self.con_iter().try_get_len());\n        self.collect_into(output)\n    }\n\n    // reduce\n\n    /// Reduces the elements to a single one, by repeatedly applying a reducing operation.\n    ///\n    /// If the iterator is empty, returns `None`; otherwise, returns the result of the reduction.\n    ///\n    /// The `reduce` function is a closure with two arguments: an ‘accumulator’, and an element.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let inputs = 1..10;\n    /// let reduced: usize = inputs.par().reduce(|acc, e| acc + e).unwrap_or(0);\n    /// assert_eq!(reduced, 45);\n    /// ```\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync;\n\n    /// Tests if every element of the iterator matches a predicate.\n    ///\n    /// `all` takes a `predicate` that returns true or false.\n    /// It applies this closure to each element of the iterator,\n    /// and if they all return true, then so does `all`.\n    /// If any of them returns false, it returns false.\n    ///\n    /// `all` is short-circuiting; in other words, it will stop processing as soon as it finds a false,\n    /// given that no matter what else happens, the result will also be false.\n    ///\n    /// An empty iterator returns true.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let mut a = vec![1, 2, 3];\n    /// assert!(a.par().all(|x| **x > 0));\n    /// assert!(!a.par().all(|x| **x > 2));\n    ///\n    /// a.clear();\n    /// assert!(a.par().all(|x| **x > 2)); // empty iterator\n    /// ```\n    fn all<Predicate>(self, predicate: Predicate) -> bool\n    where\n        Self::Item: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        let violates = |x: &Self::Item| !predicate(x);\n        self.find(violates).is_none()\n    }\n\n    /// Tests if any element of the iterator matches a predicate.\n    ///\n    /// `any` takes a `predicate` that returns true or false.\n    /// It applies this closure to each element of the iterator,\n    /// and if any of the elements returns true, then so does `any`.\n    /// If all of them return false, it returns false.\n    ///\n    /// `any` is short-circuiting; in other words, it will stop processing as soon as it finds a true,\n    /// given that no matter what else happens, the result will also be true.\n    ///\n    /// An empty iterator returns false.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let mut a = vec![1, 2, 3];\n    /// assert!(a.par().any(|x| **x > 0));\n    /// assert!(!a.par().any(|x| **x > 5));\n    ///\n    /// a.clear();\n    /// assert!(!a.par().any(|x| **x > 0)); // empty iterator\n    /// ```\n    fn any<Predicate>(self, predicate: Predicate) -> bool\n    where\n        Self::Item: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        self.find(predicate).is_some()\n    }\n\n    /// Consumes the iterator, counting the number of iterations and returning it.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    /// assert_eq!(a.par().filter(|x| **x >= 2).count(), 2);\n    /// ```\n    fn count(self) -> usize {\n        self.map(map_count).reduce(reduce_sum).unwrap_or(0)\n    }\n\n    /// Calls a closure on each element of an iterator.\n    ///\n    /// # Examples\n    ///\n    /// Basic usage:\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::sync::mpsc::channel;\n    ///\n    /// let (tx, rx) = channel();\n    /// (0..5)\n    ///     .par()\n    ///     .map(|x| x * 2 + 1)\n    ///     .for_each(move |x| tx.send(x).unwrap());\n    ///\n    /// let mut v: Vec<_> = rx.iter().collect();\n    /// v.sort(); // order can be mixed, since messages will be sent in parallel\n    /// assert_eq!(v, vec![1, 3, 5, 7, 9]);\n    /// ```\n    ///\n    /// Note that since parallel iterators cannot be used within the `for` loop as regular iterators,\n    /// `for_each` provides a way to perform arbitrary for loops on parallel iterators.\n    /// In the following example, we log every element that satisfies a predicate in parallel.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// (0..5)\n    ///     .par()\n    ///     .flat_map(|x| x * 100..x * 110)\n    ///     .filter(|&x| x % 3 == 0)\n    ///     .for_each(|x| println!(\"{x}\"));\n    /// ```\n    fn for_each<Operation>(self, operation: Operation)\n    where\n        Operation: Fn(Self::Item) + Sync,\n    {\n        let map = |x| operation(x);\n        let _ = self.map(map).reduce(reduce_unit);\n    }\n\n    /// Returns the maximum element of an iterator.\n    ///\n    /// If the iterator is empty, None is returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    /// let b: Vec<u32> = Vec::new();\n    ///\n    /// assert_eq!(a.par().max(), Some(&3));\n    /// assert_eq!(b.par().max(), None);\n    /// ```\n    fn max(self) -> Option<Self::Item>\n    where\n        Self::Item: Ord + Send,\n    {\n        self.reduce(Ord::max)\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    ///\n    /// If the iterator is empty, None is returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![-3_i32, 0, 1, 5, -10];\n    /// assert_eq!(*a.par().max_by(|x, y| x.cmp(y)).unwrap(), 5);\n    /// ```\n    fn max_by<Compare>(self, compare: Compare) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |x, y| match compare(&x, &y) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the maximum value from the specified function.\n    ///\n    /// If the iterator is empty, None is returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![-3_i32, 0, 1, 5, -10];\n    /// assert_eq!(*a.par().max_by_key(|x| x.abs()).unwrap(), -10);\n    /// ```\n    fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |x, y| match key(&x).cmp(&key(&y)) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the minimum element of an iterator.\n    ///\n    /// If the iterator is empty, None is returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    /// let b: Vec<u32> = Vec::new();\n    ///\n    /// assert_eq!(a.par().min(), Some(&1));\n    /// assert_eq!(b.par().min(), None);\n    /// ```\n    fn min(self) -> Option<Self::Item>\n    where\n        Self::Item: Ord + Send,\n    {\n        self.reduce(Ord::min)\n    }\n\n    /// Returns the element that gives the minimum value with respect to the specified `compare` function.\n    ///\n    /// If the iterator is empty, None is returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![-3_i32, 0, 1, 5, -10];\n    /// assert_eq!(*a.par().min_by(|x, y| x.cmp(y)).unwrap(), -10);\n    /// ```\n    fn min_by<Compare>(self, compare: Compare) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |x, y| match compare(&x, &y) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the minimum value from the specified function.\n    ///\n    /// If the iterator is empty, None is returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![-3_i32, 0, 1, 5, -10];\n    /// assert_eq!(*a.par().min_by_key(|x| x.abs()).unwrap(), 0);\n    /// ```\n    fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |x, y| match get_key(&x).cmp(&get_key(&y)) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Sums the elements of an iterator.\n    ///\n    /// Takes each element, adds them together, and returns the result.\n    ///\n    /// An empty iterator returns the additive identity (“zero”) of the type, which is 0 for integers and -0.0 for floats.\n    ///\n    /// `sum` can be used to sum any type implementing [`Sum<Out>`].\n    ///\n    /// [`Sum<Out>`]: crate::Sum\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![1, 2, 3];\n    /// let sum: i32 = a.par().sum();\n    ///\n    /// assert_eq!(sum, 6);\n    /// ```\n    fn sum<Out>(self) -> Out\n    where\n        Self::Item: Sum<Out>,\n        Out: Send,\n    {\n        self.map(Self::Item::map)\n            .reduce(Self::Item::reduce)\n            .unwrap_or(Self::Item::zero())\n    }\n\n    // early exit\n\n    /// Returns the first (or any) element of the iterator; returns None if it is empty.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// # Examples\n    ///\n    /// The following example demonstrates the usage of first with default `Ordered` iteration.\n    /// This guarantees that the first element with respect to position in the input sequence\n    /// is returned.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<usize> = vec![];\n    /// assert_eq!(a.par().copied().first(), None);\n    ///\n    /// let a = vec![1, 2, 3];\n    /// assert_eq!(a.par().copied().first(), Some(1));\n    ///\n    /// let a = 1..10_000;\n    /// assert_eq!(a.par().filter(|x| x % 3421 == 0).first(), Some(3421));\n    /// assert_eq!(a.par().filter(|x| x % 12345 == 0).first(), None);\n    ///\n    /// // or equivalently,\n    /// assert_eq!(a.par().find(|x| x % 3421 == 0), Some(3421));\n    /// ```\n    ///\n    /// When the order is set to `Arbitrary`, `first` might return any of the elements,\n    /// whichever is visited first depending on the parallel execution.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = 1..10_000;\n    ///\n    /// // might return either of 3421 or 2*3421\n    /// let any = a.par().iteration_order(IterationOrder::Arbitrary).filter(|x| x % 3421 == 0).first().unwrap();\n    /// assert!([3421, 2 * 3421].contains(&any));\n    ///\n    /// // or equivalently,\n    /// let any = a.par().iteration_order(IterationOrder::Arbitrary).find(|x| x % 3421 == 0).unwrap();\n    /// assert!([3421, 2 * 3421].contains(&any));\n    /// ```\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send;\n\n    /// Searches for an element of an iterator that satisfies a `predicate`.\n    ///\n    /// Depending on the set iteration order of the parallel iterator, returns\n    ///\n    /// * first element satisfying the `predicate` if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element satisfying the `predicate` if `IterationOrder::Arbitrary` is set.\n    ///\n    /// `find` takes a closure that returns true or false.\n    /// It applies this closure to each element of the iterator,\n    /// and returns `Some(x)` where `x` is the first element that returns true.\n    /// If they all return false, it returns None.\n    ///\n    /// `find` is short-circuiting; in other words, it will stop processing as soon as the closure returns true.\n    ///\n    /// `par_iter.find(predicate)` can also be considered as a shorthand for `par_iter.filter(predicate).first()`.\n    ///\n    /// # Examples\n    ///\n    /// The following example demonstrates the usage of first with default `Ordered` iteration.\n    /// This guarantees that the first element with respect to position in the input sequence\n    /// is returned.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = 1..10_000;\n    /// assert_eq!(a.par().find(|x| x % 12345 == 0), None);\n    /// assert_eq!(a.par().find(|x| x % 3421 == 0), Some(3421));\n    /// ```\n    ///\n    /// When the order is set to `Arbitrary`, `find` might return any of the elements satisfying the predicate,\n    /// whichever is found first depending on the parallel execution.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = 1..10_000;\n    ///\n    /// // might return either of 3421 or 2*3421\n    /// let any = a.par().iteration_order(IterationOrder::Arbitrary).find(|x| x % 3421 == 0).unwrap();\n    /// assert!([3421, 2 * 3421].contains(&any));\n    /// ```\n    fn find<Predicate>(self, predicate: Predicate) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        self.filter(&predicate).first()\n    }\n}\n"
  },
  {
    "path": "src/par_iter_option.rs",
    "content": "use crate::default_fns::{map_count, reduce_sum, reduce_unit};\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParThreadPool, RunnerWithPool, Sum,\n};\nuse core::cmp::Ordering;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with None.\n///\n/// # Examples\n///\n/// To demonstrate the difference of fallible iterator's behavior, consider the following simple example.\n/// We parse a series of strings into integers.\n/// We try this twice:\n/// * in the first one, all inputs are good, hence, we obtain Some of parsed numbers,\n/// * in the second one, the value in the middle is faulty, we expect the computation to fail.\n///\n/// In the following, we try to achieve this both with a regular parallel iterator ([`ParIter`]) and a fallible\n/// parallel iterator, `ParIterOption` in this case.\n///\n/// You may notice the following differences:\n/// * In the regular iterator, it is not very convenient to keep both the resulting numbers and a potential error.\n///   Here, we make use of `filter_map`.\n/// * On the other hand, the `collect` method of the fallible iterator directly returns an `Option` of the computation\n///   which is either Some of all parsed numbers or None if any computation fails.\n/// * Also importantly note that the regular iterator will try to parse all the strings, regardless of how many times\n///   the parsing fails.\n/// * Fallible iterator, on the other hand, stops immediately after observing the first None and short circuits the\n///   computation.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// let expected_results = [Some((0..100).collect::<Vec<_>>()), None];\n///\n/// for expected in expected_results {\n///     let expected_some = expected.is_some();\n///     let mut inputs: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///     if !expected_some {\n///         inputs.insert(50, \"x\".to_string()); // plant an error case\n///     }\n///\n///     // regular parallel iterator\n///     let results = inputs.par().map(|x| x.parse::<u32>().ok());\n///     let numbers: Vec<_> = results.filter_map(|x| x).collect();\n///     if expected_some {\n///         assert_eq!(&expected, &Some(numbers));\n///     } else {\n///         // otherwise, numbers contains some numbers, but we are not sure\n///         // if the computation completely succeeded or not\n///     }\n///\n///     // fallible parallel iterator\n///     let results = inputs.par().map(|x| x.parse::<u32>().ok());\n///     let result: Option<Vec<_>> = results.into_fallible_option().collect();\n///     assert_eq!(&expected, &result);\n/// }\n/// ```\n///\n/// These differences are not specific to `collect`; all fallible iterator methods return an option.\n/// The following demonstrate reduction examples, where the result is either the reduced value if the entire computation\n/// succeeds, or None.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// for will_fail in [false, true] {\n///     let mut inputs: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///     if will_fail {\n///         inputs.insert(50, \"x\".to_string()); // plant an error case\n///     }\n///\n///     // sum\n///     let results = inputs.par().map(|x| x.parse::<u32>().ok());\n///     let result: Option<u32> = results.into_fallible_option().sum();\n///     match will_fail {\n///         true => assert_eq!(result, None),\n///         false => assert_eq!(result, Some(4950)),\n///     }\n///\n///     // max\n///     let results = inputs.par().map(|x| x.parse::<u32>().ok());\n///     let result: Option<Option<u32>> = results.into_fallible_option().max();\n///     match will_fail {\n///         true => assert_eq!(result, None),\n///         false => assert_eq!(result, Some(Some(99))),\n///     }\n/// }\n/// ```\n///\n/// Finally, similar to regular iterators, a fallible parallel iterator can be tranformed using iterator methods.\n/// However, the transformation is on the success path, the failure case of None always short circuits and returns None.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// for will_fail in [false, true] {\n///     let mut inputs: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///     if will_fail {\n///         inputs.insert(50, \"x\".to_string()); // plant an error case\n///     }\n///\n///     // fallible iter\n///     let results = inputs.par().map(|x| x.parse::<u32>().ok());\n///     let fallible = results.into_fallible_option();\n///\n///     // transformations\n///\n///     let result: Option<usize> = fallible\n///         .filter(|x| x % 2 == 1)                                 // Item: u32\n///         .map(|x| 3 * x)                                         // Item: u32\n///         .filter_map(|x| (x % 10 != 0).then_some(x))             // Item: u32\n///         .flat_map(|x| [x.to_string(), (10 * x).to_string()])    // Item: String\n///         .map(|x| x.len())                                       // Item: usize\n///         .sum();\n///\n///     match will_fail {\n///         true => assert_eq!(result, None),\n///         false => assert_eq!(result, Some(312)),\n///     }\n/// }\n/// ```\n///\n/// [`ParIter`]: crate::ParIter\npub trait ParIterOption<R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n{\n    /// Type of the success element, to be received as the Some variant iff the entire computation succeeds.\n    type Item;\n\n    // params transformations\n\n    /// Sets the number of threads to be used in the parallel execution.\n    /// Integers can be used as the argument with the following mapping:\n    ///\n    /// * `0` -> `NumThreads::Auto`\n    /// * `1` -> `NumThreads::sequential()`\n    /// * `n > 0` -> `NumThreads::Max(n)`\n    ///\n    /// See [`NumThreads`] and [`crate::ParIter::num_threads`] for details.\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;\n\n    /// Sets the number of elements to be pulled from the concurrent iterator during the\n    /// parallel execution. When integers are used as argument, the following mapping applies:\n    ///\n    /// * `0` -> `ChunkSize::Auto`\n    /// * `n > 0` -> `ChunkSize::Exact(n)`\n    ///\n    /// Please use the default enum constructor for creating `ChunkSize::Min` variant.\n    ///\n    /// See [`ChunkSize`] and [`crate::ParIter::chunk_size`] for details.\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;\n\n    /// Sets the iteration order of the parallel computation.\n    ///\n    /// See [`IterationOrder`] and [`crate::ParIter::iteration_order`] for details.\n    fn iteration_order(self, order: IterationOrder) -> Self;\n\n    /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].\n    ///\n    /// See [`ParIter::with_runner`] for details.\n    ///\n    /// [`DefaultRunner`]: crate::DefaultRunner\n    /// [`ParIter::with_runner`]: crate::ParIter::with_runner\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterOption<Q, Item = Self::Item>;\n\n    /// Rather than [`DefaultPool`], uses the parallel runner with the given `pool` implementing\n    /// [`ParThreadPool`].\n    ///\n    /// See [`ParIter::with_pool`] for details.\n    ///\n    /// [`DefaultPool`]: crate::DefaultPool\n    /// [`ParIter::with_pool`]: crate::ParIter::with_pool\n    fn with_pool<P: ParThreadPool>(\n        self,\n        pool: P,\n    ) -> impl ParIterOption<RunnerWithPool<P, R::Executor>, Item = Self::Item>\n    where\n        Self: Sized,\n    {\n        let runner = RunnerWithPool::from(pool).with_executor::<R::Executor>();\n        self.with_runner(runner)\n    }\n\n    // computation transformations\n\n    /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Some` variant.\n    /// Any observation of a `None` case short-circuits the computation and immediately returns None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Option<u32>> = vec![Some(1), Some(2), Some(3)];\n    /// let iter = a.into_par().into_fallible_option().map(|x| 2 * x);\n    ///\n    /// let b: Option<Vec<_>> = iter.collect();\n    /// assert_eq!(b, Some(vec![2, 4, 6]));\n    ///\n    /// // at least one fails\n    /// let a = vec![Some(1), None, Some(3)];\n    /// let iter = a.into_par().into_fallible_option().map(|x| 2 * x);\n    ///\n    /// let b: Option<Vec<_>> = iter.collect();\n    /// assert_eq!(b, None);\n    /// ```\n    fn map<Out, Map>(self, map: Map) -> impl ParIterOption<R, Item = Out>\n    where\n        Self: Sized,\n        Map: Fn(Self::Item) -> Out + Sync + Clone,\n        Out: Send;\n\n    /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Some` variant.\n    /// Any observation of a `None` case short-circuits the computation and immediately returns None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Option<i32>> = vec![Some(1), Some(2), Some(3)];\n    /// let iter = a.into_par().into_fallible_option().filter(|x| x % 2 == 1);\n    ///\n    /// let b = iter.sum();\n    /// assert_eq!(b, Some(1 + 3));\n    ///\n    /// // at least one fails\n    /// let a = vec![Some(1), None, Some(3)];\n    /// let iter = a.into_par().into_fallible_option().filter(|x| x % 2 == 1);\n    ///\n    /// let b = iter.sum();\n    /// assert_eq!(b, None);\n    /// ```\n    fn filter<Filter>(self, filter: Filter) -> impl ParIterOption<R, Item = Self::Item>\n    where\n        Self: Sized,\n        Filter: Fn(&Self::Item) -> bool + Sync + Clone,\n        Self::Item: Send;\n\n    /// Creates an iterator that works like map, but flattens nested structure.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Some` variant.\n    /// Any observation of a `None` case short-circuits the computation and immediately returns None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let words: Vec<Option<&str>> = vec![Some(\"alpha\"), Some(\"beta\"), Some(\"gamma\")];\n    ///\n    /// let all_chars: Option<Vec<_>> = words\n    ///     .into_par()\n    ///     .into_fallible_option()\n    ///     .flat_map(|s| s.chars()) // chars() returns an iterator\n    ///     .collect();\n    ///\n    /// let merged: Option<String> = all_chars.map(|chars| chars.iter().collect());\n    /// assert_eq!(merged, Some(\"alphabetagamma\".to_string()));\n    ///\n    /// // at least one fails\n    /// let words: Vec<Option<&str>> = vec![Some(\"alpha\"), Some(\"beta\"), None, Some(\"gamma\")];\n    ///\n    /// let all_chars: Option<Vec<_>> = words\n    ///     .into_par()\n    ///     .into_fallible_option()\n    ///     .flat_map(|s| s.chars()) // chars() returns an iterator\n    ///     .collect();\n    ///\n    /// let merged: Option<String> = all_chars.map(|chars| chars.iter().collect());\n    /// assert_eq!(merged, None);\n    /// ```\n    fn flat_map<IOut, FlatMap>(self, flat_map: FlatMap) -> impl ParIterOption<R, Item = IOut::Item>\n    where\n        Self: Sized,\n        IOut: IntoIterator,\n        IOut::Item: Send,\n        FlatMap: Fn(Self::Item) -> IOut + Sync + Clone;\n\n    /// Creates an iterator that both filters and maps.\n    ///\n    /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.\n    ///\n    /// `filter_map` can be used to make chains of `filter` and `map` more concise.\n    /// The example below shows how a `map().filter().map()` can be shortened to a single call to `filter_map`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Option<&str>> = vec![Some(\"1\"), Some(\"two\"), Some(\"NaN\"), Some(\"four\"), Some(\"5\")];\n    ///\n    /// let numbers: Option<Vec<_>> = a\n    ///     .into_par()\n    ///     .into_fallible_option()\n    ///     .filter_map(|s| s.parse::<usize>().ok())\n    ///     .collect();\n    ///\n    /// assert_eq!(numbers, Some(vec![1, 5]));\n    ///\n    /// // at least one fails\n    /// let a: Vec<Option<&str>> = vec![Some(\"1\"), Some(\"two\"), None, Some(\"four\"), Some(\"5\")];\n    ///\n    /// let numbers: Option<Vec<_>> = a\n    ///     .into_par()\n    ///     .into_fallible_option()\n    ///     .filter_map(|s| s.parse::<usize>().ok())\n    ///     .collect();\n    ///\n    /// assert_eq!(numbers, None);\n    /// ```\n    fn filter_map<Out, FilterMap>(self, filter_map: FilterMap) -> impl ParIterOption<R, Item = Out>\n    where\n        Self: Sized,\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync + Clone,\n        Out: Send;\n\n    /// Does something with each successful element of an iterator, passing the value on, provided that all elements are of Some variant;\n    /// short-circuits and returns None otherwise.\n    ///\n    /// When using iterators, you’ll often chain several of them together.\n    /// While working on such code, you might want to check out what’s happening at various parts in the pipeline.\n    /// To do that, insert a call to `inspect()`.\n    ///\n    /// It’s more common for `inspect()` to be used as a debugging tool than to exist in your final code,\n    /// but applications may find it useful in certain situations when errors need to be logged before being discarded.\n    ///\n    /// It is often convenient to use thread-safe collections such as [`ConcurrentBag`] and\n    /// [`ConcurrentVec`](https://crates.io/crates/orx-concurrent-vec) to\n    /// collect some intermediate values during parallel execution for further inspection.\n    /// The following example demonstrates such a use case.\n    ///\n    /// [`ConcurrentBag`]: orx_concurrent_bag::ConcurrentBag\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use orx_concurrent_bag::*;\n    /// use std::num::ParseIntError;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Option<u32>> = [\"1\", \"4\", \"2\", \"3\"]\n    ///     .into_iter()\n    ///     .map(|x| x.parse::<u32>().ok())\n    ///     .collect();\n    ///\n    /// // let's add some inspect() calls to investigate what's happening\n    /// // - log some events\n    /// // - use a concurrent bag to collect and investigate numbers contributing to the sum\n    /// let bag = ConcurrentBag::new();\n    ///\n    /// let sum = a\n    ///     .par()\n    ///     .cloned()\n    ///     .into_fallible_option()\n    ///     .inspect(|x| println!(\"about to filter: {x}\"))\n    ///     .filter(|x| x % 2 == 0)\n    ///     .inspect(|x| {\n    ///         bag.push(*x);\n    ///         println!(\"made it through filter: {x}\");\n    ///     })\n    ///     .sum();\n    /// assert_eq!(sum, Some(4 + 2));\n    ///\n    /// let mut values_made_through = bag.into_inner();\n    /// values_made_through.sort();\n    /// assert_eq!(values_made_through, [2, 4]);\n    ///\n    /// // at least one fails\n    /// let a: Vec<Option<u32>> = [\"1\", \"4\", \"x\", \"3\"]\n    ///     .into_iter()\n    ///     .map(|x| x.parse::<u32>().ok())\n    ///     .collect();\n    ///\n    /// // let's add some inspect() calls to investigate what's happening\n    /// // - log some events\n    /// // - use a concurrent bag to collect and investigate numbers contributing to the sum\n    /// let bag = ConcurrentBag::new();\n    ///\n    /// let sum = a\n    ///     .par()\n    ///     .cloned()\n    ///     .into_fallible_option()\n    ///     .inspect(|x| println!(\"about to filter: {x}\"))\n    ///     .filter(|x| x % 2 == 0)\n    ///     .inspect(|x| {\n    ///         bag.push(*x);\n    ///         println!(\"made it through filter: {x}\");\n    ///     })\n    ///     .sum();\n    /// assert_eq!(sum, None);\n    /// ```\n    fn inspect<Operation>(self, operation: Operation) -> impl ParIterOption<R, Item = Self::Item>\n    where\n        Self: Sized,\n        Operation: Fn(&Self::Item) + Sync + Clone,\n        Self::Item: Send;\n\n    // collect\n\n    /// Collects all the items from an iterator into a collection iff all elements are of Some variant.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// This is useful when you already have a collection and want to add the iterator items to it.\n    ///\n    /// The collection is passed in as owned value, and returned back with the additional elements.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let vec: Vec<i32> = vec![0, 1];\n    ///\n    /// // all succeeds\n    /// let result = [\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 10)\n    ///     .collect_into(vec);\n    /// assert_eq!(result, Some(vec![0, 1, 10, 20, 30]));\n    ///\n    /// let vec = result.unwrap();\n    ///\n    /// // at least one fails\n    ///\n    /// let result = [\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 10)\n    ///     .collect_into(vec);\n    /// assert_eq!(result, None);\n    /// ```\n    fn collect_into<C>(self, output: C) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>;\n\n    /// Transforms an iterator into a collection iff all elements are of Ok variant.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Similar to [`Iterator::collect`], the type annotation on the left-hand-side determines\n    /// the type of the result collection; or turbofish annotation can be used.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    ///\n    /// let result_doubled: Option<Vec<i32>> = [\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 2)\n    ///     .collect();\n    ///\n    /// assert_eq!(result_doubled, Some(vec![2, 4, 6]));\n    ///\n    /// // at least one fails\n    ///\n    /// let result_doubled: Option<Vec<i32>> = [\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 2)\n    ///     .collect();\n    ///\n    /// assert_eq!(result_doubled, None);\n    /// ```\n    fn collect<C>(self) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>;\n\n    // reduce\n\n    /// Reduces the elements to a single one, by repeatedly applying a reducing operation.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// If the iterator is empty, returns `Some(None)`; otherwise, returns `Some` of result of the reduction.\n    ///\n    /// The `reduce` function is a closure with two arguments: an ‘accumulator’, and an element.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let reduced: Option<Option<u32>> = (1..10)\n    ///     .par()\n    ///     .map(|x| 100u32.checked_div(x as u32))\n    ///     .into_fallible_option()\n    ///     .reduce(|acc, e| acc + e);\n    /// assert_eq!(reduced, Some(Some(281)));\n    ///\n    /// // all succeeds - empty iterator\n    /// let reduced: Option<Option<u32>> = (1..1)\n    ///     .par()\n    ///     .map(|x| 100u32.checked_div(x as u32))\n    ///     .into_fallible_option()\n    ///     .reduce(|acc, e| acc + e);\n    /// assert_eq!(reduced, Some(None));\n    ///\n    /// // at least one fails\n    /// let reduced: Option<Option<u32>> = (0..10)\n    ///     .par()\n    ///     .map(|x| 100u32.checked_div(x as u32))\n    ///     .into_fallible_option()\n    ///     .reduce(|acc, e| acc + e);\n    /// assert_eq!(reduced, None);\n    /// ```\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync;\n\n    /// Tests if every element of the iterator matches a predicate.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// `all` takes a `predicate` that returns true or false.\n    /// It applies this closure to each Ok element of the iterator,\n    /// and if they all return true, then so does `all`.\n    /// If any of them returns false, it returns false.\n    ///\n    /// Note that `all` computation is itself also short-circuiting; in other words, it will stop processing as soon as it finds a false,\n    /// given that no matter what else happens, the result will also be false.\n    ///\n    /// Therefore, in case the fallible iterator contains both a None element and a Some element which violates the `predicate`,\n    /// the result is **not deterministic**. It might be the `None` if it is observed first; or `Some(false)` if the violation is observed first.\n    ///\n    /// On the other hand, when it returns `Some(true)`, we are certain that all elements are of `Some` variant and all satisfy the `predicate`.\n    ///\n    /// An empty iterator returns `Some(true)`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all Some\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .all(|x| *x > 0);\n    /// assert_eq!(result, Some(true));\n    ///\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .all(|x| *x > 1);\n    /// assert_eq!(result, Some(false));\n    ///\n    /// let result = Vec::<&str>::new()\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .all(|x| *x > 1);\n    /// assert_eq!(result, Some(true)); // empty iterator\n    ///\n    /// // at least one None\n    /// let result = vec![\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .all(|x| *x > 0);\n    /// assert_eq!(result, None);\n    /// ```\n    fn all<Predicate>(self, predicate: Predicate) -> Option<bool>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        let violates = |x: &Self::Item| !predicate(x);\n        self.find(violates).map(|x| x.is_none())\n    }\n\n    /// Tests if any element of the iterator matches a predicate.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// `any` takes a `predicate` that returns true or false.\n    /// It applies this closure to each element of the iterator,\n    /// and if any of the elements returns true, then so does `any`.\n    /// If all of them return false, it returns false.\n    ///\n    /// Note that `any` computation is itself also short-circuiting; in other words, it will stop processing as soon as it finds a true,\n    /// given that no matter what else happens, the result will also be true.\n    ///\n    /// Therefore, in case the fallible iterator contains both a None element and a Some element which satisfies the `predicate`,\n    /// the result is **not deterministic**. It might be the `None` if it is observed first; or `Some(true)` if element satisfying the predicate\n    /// is observed first.\n    ///\n    /// On the other hand, when it returns `Some(false)`, we are certain that all elements are of `Some` variant and none of them satisfies the `predicate`.\n    ///\n    /// An empty iterator returns `Some(false)`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all Some\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .any(|x| *x > 1);\n    /// assert_eq!(result, Some(true));\n    ///\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .any(|x| *x > 3);\n    /// assert_eq!(result, Some(false));\n    ///\n    /// let result = Vec::<&str>::new()\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .any(|x| *x > 1);\n    /// assert_eq!(result, Some(false)); // empty iterator\n    ///\n    /// // at least one None\n    /// let result = vec![\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .any(|x| *x > 5);\n    /// assert_eq!(result, None);\n    /// ```\n    fn any<Predicate>(self, predicate: Predicate) -> Option<bool>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        self.find(predicate).map(|x| x.is_some())\n    }\n\n    /// Consumes the iterator, counting the number of iterations and returning it.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all Some\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .filter(|x| *x >= 2)\n    ///     .count();\n    /// assert_eq!(result, Some(2));\n    ///\n    /// // at least one None\n    /// let result = vec![\"x!\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .filter(|x| *x >= 2)\n    ///     .count();\n    /// assert_eq!(result, None);\n    /// ```\n    fn count(self) -> Option<usize>\n    where\n        Self: Sized,\n    {\n        self.map(map_count)\n            .reduce(reduce_sum)\n            .map(|x| x.unwrap_or(0))\n    }\n\n    /// Calls a closure on each element of an iterator, and returns `Ok(())` if all elements succeed.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// # Examples\n    ///\n    /// Basic usage:\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::sync::mpsc::channel;\n    ///\n    /// // all Some\n    /// let (tx, rx) = channel();\n    /// let result = vec![\"0\", \"1\", \"2\", \"3\", \"4\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 2 + 1)\n    ///     .for_each(move |x| tx.send(x).unwrap());\n    ///\n    /// assert_eq!(result, Some(()));\n    ///\n    /// let mut v: Vec<_> = rx.iter().collect();\n    /// v.sort(); // order can be mixed, since messages will be sent in parallel\n    /// assert_eq!(v, vec![1, 3, 5, 7, 9]);\n    ///\n    /// // at least one None\n    /// let (tx, _rx) = channel();\n    /// let result = vec![\"0\", \"1\", \"2\", \"x!\", \"4\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>().ok())\n    ///     .into_fallible_option()\n    ///     .map(|x| x * 2 + 1)\n    ///     .for_each(move |x| tx.send(x).unwrap());\n    ///\n    /// assert_eq!(result, None);\n    /// ```\n    fn for_each<Operation>(self, operation: Operation) -> Option<()>\n    where\n        Self: Sized,\n        Operation: Fn(Self::Item) + Sync,\n    {\n        let map = |x| operation(x);\n        self.map(map).reduce(reduce_unit).map(|_| ())\n    }\n\n    /// Returns Some of maximum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![Some(1), Some(2), Some(3)];\n    /// assert_eq!(a.par().copied().into_fallible_option().max(), Some(Some(3)));\n    ///\n    /// let b: Vec<Option<i32>> = vec![];\n    /// assert_eq!(b.par().copied().into_fallible_option().max(), Some(None));\n    ///\n    /// let c = vec![Some(1), Some(2), None];\n    /// assert_eq!(c.par().copied().into_fallible_option().max(), None);\n    /// ```\n    fn max(self) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Ord + Send,\n    {\n        self.reduce(Ord::max)\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(1), Some(2), Some(3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .max_by(|a, b| a.cmp(b)),\n    ///     Some(Some(3))\n    /// );\n    ///\n    /// let b: Vec<Option<i32>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .max_by(|a, b| a.cmp(b)),\n    ///     Some(None)\n    /// );\n    ///\n    /// let c: Vec<Option<i32>> = vec![Some(1), Some(2), None];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .max_by(|a, b| a.cmp(b)),\n    ///     None\n    /// );\n    /// ```\n    fn max_by<Compare>(self, compare: Compare) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |x, y| match compare(&x, &y) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the maximum value from the specified function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(-1), Some(2), Some(-3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .max_by_key(|x| x.abs()),\n    ///     Some(Some(-3))\n    /// );\n    ///\n    /// let b: Vec<Option<i32>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .max_by_key(|x| x.abs()),\n    ///     Some(None)\n    /// );\n    ///\n    /// let c: Vec<Option<i32>> = vec![Some(1), Some(2), None];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .max_by_key(|x| x.abs()),\n    ///     None\n    /// );\n    /// ```\n    fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |x, y| match key(&x).cmp(&key(&y)) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns Some of minimum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a = vec![Some(1), Some(2), Some(3)];\n    /// assert_eq!(a.par().copied().into_fallible_option().min(), Some(Some(1)));\n    ///\n    /// let b: Vec<Option<i32>> = vec![];\n    /// assert_eq!(b.par().copied().into_fallible_option().min(), Some(None));\n    ///\n    /// let c = vec![Some(1), Some(2), None];\n    /// assert_eq!(c.par().copied().into_fallible_option().min(), None);\n    /// ```\n    fn min(self) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Ord + Send,\n    {\n        self.reduce(Ord::min)\n    }\n\n    /// Returns the element that gives the minimum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(1), Some(2), Some(3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .min_by(|a, b| a.cmp(b)),\n    ///     Some(Some(1))\n    /// );\n    ///\n    /// let b: Vec<Option<i32>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .min_by(|a, b| a.cmp(b)),\n    ///     Some(None)\n    /// );\n    ///\n    /// let c: Vec<Option<i32>> = vec![Some(1), Some(2), None];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .min_by(|a, b| a.cmp(b)),\n    ///     None\n    /// );\n    /// ```\n    fn min_by<Compare>(self, compare: Compare) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |x, y| match compare(&x, &y) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the minimum value from the specified function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(-1), Some(2), Some(-3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .min_by_key(|x| x.abs()),\n    ///     Some(Some(-1))\n    /// );\n    ///\n    /// let b: Vec<Option<i32>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .min_by_key(|x| x.abs()),\n    ///     Some(None)\n    /// );\n    ///\n    /// let c: Vec<Option<i32>> = vec![Some(1), Some(2), None];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_option()\n    ///         .min_by_key(|x| x.abs()),\n    ///     None\n    /// );\n    /// ```\n    fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |x, y| match get_key(&x).cmp(&get_key(&y)) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Sums the elements of an iterator.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// If the iterator is empty, returns zero; otherwise, returns `Some` of the sum.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let reduced: Option<u32> = (1..10)\n    ///     .par()\n    ///     .map(|x| 100u32.checked_div(x as u32))\n    ///     .into_fallible_option()\n    ///     .sum();\n    /// assert_eq!(reduced, Some(281));\n    ///\n    /// // all succeeds - empty iterator\n    /// let reduced: Option<u32> = (1..1)\n    ///     .par()\n    ///     .map(|x| 100u32.checked_div(x as u32))\n    ///     .into_fallible_option()\n    ///     .sum();\n    /// assert_eq!(reduced, Some(0));\n    ///\n    /// // at least one fails\n    /// let reduced: Option<u32> = (0..10)\n    ///     .par()\n    ///     .map(|x| 100u32.checked_div(x as u32))\n    ///     .into_fallible_option()\n    ///     .sum();\n    /// assert_eq!(reduced, None);\n    /// ```\n    fn sum<Out>(self) -> Option<Out>\n    where\n        Self: Sized,\n        Self::Item: Sum<Out>,\n        Out: Send,\n    {\n        self.map(Self::Item::map)\n            .reduce(Self::Item::reduce)\n            .map(|x| x.unwrap_or(Self::Item::zero()))\n    }\n\n    // early exit\n\n    /// Returns the first (or any) element of the iterator.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if a None element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// Note that `find` itself is short-circuiting in addition to fallible computation.\n    /// Therefore, in case the fallible iterator contains both a None and a Some element,\n    /// the result is **not deterministic**:\n    /// * it might be the `None` if it is observed first;\n    /// * or `Some(element)` if the Some element is observed first.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Option<i32>> = vec![];\n    /// assert_eq!(a.par().copied().into_fallible_option().first(), Some(None));\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(1), Some(2), Some(3)];\n    /// assert_eq!(\n    ///     a.par().copied().into_fallible_option().first(),\n    ///     Some(Some(1))\n    /// );\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(1), None, Some(3)];\n    /// let result = a.par().copied().into_fallible_option().first();\n    /// // depends on whichever is observed first in parallel execution\n    /// assert!(result == Some(Some(1)) || result == None);\n    /// ```\n    fn first(self) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send;\n\n    /// Returns the first (or any) element of the iterator that satisfies the `predicate`.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if a None element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// Note that `find` itself is short-circuiting in addition to fallible computation.\n    /// Therefore, in case the fallible iterator contains both a None and a Some element,\n    /// the result is **not deterministic**:\n    /// * it might be the `None` if it is observed first;\n    /// * or `Some(element)` if the Some element satisfying the predicate is observed first.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Option<i32>> = vec![];\n    /// assert_eq!(\n    ///     a.par().copied().into_fallible_option().find(|x| *x > 2),\n    ///     Some(None)\n    /// );\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(1), Some(2), Some(3)];\n    /// assert_eq!(\n    ///     a.par().copied().into_fallible_option().find(|x| *x > 2),\n    ///     Some(Some(3))\n    /// );\n    ///\n    /// let a: Vec<Option<i32>> = vec![Some(1), None, Some(3)];\n    /// let result = a.par().copied().into_fallible_option().find(|x| *x > 2);\n    /// // depends on whichever is observed first in parallel execution\n    /// assert!(result == Some(Some(3)) || result == None);\n    /// ```\n    fn find<Predicate>(self, predicate: Predicate) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        self.filter(&predicate).first()\n    }\n}\n\npub trait IntoOption<T> {\n    fn into_option(self) -> Option<T>;\n\n    fn into_result_with_unit_err(self) -> Result<T, ()>;\n}\n\nimpl<T> IntoOption<T> for Option<T> {\n    #[inline(always)]\n    fn into_option(self) -> Option<T> {\n        self\n    }\n\n    #[inline(always)]\n    fn into_result_with_unit_err(self) -> Result<T, ()> {\n        match self {\n            Some(x) => Ok(x),\n            None => Err(()),\n        }\n    }\n}\n\npub(crate) trait ResultIntoOption<T> {\n    fn into_option(self) -> Option<T>;\n}\n\nimpl<T> ResultIntoOption<T> for Result<T, ()> {\n    #[inline(always)]\n    fn into_option(self) -> Option<T> {\n        self.ok()\n    }\n}\n"
  },
  {
    "path": "src/par_iter_result.rs",
    "content": "use crate::default_fns::{map_count, reduce_sum, reduce_unit};\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::{ChunkSize, IterationOrder, NumThreads, ParThreadPool, RunnerWithPool, Sum};\nuse crate::{ParCollectInto, ParIter, generic_values::fallible_iterators::ResultOfIter};\nuse core::cmp::Ordering;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\n///\n/// # Examples\n///\n/// To demonstrate the difference of fallible iterator's behavior, consider the following simple example.\n/// We parse a series of strings into integers.\n/// We try this twice:\n/// * in the first one, all inputs are good, hence, we obtain Ok of parsed numbers,\n/// * in the second one, the value in the middle is faulty, we expect the computation to fail.\n///\n/// In the following, we try to achieve this both with a regular parallel iterator ([`ParIter`]) and a fallible\n/// parallel iterator, `ParIterResult` in this case.\n///\n/// You may notice the following differences:\n/// * In the regular iterator, it is not very convenient to keep both the resulting numbers and a potential error.\n///   Here, we make use of `filter_map` and simply ignore the error.\n/// * On the other hand, the `collect` method of the fallible iterator directly returns a `Result` of the computation\n///   which is either Ok of all parsed numbers or the error.\n/// * Also importantly note that the regular iterator will try to parse all the strings, regardless of how many times\n///   the parsing fails.\n/// * Fallible iterator, on the other hand, stops immediately after observing the first error and short circuits the\n///   computation.\n///\n/// ```\n/// use orx_parallel::*;\n/// use std::num::{IntErrorKind, ParseIntError};\n///\n/// let expected_results = [\n///     Ok((0..100).collect::<Vec<_>>()),\n///     Err(IntErrorKind::InvalidDigit),\n/// ];\n///\n/// for expected in expected_results {\n///     let expected_ok = expected.is_ok();\n///     let mut inputs: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///     if !expected_ok {\n///         inputs.insert(50, \"x\".to_string()); // plant an error case\n///     }\n///\n///     // regular parallel iterator\n///     let results = inputs.par().map(|x| x.parse::<u32>());\n///     let numbers: Vec<_> = results.filter_map(|x| x.ok()).collect();\n///     if expected_ok {\n///         assert_eq!(&expected, &Ok(numbers));\n///     } else {\n///         // we lost the error\n///     }\n///\n///     // fallible parallel iterator\n///     let results = inputs.par().map(|x| x.parse::<u32>());\n///     let result: Result<Vec<_>, ParseIntError> = results.into_fallible_result().collect();\n///     assert_eq!(&expected, &result.map_err(|x| x.kind().clone()));\n/// }\n/// ```\n///\n/// These differences are not specific to `collect`; all fallible iterator methods return a result.\n/// The following demonstrate reduction examples, where the result is either the reduced value if the entire computation\n/// succeeds, or the error.\n///\n/// ```\n/// use orx_parallel::*;\n/// use std::num::ParseIntError;\n///\n/// for will_fail in [false, true] {\n///     let mut inputs: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///     if will_fail {\n///         inputs.insert(50, \"x\".to_string()); // plant an error case\n///     }\n///\n///     // sum\n///     let results = inputs.par().map(|x| x.parse::<u32>());\n///     let result: Result<u32, ParseIntError> = results.into_fallible_result().sum();\n///     match will_fail {\n///         true => assert!(result.is_err()),\n///         false => assert_eq!(result, Ok(4950)),\n///     }\n///\n///     // max\n///     let results = inputs.par().map(|x| x.parse::<u32>());\n///     let result: Result<Option<u32>, ParseIntError> = results.into_fallible_result().max();\n///     match will_fail {\n///         true => assert!(result.is_err()),\n///         false => assert_eq!(result, Ok(Some(99))),\n///     }\n/// }\n/// ```\n///\n/// Finally, similar to regular iterators, a fallible parallel iterator can be tranformed using iterator methods.\n/// However, the transformation is on the success path, the error case always short circuits and returns the error.\n/// Notice in the following example that the success type keeps changing through transformations while the error type\n/// remains the same.\n///\n/// ```\n/// use orx_parallel::*;\n/// use std::num::ParseIntError;\n///\n/// for will_fail in [false, true] {\n///     let mut inputs: Vec<_> = (0..100).map(|x| x.to_string()).collect();\n///     if will_fail {\n///         inputs.insert(50, \"x\".to_string()); // plant an error case\n///     }\n///\n///     // fallible iter\n///     let results = inputs.par().map(|x| x.parse::<u32>());\n///     let fallible = results.into_fallible_result();              // Ok: u32, Error: ParseIntError\n///\n///     // transformations\n///\n///     let result: Result<usize, ParseIntError> = fallible\n///         .filter(|x| x % 2 == 1)                                 // Ok: u32, Error: ParseIntError\n///         .map(|x| 3 * x)                                         // Ok: u32, Error: ParseIntError\n///         .filter_map(|x| (x % 10 != 0).then_some(x))             // Ok: u32, Error: ParseIntError\n///         .flat_map(|x| [x.to_string(), (10 * x).to_string()])    // Ok: String, Error: ParseIntError\n///         .map(|x| x.len())                                       // Ok: usize, Error: ParseIntError\n///         .sum();\n///\n///     match will_fail {\n///         true => assert!(result.is_err()),\n///         false => assert_eq!(result, Ok(312)),\n///     }\n/// }\n/// ```\n///\n/// [`ParIter`]: crate::ParIter\npub trait ParIterResult<R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n{\n    /// Type of the Ok element, to be received as the Ok variant iff the entire computation succeeds.\n    type Item;\n\n    /// Type of the Err element, to be received if any of the computations fails.\n    type Err;\n\n    /// Element type of the regular parallel iterator this fallible iterator can be converted to, simply `Result<Self::Ok, Self::Err>`.\n    type RegularItem: IntoResult<Self::Item, Self::Err>;\n\n    /// Regular parallel iterator this fallible iterator can be converted into.\n    type RegularParIter: ParIter<R, Item = Self::RegularItem>;\n\n    /// Returns a reference to the input concurrent iterator.\n    fn con_iter_len(&self) -> Option<usize>;\n\n    /// Converts this fallible iterator into a regular parallel iterator; i.e., [`ParIter`], with `Item = Result<Self::Ok, Self::Err>`.\n    fn into_regular_par(self) -> Self::RegularParIter;\n\n    /// Converts the `regular_par` iterator with `Item = Result<Self::Ok, Self::Err>` into fallible result iterator.\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self;\n\n    // params transformations\n\n    /// Sets the number of threads to be used in the parallel execution.\n    /// Integers can be used as the argument with the following mapping:\n    ///\n    /// * `0` -> `NumThreads::Auto`\n    /// * `1` -> `NumThreads::sequential()`\n    /// * `n > 0` -> `NumThreads::Max(n)`\n    ///\n    /// See [`NumThreads`] and [`ParIter::num_threads`] for details.\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self\n    where\n        Self: Sized,\n    {\n        Self::from_regular_par(self.into_regular_par().num_threads(num_threads))\n    }\n\n    /// Sets the number of elements to be pulled from the concurrent iterator during the\n    /// parallel execution. When integers are used as argument, the following mapping applies:\n    ///\n    /// * `0` -> `ChunkSize::Auto`\n    /// * `n > 0` -> `ChunkSize::Exact(n)`\n    ///\n    /// Please use the default enum constructor for creating `ChunkSize::Min` variant.\n    ///\n    /// See [`ChunkSize`] and [`ParIter::chunk_size`] for details.\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self\n    where\n        Self: Sized,\n    {\n        Self::from_regular_par(self.into_regular_par().chunk_size(chunk_size))\n    }\n\n    /// Sets the iteration order of the parallel computation.\n    ///\n    /// See [`IterationOrder`] and [`ParIter::iteration_order`] for details.\n    fn iteration_order(self, order: IterationOrder) -> Self\n    where\n        Self: Sized,\n    {\n        Self::from_regular_par(self.into_regular_par().iteration_order(order))\n    }\n\n    /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].\n    ///\n    /// See [`ParIter::with_runner`] for details.\n    ///\n    /// [`DefaultRunner`]: crate::DefaultRunner\n    /// [`ParIter::with_runner`]: crate::ParIter::with_runner\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResult<Q, Item = Self::Item, Err = Self::Err>;\n\n    /// Rather than [`DefaultPool`], uses the parallel runner with the given `pool` implementing\n    /// [`ParThreadPool`].\n    ///\n    /// See [`ParIter::with_pool`] for details.\n    ///\n    /// [`DefaultPool`]: crate::DefaultPool\n    /// [`ParIter::with_pool`]: crate::ParIter::with_pool\n    fn with_pool<P: ParThreadPool>(\n        self,\n        pool: P,\n    ) -> impl ParIterResult<RunnerWithPool<P, R::Executor>, Item = Self::Item, Err = Self::Err>\n    where\n        Self: Sized,\n    {\n        let runner = RunnerWithPool::from(pool).with_executor::<R::Executor>();\n        self.with_runner(runner)\n    }\n\n    // computation transformations\n\n    /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Ok` variant.\n    /// Any observation of an `Err` case short-circuits the computation and immediately returns the observed error.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Result<u32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// let iter = a.into_par().into_fallible_result().map(|x| 2 * x);\n    ///\n    /// let b: Result<Vec<_>, _> = iter.collect();\n    /// assert_eq!(b, Ok(vec![2, 4, 6]));\n    ///\n    /// // at least one fails\n    /// let a = vec![Ok(1), Err('x'), Ok(3)];\n    /// let iter = a.into_par().into_fallible_result().map(|x| 2 * x);\n    ///\n    /// let b: Result<Vec<_>, _> = iter.collect();\n    /// assert_eq!(b, Err('x'));\n    /// ```\n    fn map<Out, Map>(self, map: Map) -> impl ParIterResult<R, Item = Out, Err = Self::Err>\n    where\n        Self: Sized,\n        Map: Fn(Self::Item) -> Out + Sync + Clone,\n        Out: Send,\n    {\n        let par = self.into_regular_par();\n        let map = par.map(move |x| x.into_result().map(map.clone()));\n        map.into_fallible_result()\n    }\n\n    /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Ok` variant.\n    /// Any observation of an `Err` case short-circuits the computation and immediately returns the observed error.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Result<u32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// let iter = a.into_par().into_fallible_result().filter(|x| x % 2 == 1);\n    ///\n    /// let b = iter.sum();\n    /// assert_eq!(b, Ok(1 + 3));\n    ///\n    /// // at least one fails\n    /// let a = vec![Ok(1), Err('x'), Ok(3)];\n    /// let iter = a.into_par().into_fallible_result().filter(|x| x % 2 == 1);\n    ///\n    /// let b = iter.sum();\n    /// assert_eq!(b, Err('x'));\n    /// ```\n    fn filter<Filter>(\n        self,\n        filter: Filter,\n    ) -> impl ParIterResult<R, Item = Self::Item, Err = Self::Err>\n    where\n        Self: Sized,\n        Filter: Fn(&Self::Item) -> bool + Sync + Clone,\n        Self::Item: Send,\n    {\n        let par = self.into_regular_par();\n        let filter_map = par.filter_map(move |x| match x.into_result() {\n            Ok(x) => match filter(&x) {\n                true => Some(Ok(x)),\n                false => None,\n            },\n            Err(e) => Some(Err(e)),\n        });\n        filter_map.into_fallible_result()\n    }\n\n    /// Creates an iterator that works like map, but flattens nested structure.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Ok` variant.\n    /// Any observation of an `Err` case short-circuits the computation and immediately returns the observed error.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let words: Vec<Result<&str, char>> = vec![Ok(\"alpha\"), Ok(\"beta\"), Ok(\"gamma\")];\n    ///\n    /// let all_chars: Result<Vec<_>, _> = words\n    ///     .into_par()\n    ///     .into_fallible_result()\n    ///     .flat_map(|s| s.chars()) // chars() returns an iterator\n    ///     .collect();\n    ///\n    /// let merged: Result<String, _> = all_chars.map(|chars| chars.iter().collect());\n    /// assert_eq!(merged, Ok(\"alphabetagamma\".to_string()));\n    ///\n    /// // at least one fails\n    /// let words: Vec<Result<&str, char>> = vec![Ok(\"alpha\"), Ok(\"beta\"), Err('x'), Ok(\"gamma\")];\n    ///\n    /// let all_chars: Result<Vec<_>, _> = words\n    ///     .into_par()\n    ///     .into_fallible_result()\n    ///     .flat_map(|s| s.chars()) // chars() returns an iterator\n    ///     .collect();\n    ///\n    /// let merged: Result<String, _> = all_chars.map(|chars| chars.iter().collect());\n    /// assert_eq!(merged, Err('x'));\n    /// ```\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterResult<R, Item = IOut::Item, Err = Self::Err>\n    where\n        Self: Sized,\n        IOut: IntoIterator,\n        IOut::Item: Send,\n        FlatMap: Fn(Self::Item) -> IOut + Sync + Clone,\n    {\n        let par = self.into_regular_par();\n        let map = par.flat_map(move |x| match x.into_result() {\n            Ok(x) => ResultOfIter::ok(flat_map(x).into_iter()),\n            Err(e) => ResultOfIter::err(e),\n        });\n        map.into_fallible_result()\n    }\n\n    /// Creates an iterator that both filters and maps.\n    ///\n    /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.\n    ///\n    /// `filter_map` can be used to make chains of `filter` and `map` more concise.\n    /// The example below shows how a `map().filter().map()` can be shortened to a single call to `filter_map`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Result<&str, char>> = vec![Ok(\"1\"), Ok(\"two\"), Ok(\"NaN\"), Ok(\"four\"), Ok(\"5\")];\n    ///\n    /// let numbers: Result<Vec<_>, char> = a\n    ///     .into_par()\n    ///     .into_fallible_result()\n    ///     .filter_map(|s| s.parse::<usize>().ok())\n    ///     .collect();\n    ///\n    /// assert_eq!(numbers, Ok(vec![1, 5]));\n    ///\n    /// // at least one fails\n    /// let a: Vec<Result<&str, char>> = vec![Ok(\"1\"), Ok(\"two\"), Err('x'), Ok(\"four\"), Ok(\"5\")];\n    ///\n    /// let numbers: Result<Vec<_>, char> = a\n    ///     .into_par()\n    ///     .into_fallible_result()\n    ///     .filter_map(|s| s.parse::<usize>().ok())\n    ///     .collect();\n    ///\n    /// assert_eq!(numbers, Err('x'));\n    /// ```\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterResult<R, Item = Out, Err = Self::Err>\n    where\n        Self: Sized,\n        FilterMap: Fn(Self::Item) -> Option<Out> + Sync + Clone,\n        Out: Send,\n    {\n        let par = self.into_regular_par();\n        let filter_map = par.filter_map(move |x| match x.into_result() {\n            Ok(x) => filter_map(x).map(|x| Ok(x)),\n            Err(e) => Some(Err(e)),\n        });\n        filter_map.into_fallible_result()\n    }\n\n    /// Does something with each successful element of an iterator, passing the value on, provided that all elements are of Ok variant;\n    /// short-circuits and returns the error otherwise.\n    ///\n    /// When using iterators, you’ll often chain several of them together.\n    /// While working on such code, you might want to check out what’s happening at various parts in the pipeline.\n    /// To do that, insert a call to `inspect()`.\n    ///\n    /// It’s more common for `inspect()` to be used as a debugging tool than to exist in your final code,\n    /// but applications may find it useful in certain situations when errors need to be logged before being discarded.\n    ///\n    /// It is often convenient to use thread-safe collections such as [`ConcurrentBag`] and\n    /// [`ConcurrentVec`](https://crates.io/crates/orx-concurrent-vec) to\n    /// collect some intermediate values during parallel execution for further inspection.\n    /// The following example demonstrates such a use case.\n    ///\n    /// [`ConcurrentBag`]: orx_concurrent_bag::ConcurrentBag\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use orx_concurrent_bag::*;\n    /// use std::num::ParseIntError;\n    ///\n    /// // all succeeds\n    /// let a: Vec<Result<u32, ParseIntError>> = [\"1\", \"4\", \"2\", \"3\"]\n    ///     .into_iter()\n    ///     .map(|x| x.parse::<u32>())\n    ///     .collect();\n    ///\n    /// // let's add some inspect() calls to investigate what's happening\n    /// // - log some events\n    /// // - use a concurrent bag to collect and investigate numbers contributing to the sum\n    /// let bag = ConcurrentBag::new();\n    ///\n    /// let sum = a\n    ///     .par()\n    ///     .cloned()\n    ///     .into_fallible_result()\n    ///     .inspect(|x| println!(\"about to filter: {x}\"))\n    ///     .filter(|x| x % 2 == 0)\n    ///     .inspect(|x| {\n    ///         bag.push(*x);\n    ///         println!(\"made it through filter: {x}\");\n    ///     })\n    ///     .sum();\n    /// assert_eq!(sum, Ok(4 + 2));\n    ///\n    /// let mut values_made_through = bag.into_inner();\n    /// values_made_through.sort();\n    /// assert_eq!(values_made_through, [2, 4]);\n    ///\n    /// // at least one fails\n    /// let a: Vec<Result<u32, ParseIntError>> = [\"1\", \"4\", \"x\", \"3\"]\n    ///     .into_iter()\n    ///     .map(|x| x.parse::<u32>())\n    ///     .collect();\n    ///\n    /// // let's add some inspect() calls to investigate what's happening\n    /// // - log some events\n    /// // - use a concurrent bag to collect and investigate numbers contributing to the sum\n    /// let bag = ConcurrentBag::new();\n    ///\n    /// let sum = a\n    ///     .par()\n    ///     .cloned()\n    ///     .into_fallible_result()\n    ///     .inspect(|x| println!(\"about to filter: {x}\"))\n    ///     .filter(|x| x % 2 == 0)\n    ///     .inspect(|x| {\n    ///         bag.push(*x);\n    ///         println!(\"made it through filter: {x}\");\n    ///     })\n    ///     .sum();\n    /// assert!(sum.is_err());\n    /// ```\n    fn inspect<Operation>(\n        self,\n        operation: Operation,\n    ) -> impl ParIterResult<R, Item = Self::Item, Err = Self::Err>\n    where\n        Self: Sized,\n        Operation: Fn(&Self::Item) + Sync + Clone,\n        Self::Item: Send,\n    {\n        let map = move |x| {\n            operation(&x);\n            x\n        };\n        self.map(map)\n    }\n\n    // collect\n\n    /// Collects all the items from an iterator into a collection iff all elements are of Ok variant.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// This is useful when you already have a collection and want to add the iterator items to it.\n    ///\n    /// The collection is passed in as owned value, and returned back with the additional elements.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let vec: Vec<i32> = vec![0, 1];\n    ///\n    /// // all succeeds\n    /// let result = [\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 10)\n    ///     .collect_into(vec);\n    ///\n    /// assert!(result.is_ok());\n    /// let vec = result.unwrap();\n    /// assert_eq!(vec, vec![0, 1, 10, 20, 30]);\n    ///\n    /// // at least one fails\n    ///\n    /// let result = [\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 10)\n    ///     .collect_into(vec);\n    /// assert!(result.is_err());\n    /// ```\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send;\n\n    /// Transforms an iterator into a collection iff all elements are of Ok variant.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Similar to [`Iterator::collect`], the type annotation on the left-hand-side determines\n    /// the type of the result collection; or turbofish annotation can be used.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all succeeds\n    ///\n    /// let result_doubled: Result<Vec<i32>, _> = [\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 2)\n    ///     .collect();\n    ///\n    /// assert_eq!(result_doubled, Ok(vec![2, 4, 6]));\n    ///\n    /// // at least one fails\n    ///\n    /// let result_doubled: Result<Vec<i32>, _> = [\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 2)\n    ///     .collect();\n    ///\n    /// assert!(result_doubled.is_err());\n    /// ```\n    fn collect<C>(self) -> Result<C, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        C: ParCollectInto<Self::Item>,\n    {\n        let output = C::empty(self.con_iter_len());\n        self.collect_into(output)\n    }\n\n    // reduce\n\n    /// Reduces the elements to a single one, by repeatedly applying a reducing operation.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// If the iterator is empty, returns `Ok(None)`; otherwise, returns `Ok` of result of the reduction.\n    ///\n    /// The `reduce` function is a closure with two arguments: an ‘accumulator’, and an element.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// fn safe_div(a: u32, b: u32) -> Result<u32, char> {\n    ///     match b {\n    ///         0 => Err('!'),\n    ///         b => Ok(a / b),\n    ///     }\n    /// }\n    ///\n    /// // all succeeds\n    /// let reduced: Result<Option<u32>, char> = (1..10)\n    ///     .par()\n    ///     .map(|x| safe_div(100, x as u32))\n    ///     .into_fallible_result()\n    ///     .reduce(|acc, e| acc + e);\n    /// assert_eq!(reduced, Ok(Some(281)));\n    ///\n    /// // all succeeds - empty iterator\n    /// let reduced: Result<Option<u32>, char> = (1..1)\n    ///     .par()\n    ///     .map(|x| safe_div(100, x as u32))\n    ///     .into_fallible_result()\n    ///     .reduce(|acc, e| acc + e);\n    /// assert_eq!(reduced, Ok(None));\n    ///\n    /// // at least one fails\n    /// let reduced: Result<Option<u32>, char> = (0..10)\n    ///     .par()\n    ///     .map(|x| safe_div(100, x as u32))\n    ///     .into_fallible_result()\n    ///     .reduce(|acc, e| acc + e);\n    /// assert_eq!(reduced, Err('!'));\n    /// ```\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(Self::Item, Self::Item) -> Self::Item + Sync;\n\n    /// Tests if every element of the iterator matches a predicate.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// `all` takes a `predicate` that returns true or false.\n    /// It applies this closure to each Ok element of the iterator,\n    /// and if they all return true, then so does `all`.\n    /// If any of them returns false, it returns false.\n    ///\n    /// Note that `all` computation is itself also short-circuiting; in other words, it will stop processing as soon as it finds a false,\n    /// given that no matter what else happens, the result will also be false.\n    ///\n    /// Therefore, in case the fallible iterator contains both an Err element and an Ok element which violates the `predicate`,\n    /// the result is **not deterministic**. It might be the `Err` if it is observed first; or `Ok(false)` if the violation is observed first.\n    ///\n    /// On the other hand, when it returns `Ok(true)`, we are certain that all elements are of `Ok` variant and all satisfy the `predicate`.\n    ///\n    /// An empty iterator returns `Ok(true)`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all Ok\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .all(|x| *x > 0);\n    /// assert_eq!(result, Ok(true));\n    ///\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .all(|x| *x > 1);\n    /// assert_eq!(result, Ok(false));\n    ///\n    /// let result = Vec::<&str>::new()\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .all(|x| *x > 1);\n    /// assert_eq!(result, Ok(true)); // empty iterator\n    ///\n    /// // at least one Err\n    /// let result = vec![\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .all(|x| *x > 0);\n    /// assert!(result.is_err());\n    /// ```\n    fn all<Predicate>(self, predicate: Predicate) -> Result<bool, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        let violates = |x: &Self::Item| !predicate(x);\n        self.find(violates).map(|x| x.is_none())\n    }\n\n    /// Tests if any element of the iterator matches a predicate.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// `any` takes a `predicate` that returns true or false.\n    /// It applies this closure to each element of the iterator,\n    /// and if any of the elements returns true, then so does `any`.\n    /// If all of them return false, it returns false.\n    ///\n    /// Note that `any` computation is itself also short-circuiting; in other words, it will stop processing as soon as it finds a true,\n    /// given that no matter what else happens, the result will also be true.\n    ///\n    /// Therefore, in case the fallible iterator contains both an Err element and an Ok element which satisfies the `predicate`,\n    /// the result is **not deterministic**. It might be the `Err` if it is observed first; or `Ok(true)` if element satisfying the predicate\n    /// is observed first.\n    ///\n    /// On the other hand, when it returns `Ok(false)`, we are certain that all elements are of `Ok` variant and none of them satisfies the `predicate`.\n    ///\n    /// An empty iterator returns `Ok(false)`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all Ok\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .any(|x| *x > 1);\n    /// assert_eq!(result, Ok(true));\n    ///\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .any(|x| *x > 3);\n    /// assert_eq!(result, Ok(false));\n    ///\n    /// let result = Vec::<&str>::new()\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .any(|x| *x > 1);\n    /// assert_eq!(result, Ok(false)); // empty iterator\n    ///\n    /// // at least one Err\n    /// let result = vec![\"1\", \"x!\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .any(|x| *x > 5);\n    /// assert!(result.is_err());\n    /// ```\n    fn any<Predicate>(self, predicate: Predicate) -> Result<bool, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        self.find(predicate).map(|x| x.is_some())\n    }\n\n    /// Consumes the iterator, counting the number of iterations and returning it.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // all Ok\n    /// let result = vec![\"1\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .filter(|x| *x >= 2)\n    ///     .count();\n    /// assert_eq!(result, Ok(2));\n    ///\n    /// // at least one Err\n    /// let result = vec![\"x!\", \"2\", \"3\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .filter(|x| *x >= 2)\n    ///     .count();\n    /// assert!(result.is_err());\n    /// ```\n    fn count(self) -> Result<usize, Self::Err>\n    where\n        Self: Sized,\n        Self::Err: Send,\n    {\n        self.map(map_count)\n            .reduce(reduce_sum)\n            .map(|x| x.unwrap_or(0))\n    }\n\n    /// Calls a closure on each element of an iterator, and returns `Ok(())` if all elements succeed.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// # Examples\n    ///\n    /// Basic usage:\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    /// use std::sync::mpsc::channel;\n    ///\n    /// // all Ok\n    /// let (tx, rx) = channel();\n    /// let result = vec![\"0\", \"1\", \"2\", \"3\", \"4\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 2 + 1)\n    ///     .for_each(move |x| tx.send(x).unwrap());\n    ///\n    /// assert_eq!(result, Ok(()));\n    ///\n    /// let mut v: Vec<_> = rx.iter().collect();\n    /// v.sort(); // order can be mixed, since messages will be sent in parallel\n    /// assert_eq!(v, vec![1, 3, 5, 7, 9]);\n    ///\n    /// // at least one Err\n    /// let (tx, _rx) = channel();\n    /// let result = vec![\"0\", \"1\", \"2\", \"x!\", \"4\"]\n    ///     .into_par()\n    ///     .map(|x| x.parse::<i32>())\n    ///     .into_fallible_result()\n    ///     .map(|x| x * 2 + 1)\n    ///     .for_each(move |x| tx.send(x).unwrap());\n    ///\n    /// assert!(result.is_err());\n    /// ```\n    fn for_each<Operation>(self, operation: Operation) -> Result<(), Self::Err>\n    where\n        Self: Sized,\n        Self::Err: Send,\n        Operation: Fn(Self::Item) + Sync,\n    {\n        let map = |x| operation(x);\n        self.map(map).reduce(reduce_unit).map(|_| ())\n    }\n\n    /// Returns Ok of maximum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// assert_eq!(a.par().copied().into_fallible_result().max(), Ok(Some(3)));\n    ///\n    /// let b: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(b.par().copied().into_fallible_result().max(), Ok(None));\n    ///\n    /// let c: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Err('x')];\n    /// assert_eq!(c.par().copied().into_fallible_result().max(), Err('x'));\n    /// ```\n    fn max(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Err: Send,\n        Self::Item: Ord + Send,\n    {\n        self.reduce(Ord::max)\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .max_by(|a, b| a.cmp(b)),\n    ///     Ok(Some(3))\n    /// );\n    ///\n    /// let b: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .max_by(|a, b| a.cmp(b)),\n    ///     Ok(None)\n    /// );\n    ///\n    /// let c: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Err('x')];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .max_by(|a, b| a.cmp(b)),\n    ///     Err('x')\n    /// );\n    /// ```\n    fn max_by<Compare>(self, compare: Compare) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |x, y| match compare(&x, &y) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the maximum value from the specified function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(-1), Ok(2), Ok(-3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .max_by_key(|x| x.abs()),\n    ///     Ok(Some(-3))\n    /// );\n    ///\n    /// let b: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .max_by_key(|x| x.abs()),\n    ///     Ok(None)\n    /// );\n    ///\n    /// let c: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Err('x')];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .max_by_key(|x| x.abs()),\n    ///     Err('x')\n    /// );\n    /// ```\n    fn max_by_key<Key, GetKey>(self, key: GetKey) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |x, y| match key(&x).cmp(&key(&y)) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns Ok of minimum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// assert_eq!(a.par().copied().into_fallible_result().min(), Ok(Some(1)));\n    ///\n    /// let b: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(b.par().copied().into_fallible_result().min(), Ok(None));\n    ///\n    /// let c: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Err('x')];\n    /// assert_eq!(c.par().copied().into_fallible_result().min(), Err('x'));\n    /// ```\n    fn min(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Ord + Send,\n        Self::Err: Send,\n    {\n        self.reduce(Ord::min)\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .min_by(|a, b| a.cmp(b)),\n    ///     Ok(Some(1))\n    /// );\n    ///\n    /// let b: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .min_by(|a, b| a.cmp(b)),\n    ///     Ok(None)\n    /// );\n    ///\n    /// let c: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Err('x')];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .min_by(|a, b| a.cmp(b)),\n    ///     Err('x')\n    /// );\n    /// ```\n    fn min_by<Compare>(self, compare: Compare) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |x, y| match compare(&x, &y) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the minimum value from the specified function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(-1), Ok(2), Ok(-3)];\n    /// assert_eq!(\n    ///     a.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .min_by_key(|x| x.abs()),\n    ///     Ok(Some(-1))\n    /// );\n    ///\n    /// let b: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(\n    ///     b.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .min_by_key(|x| x.abs()),\n    ///     Ok(None)\n    /// );\n    ///\n    /// let c: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Err('x')];\n    /// assert_eq!(\n    ///     c.par()\n    ///         .copied()\n    ///         .into_fallible_result()\n    ///         .min_by_key(|x| x.abs()),\n    ///     Err('x')\n    /// );\n    /// ```\n    fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |x, y| match get_key(&x).cmp(&get_key(&y)) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Sums the elements of an iterator.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// If the iterator is empty, returns zero; otherwise, returns `Ok` of the sum.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// fn safe_div(a: u32, b: u32) -> Result<u32, char> {\n    ///     match b {\n    ///         0 => Err('!'),\n    ///         b => Ok(a / b),\n    ///     }\n    /// }\n    ///\n    /// // all succeeds\n    /// let reduced: Result<u32, char> = (1..10)\n    ///     .par()\n    ///     .map(|x| safe_div(100, x as u32))\n    ///     .into_fallible_result()\n    ///     .sum();\n    /// assert_eq!(reduced, Ok(281));\n    ///\n    /// // all succeeds - empty iterator\n    /// let reduced: Result<u32, char> = (1..1)\n    ///     .par()\n    ///     .map(|x| safe_div(100, x as u32))\n    ///     .into_fallible_result()\n    ///     .sum();\n    /// assert_eq!(reduced, Ok(0));\n    ///\n    /// // at least one fails\n    /// let reduced: Result<u32, char> = (0..10)\n    ///     .par()\n    ///     .map(|x| safe_div(100, x as u32))\n    ///     .into_fallible_result()\n    ///     .sum();\n    /// assert_eq!(reduced, Err('!'));\n    /// ```\n    fn sum<Out>(self) -> Result<Out, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Sum<Out>,\n        Self::Err: Send,\n        Out: Send,\n    {\n        self.map(Self::Item::map)\n            .reduce(Self::Item::reduce)\n            .map(|x| x.unwrap_or(Self::Item::zero()))\n    }\n\n    // early exit\n\n    /// Returns the first (or any) element of the iterator.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if an Err element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// Note that `find` itself is short-circuiting in addition to fallible computation.\n    /// Therefore, in case the fallible iterator contains both an Err and an Ok element,\n    /// the result is **not deterministic**:\n    /// * it might be the `Err` if it is observed first;\n    /// * or `Ok(element)` if the Ok element is observed first.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(a.par().copied().into_fallible_result().first(), Ok(None));\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// assert_eq!(a.par().copied().into_fallible_result().first(), Ok(Some(1)));\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Err('x'), Ok(3)];\n    /// let result = a.par().copied().into_fallible_result().first();\n    /// // depends on whichever is observed first in parallel execution\n    /// assert!(result == Ok(Some(1)) || result == Err('x'));\n    /// ```\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send;\n\n    /// Returns the first (or any) element of the iterator that satisfies the `predicate`.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if an Err element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// Note that `find` itself is short-circuiting in addition to fallible computation.\n    /// Therefore, in case the fallible iterator contains both an Err and an Ok element,\n    /// the result is **not deterministic**:\n    /// * it might be the `Err` if it is observed first;\n    /// * or `Ok(element)` if the Ok element satisfying the predicate is observed first.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![];\n    /// assert_eq!(\n    ///     a.par().copied().into_fallible_result().find(|x| *x > 2),\n    ///     Ok(None)\n    /// );\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Ok(2), Ok(3)];\n    /// assert_eq!(\n    ///     a.par().copied().into_fallible_result().find(|x| *x > 2),\n    ///     Ok(Some(3))\n    /// );\n    ///\n    /// let a: Vec<Result<i32, char>> = vec![Ok(1), Err('x'), Ok(3)];\n    /// let result = a.par().copied().into_fallible_result().find(|x| *x > 2);\n    /// // depends on whichever is observed first in parallel execution\n    /// assert!(result == Ok(Some(3)) || result == Err('x'));\n    /// ```\n    fn find<Predicate>(self, predicate: Predicate) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Predicate: Fn(&Self::Item) -> bool + Sync,\n    {\n        self.filter(&predicate).first()\n    }\n}\n\npub trait IntoResult<T, E> {\n    fn into_result(self) -> Result<T, E>;\n}\n\nimpl<T, E> IntoResult<T, E> for Result<T, E> {\n    #[inline(always)]\n    fn into_result(self) -> Result<T, E> {\n        self\n    }\n}\n"
  },
  {
    "path": "src/par_thread_pool.rs",
    "content": "use crate::{generic_values::runner_results::Fallibility, runner::NumSpawned};\nuse alloc::vec::Vec;\nuse core::num::NonZeroUsize;\nuse orx_concurrent_bag::ConcurrentBag;\n\n/// A thread pool that can be used for parallel computation.\n///\n/// orx_parallel abstracts away the thread pool implementation and can work with different\n/// thread pool implementations.\n///\n/// Parallel computation will not use any threads outside the pool.\n/// Default std thread pool assumes all OS threads are available in the pool.\n///\n/// # Examples\n///\n/// ## Default std pool\n///\n/// **requires std feature**\n///\n/// Default parallel runner spawns scoped threads using `std::thread::scope`.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// let sum = (0..1000).par().sum();\n/// assert_eq!(sum, 1000 * 999 / 2);\n///\n/// // this is equivalent to\n/// let sum = (0..1000).par().with_runner(DefaultRunner::default()).sum();\n/// assert_eq!(sum, 1000 * 999 / 2);\n/// ```\n///\n/// ## Rayon thread pool\n///\n/// **requires rayon feature**\n///\n/// The following example demonstrate using a rayon thread pool as the thread provider of\n/// the parallel computation.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"rayon-core\")]\n/// {\n///     let pool = rayon::ThreadPoolBuilder::new()\n///         .num_threads(4)\n///         .build()\n///         .unwrap();\n///\n///     // creating a runner for the computation\n///     let runner = RunnerWithPool::from(&pool);\n///     let sum = (0..1000).par().with_runner(runner).sum();\n///     assert_eq!(sum, 1000 * 999 / 2);\n///\n///     // or reuse a runner multiple times (identical under the hood)\n///     let mut runner = RunnerWithPool::from(&pool);\n///     let sum = (0..1000).par().with_runner(&mut runner).sum();\n///     assert_eq!(sum, 1000 * 999 / 2);\n/// }\n/// ```\n///\n/// Note that since rayon::ThreadPool::scope only requires a shared reference `&self`,\n/// we can concurrently create as many runners as we want from the same thread pool and use them concurrently.\n///\n/// ## Scoped thread pool\n///\n/// **requires scoped_threadpool feature**\n///\n/// The following example demonstrate using a scoped_threadpool thread pool as the thread provider of\n/// the parallel computation.\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"scoped_threadpool\")]\n/// {\n///     // creating a runner for the computation\n///     let mut pool = scoped_threadpool::Pool::new(4);\n///     let runner = RunnerWithPool::from(&mut pool);\n///     let sum = (0..1000).par().with_runner(runner).sum();\n///     assert_eq!(sum, 1000 * 999 / 2);\n///\n///     // or reuse a runner multiple times (identical under the hood)\n///     let mut pool = scoped_threadpool::Pool::new(4);\n///     let mut runner = RunnerWithPool::from(&mut pool);\n///     let sum = (0..1000).par().with_runner(&mut runner).sum();\n///     assert_eq!(sum, 1000 * 999 / 2);\n/// }\n/// ```\n///\n/// Since scoped_thread_pool::Pool::scoped requires an exclusive reference `&mut self`,\n/// we can create one runner from a pool at a time, note use of `&mut pool` in runner creation.\npub trait ParThreadPool {\n    /// Scope type of the thread pool.\n    type ScopeRef<'s, 'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    /// Executes the `work` within scope `s`.\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env;\n\n    /// Executes the scoped computation `f`.\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(Self::ScopeRef<'s, 'env, 'scope>) + Send;\n\n    /// Returns the maximum number of threads available in the pool.\n    fn max_num_threads(&self) -> NonZeroUsize;\n}\n\n// derived\n\npub trait ParThreadPoolCompute: ParThreadPool {\n    fn map_in_pool<F, S, M, T>(\n        &mut self,\n        do_spawn: S,\n        thread_map: M,\n        max_num_threads: NonZeroUsize,\n    ) -> (NumSpawned, Result<Vec<T>, F::Error>)\n    where\n        F: Fallibility,\n        S: Fn(NumSpawned) -> bool + Sync,\n        M: Fn(NumSpawned) -> Result<T, F::Error> + Sync,\n        T: Send,\n        F::Error: Send,\n    {\n        let thread_map = &thread_map;\n        let mut nt = NumSpawned::zero();\n        let thread_results = ConcurrentBag::with_fixed_capacity(max_num_threads.into());\n        let bag = &thread_results;\n        self.scoped_computation(|s| {\n            while do_spawn(nt) {\n                let num_spawned = nt;\n                nt.increment();\n                let work = move || {\n                    bag.push(thread_map(num_spawned));\n                };\n                Self::run_in_scope(&s, work);\n            }\n        });\n\n        let thread_results: Vec<_> = thread_results.into_inner().into();\n        let result = F::reduce_results(thread_results);\n\n        (nt, result)\n    }\n\n    fn run_in_pool<S, F>(&mut self, do_spawn: S, thread_do: F) -> NumSpawned\n    where\n        S: Fn(NumSpawned) -> bool + Sync,\n        F: Fn(NumSpawned) + Sync,\n    {\n        let thread_do = &thread_do;\n        let mut nt = NumSpawned::zero();\n        self.scoped_computation(|s| {\n            while do_spawn(nt) {\n                let num_spawned = nt;\n                nt.increment();\n                let work = move || thread_do(num_spawned);\n                Self::run_in_scope(&s, work);\n            }\n        });\n        nt\n    }\n}\n\nimpl<X: ParThreadPool> ParThreadPoolCompute for X {}\n"
  },
  {
    "path": "src/parallel_drainable.rs",
    "content": "use crate::{Params, computational_variants::Par, runner::DefaultRunner};\nuse core::ops::RangeBounds;\nuse orx_concurrent_iter::ConcurrentDrainableOverSlice;\n\n/// A type which can create a parallel draining iterator over any of its sub-slices.\n///\n/// * Created draining iterator takes out and returns all elements of the slice defined by the `range`.\n/// * The slice defined by this `range` will be removed from the original collection.\n///\n/// If the iterator is dropped before being fully consumed, it drops the remaining removed elements.\n///\n/// If the complete range is provided (`..` or `0..self.len()`), self will remain empty.\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// let mut v = vec![1, 2, 3];\n/// let u: Vec<_> = v.par_drain(1..).num_threads(2).collect();\n///\n/// assert_eq!(v, &[1]);\n/// assert_eq!(u, &[2, 3]);\n/// ```\npub trait ParallelDrainableOverSlice: ConcurrentDrainableOverSlice {\n    /// Creates a parallel draining iterator over the slice defined by the given `range`.\n    ///\n    /// * Created draining iterator takes out and returns all elements of the slice defined by the `range`.\n    /// * The slice defined by this `range` will be removed from the original collection.\n    ///\n    /// If the iterator is dropped before being fully consumed, it drops the remaining removed elements.\n    ///\n    /// If the complete range is provided (`..` or `0..self.len()`), self will remain empty.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let mut v = vec![1, 2, 3];\n    /// let u: Vec<_> = v.par_drain(1..).num_threads(2).collect();\n    ///\n    /// assert_eq!(v, &[1]);\n    /// assert_eq!(u, &[2, 3]);\n    /// ```\n    fn par_drain<R>(\n        &mut self,\n        range: R,\n    ) -> Par<<Self as ConcurrentDrainableOverSlice>::DrainingIter<'_>, DefaultRunner>\n    where\n        R: RangeBounds<usize>,\n    {\n        Par::new(Default::default(), Params::default(), self.con_drain(range))\n    }\n}\n\nimpl<I> ParallelDrainableOverSlice for I where I: ConcurrentDrainableOverSlice {}\n"
  },
  {
    "path": "src/parallelizable.rs",
    "content": "use crate::{computational_variants::Par, parameters::Params, runner::DefaultRunner};\nuse orx_concurrent_iter::ConcurrentIterable;\n\n/// `Parallelizable` types are those from which parallel iterators can be created\n/// **multiple times** using the [`par`] method, since this method call does not consume the source.\n///\n/// This trait can be considered as the *parallel counterpart* of the [`Iterable`] trait.\n///\n/// Note that every [`ConcurrentIterable`] type automatically implements [`Parallelizable`].\n///\n/// [`par`]: crate::Parallelizable::par\n/// [`Iterable`]: orx_iterable::Iterable\n/// [`ConcurrentIterable`]: orx_concurrent_iter::ConcurrentIterable\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// // Vec<T>: Parallelizable<Item = &T>\n/// let vec = vec![1, 2, 3, 4];\n/// assert_eq!(vec.par().sum(), 10);\n/// assert_eq!(vec.par().max(), Some(&4));\n///\n/// // &[T]: Parallelizable<Item = &T>\n/// let slice = vec.as_slice();\n/// assert_eq!(slice.par().sum(), 10);\n/// assert_eq!(slice.par().max(), Some(&4));\n///\n/// // Range<T>: Parallelizable<Item = T>\n/// let range = 1..5;\n/// assert_eq!(range.par().sum(), 10);\n/// assert_eq!(range.par().max(), Some(4));\n/// ```\npub trait Parallelizable: ConcurrentIterable {\n    /// `Parallelizable` types are those from which parallel iterators can be created\n    /// **multiple times** using the [`par`] method, since this method call does not consume the source.\n    ///\n    /// This trait can be considered as the *parallel counterpart* of the [`Iterable`] trait.\n    ///\n    /// [`par`]: crate::Parallelizable::par\n    /// [`Iterable`]: orx_iterable::Iterable\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // Vec<T>: Parallelizable<Item = &T>\n    /// let vec = vec![1, 2, 3, 4];\n    /// assert_eq!(vec.par().sum(), 10);\n    /// assert_eq!(vec.par().max(), Some(&4));\n    ///\n    /// // &[T]: Parallelizable<Item = &T>\n    /// let slice = vec.as_slice();\n    /// assert_eq!(slice.par().sum(), 10);\n    /// assert_eq!(slice.par().max(), Some(&4));\n    ///\n    /// // Range<T>: Parallelizable<Item = T>\n    /// let range = 1..5;\n    /// assert_eq!(range.par().sum(), 10);\n    /// assert_eq!(range.par().max(), Some(4));\n    /// ```\n    fn par(&self) -> Par<<Self as ConcurrentIterable>::Iter, DefaultRunner> {\n        Par::new(Default::default(), Params::default(), self.con_iter())\n    }\n}\n\nimpl<I> Parallelizable for I where I: ConcurrentIterable {}\n"
  },
  {
    "path": "src/parallelizable_collection.rs",
    "content": "use crate::{Params, computational_variants::Par, runner::DefaultRunner};\nuse orx_concurrent_iter::{ConcurrentCollection, ConcurrentIterable};\n\n/// A type implementing [`ParallelizableCollection`] is a collection owning the elements such that\n///\n/// * if the elements are of type `T`,\n/// * non-consuming [`par`] method can be called **multiple times** to create parallel\n///   iterators; i.e., [`ParIter`], yielding references to the elements `&T`; and\n/// * consuming [`into_par`] method can be called once to create a parallel iterator yielding\n///   owned elements `T`.\n///\n/// This trait can be considered as the *concurrent counterpart* of the [`Collection`] trait.\n///\n/// Note that every [`ConcurrentCollection`] type automatically implements [`ParallelizableCollection`].\n///\n/// [`Collection`]: orx_iterable::Collection\n/// [`ConcurrentCollection`]: orx_concurrent_iter::ConcurrentCollection\n/// [`par`]: crate::ParallelizableCollection::par\n/// [`into_par`]: crate::IntoParIter::into_par\n/// [`ParIter`]: crate::ParIter\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// // Vec<T>: ParallelizableCollection<Item = T>\n/// let vec = vec![1, 2, 3, 4];\n///\n/// // non-consuming iteration over references\n/// assert_eq!(vec.par().sum(), 10);\n/// assert_eq!(vec.par().min(), Some(&1));\n/// assert_eq!(vec.par().max(), Some(&4));\n///\n/// // consuming iteration over owned values\n/// assert_eq!(vec.into_par().max(), Some(4));\n/// ```\npub trait ParallelizableCollection: ConcurrentCollection {\n    /// A type implementing [`ParallelizableCollection`] is a collection owning the elements such that\n    ///\n    /// * if the elements are of type `T`,\n    /// * non-consuming [`par`] method can be called **multiple times** to create parallel\n    ///   iterators; i.e., [`ParIter`], yielding references to the elements `&T`; and\n    /// * consuming [`into_par`] method can be called once to create a parallel iterator yielding\n    ///   owned elements `T`.\n    ///\n    /// This trait can be considered as the *concurrent counterpart* of the [`Collection`] trait.\n    ///\n    /// Note that every [`ConcurrentCollection`] type automatically implements [`ParallelizableCollection`].\n    ///\n    /// [`con_iter`]: orx_concurrent_iter::ConcurrentCollection::con_iter\n    /// [`Collection`]: orx_iterable::Collection\n    /// [`ConcurrentIter`]: orx_concurrent_iter::ConcurrentIter\n    /// [`par`]: crate::ParallelizableCollection::par\n    /// [`into_par`]: crate::IntoParIter::into_par\n    /// [`ParIter`]: crate::ParIter\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // Vec<T>: ParallelizableCollection<Item = T>\n    /// let vec = vec![1, 2, 3, 4];\n    ///\n    /// // non-consuming iteration over references\n    /// assert_eq!(vec.par().sum(), 10);\n    /// assert_eq!(vec.par().min(), Some(&1));\n    /// assert_eq!(vec.par().max(), Some(&4));\n    ///\n    /// // consuming iteration over owned values\n    /// assert_eq!(vec.into_par().max(), Some(4));\n    /// ```\n    fn par(\n        &self,\n    ) -> Par<\n        <<Self as ConcurrentCollection>::Iterable<'_> as ConcurrentIterable>::Iter,\n        DefaultRunner,\n    > {\n        Par::new(Default::default(), Params::default(), self.con_iter())\n    }\n}\n\nimpl<X> ParallelizableCollection for X where X: ConcurrentCollection {}\n"
  },
  {
    "path": "src/parallelizable_collection_mut.rs",
    "content": "use crate::{\n    ParIter, ParallelizableCollection, Params, computational_variants::Par, runner::DefaultRunner,\n};\nuse orx_concurrent_iter::ConcurrentCollectionMut;\n\n/// A type implementing [`ParallelizableCollectionMut`] is a collection owning the elements such that\n///\n/// * if the elements are of type `T`,\n/// * non-consuming [`par`] method can be called **multiple times** to create parallel\n///   iterators; i.e., [`ParIter`], yielding references to the elements `&T`; and\n/// * non-consuming [`par_mut`] method can be called **multiple times** to create parallel\n///   iterators yielding mutable references to the elements `&mut T`; and\n/// * consuming [`into_par`] method can be called once to create a parallel iterator yielding\n///   owned elements `T`.\n///\n/// This trait can be considered as the *concurrent counterpart* of the [`CollectionMut`] trait.\n///\n/// Note that every [`ConcurrentCollectionMut`] type automatically implements [`ParallelizableCollectionMut`].\n///\n/// [`CollectionMut`]: orx_iterable::CollectionMut\n/// [`ConcurrentCollectionMut`]: orx_concurrent_iter::ConcurrentCollectionMut\n/// [`par`]: crate::ParallelizableCollection::par\n/// [`par_mut`]: crate::ParallelizableCollectionMut::par_mut\n/// [`into_par`]: crate::IntoParIter::into_par\n/// [`ParIter`]: crate::ParIter\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// // Vec<T>: ParallelizableCollectionMut<Item = T>\n/// let mut vec = vec![1, 2, 3, 4];\n///\n/// // non-consuming iteration over references\n/// assert_eq!(vec.par().sum(), 10);\n/// assert_eq!(vec.par().min(), Some(&1));\n/// assert_eq!(vec.par().max(), Some(&4));\n///\n/// // non-consuming mutable iteration\n/// vec.par_mut().filter(|x| **x >= 3).for_each(|x| *x += 10);\n/// assert_eq!(&vec, &[1, 2, 13, 14]);\n///\n/// // consuming iteration over owned values\n/// assert_eq!(vec.into_par().max(), Some(14));\n/// ```\npub trait ParallelizableCollectionMut: ConcurrentCollectionMut + ParallelizableCollection {\n    /// Creates a parallel iterator over mutable references of the collection's elements.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // Vec<T>: ParallelizableCollectionMut<Item = T>\n    /// let mut vec = vec![1, 2, 3, 4];\n    ///\n    /// vec.par_mut().filter(|x| **x >= 3).for_each(|x| *x += 10);\n    ///\n    /// assert_eq!(&vec, &[1, 2, 13, 14]);\n    /// ```\n    fn par_mut(&mut self) -> impl ParIter<DefaultRunner, Item = &mut Self::Item> {\n        Par::new(Default::default(), Params::default(), self.con_iter_mut())\n    }\n}\n\nimpl<X> ParallelizableCollectionMut for X where X: ConcurrentCollectionMut + ParallelizableCollection\n{}\n"
  },
  {
    "path": "src/parameters/chunk_size.rs",
    "content": "use core::num::NonZeroUsize;\n\n/// `ChunkSize` represents the batch size of elements each thread will pull from the main iterator once it becomes idle again.\n/// It is possible to define a minimum or exact chunk size.\n///\n/// # Rules of Thumb / Guidelines\n///\n/// The objective of this parameter is to balance the overhead of parallelization and cost of heterogeneity of tasks.\n///\n/// In order to illustrate, assume that there exist 8 elements to process, or 8 jobs to execute, and we will use 2 threads for this computation.\n/// Two extreme strategies can be defined as follows.\n///\n/// * **Perfect Sharing of Tasks**\n///   * Setting chunk size to 4 provides a perfect division of tasks in terms of quantity.\n///     Each thread will retrieve 4 elements at once in one pull and process them.\n///     This *one pull* per thread can be considered as the parallelization overhead and this is the best/minimum we can achieve.\n///   * Drawback of this approach, on the other hand, is observed when the execution time of each job is significantly different; i.e., when we have heterogeneous tasks.\n///   * Assume, for instance, that the first element requires 7 units of time while all remaining elements require 1 unit of time.\n///   * Roughly, the parallel execution with a chunk size of 4 would complete in 10 units of time, which is the execution time of the first thread (7 + 3*1).\n///   * The second thread will complete its 4 tasks in 4 units of time and will remain idle for 6 units of time.\n/// * **Perfect Handling of Heterogeneity**\n///   * Setting chunk size to 1 provides a perfect way to deal with heterogeneous tasks, minimizing the idle time of threads.\n///     Each thread will retrieve elements one by one whenever they become idle.\n///   * Considering the heterogeneous example above, the parallel execution with a chunk size of 1 would complete around 7 units of time.\n///     * This is again the execution time of the first thread, which will only execute the first element.\n///     * The second thread will execute the remaining 7 elements, again in 7 units in time.\n///   * None of the threads will be idle, which is the best we can achieve.\n///   * Drawback of this approach is the parallelization overhead due to *pull*s.\n///   * Chunk size being 1, this setting will lead to a total of 8 pull operations (1 pull by the first thread, 7 pulls by the second thread).\n///   * This leads to the maximum/worst parallelization overhead in this scenario.\n///\n/// The objective then is to find a chunk size which is:\n/// * large enough that total time spent for the pulls is insignificant, while\n/// * small enough not to suffer from the impact of heterogeneity.\n///\n/// Note that this decision is data dependent, and hence, can be tuned for the input when the operation is extremely time-critical.\n///\n/// In these cases, the following rule of thumb helps to find a good chunk size.\n/// We can set the chunk size to the smallest value which would make the overhead of pulls insignificant:\n/// * The larger each individual task, the less significant the parallelization overhead. A small chunk size would do.\n/// * The smaller each individual task, the more significant the parallelization overhead. We require a larger chunk size while being careful not to suffer from idle times of threads due to heterogeneity.\n///\n/// In general, it is recommended to set this parameter to its default value, `ChunkSize::Auto`.\n/// This library will try to solve the tradeoff explained above depending on the input data to minimize execution time and idle thread time.\n///\n/// For more critical operations, this `ChunkSize::Exact` and `ChunkSize::Min` options can be used to tune the execution for the class of the relevant input data.\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]\npub enum ChunkSize {\n    /// The objective of `ChunkSize` parameter is to balance the overhead of parallelization and cost of heterogeneity of tasks.\n    ///\n    /// When `ChunkSize::Auto` is used, this library will try to solve the tradeoff explained above depending on the input data to minimize execution time and idle thread time.\n    #[default]\n    Auto,\n    /// This variant defines a minimum chunk size, say `min_chunk_size`.\n    /// Each time a thread completes a task and becomes idle, it will pull at least `min_chunk_size` elements from the input source.\n    /// Parallel execution is allowed to and might decide to pull more elements depending on characteristics of the inputs and used number of threads.\n    Min(NonZeroUsize),\n    /// This variant defines an exact chunk size, say `exact_chunk_size`.\n    /// Each time a thread completes a task and becomes idle, it will pull exactly `exact_chunk_size` elements from the input source.\n    Exact(NonZeroUsize),\n}\n\nimpl From<usize> for ChunkSize {\n    /// Converts the nonnegative integer to chunk size as follows:\n    ///\n    /// * 0 is converted to `ChunkSize::Auto`,\n    /// * `n` is converted to `ChunkSize::Exact(n)` where `n > 0`.\n    fn from(value: usize) -> Self {\n        match value {\n            0 => Self::Auto,\n            n => Self::Exact(NonZeroUsize::new(n).expect(\"is positive\")),\n        }\n    }\n}\n"
  },
  {
    "path": "src/parameters/iteration_order.rs",
    "content": "/// Order of parallel iteration, which might be:\n/// * in the order of the input as in regular sequential iterators, or\n/// * arbitrary.\n///\n/// This is important for certain computations:\n///\n/// * `collect` will return exactly the same result of its sequential counterpart\n///   when `Ordered` is used. However, the elements might (but not necessarily)\n///   be in arbitrary order when `Arbitrary` is used.\n/// * `first` returns the first element of the iterator when `Ordered`, might\n///   return any element when `Arbitrary`.\n/// * `find` returns the first element satisfying the predicate when `Ordered`,\n///   might return any element satisfying the predicate when `Arbitrary`\n///   (sometimes this method is called `find_any`).\n///\n/// [`collect`]: crate::ParIter::collect\n/// [`first`]: crate::ParIter::first\n/// [`find`]: crate::ParIter::find\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]\npub enum IterationOrder {\n    /// The iteration is allowed to be in arbitrary order when it might improve performance,\n    /// but not necessarily.\n    Arbitrary,\n    /// ***Default ordering***.\n    ///\n    /// The iteration will be in an order consistent with the input of the collection,\n    /// and hence, the outputs will always be equivalent to the sequential counterpart.\n    #[default]\n    Ordered,\n}\n"
  },
  {
    "path": "src/parameters/mod.rs",
    "content": "mod chunk_size;\nmod iteration_order;\nmod num_threads;\nmod params;\n\npub use chunk_size::ChunkSize;\npub use iteration_order::IterationOrder;\npub use num_threads::NumThreads;\npub use params::Params;\n"
  },
  {
    "path": "src/parameters/num_threads.rs",
    "content": "use core::num::NonZeroUsize;\n\n/// `NumThreads` represents the degree of parallelization. It is possible to define an upper bound on the number of threads to be used for the parallel computation.\n/// When set to **1**, the computation will be executed sequentially without any overhead.\n/// In this sense, parallel iterators defined in this crate are a union of sequential and parallel execution.\n///\n/// # Rules of Thumb / Guidelines\n///\n/// It is recommended to set this parameter to its default value, `NumThreads::Auto`.\n/// This setting assumes that it can use all available threads; however, the computation will spawn new threads only when required.\n/// In other words, when we can dynamically decide that the task is not large enough to justify spawning a new thread, the parallel execution will avoid it.\n///\n/// A special case is `NumThreads::Max(NonZeroUsize::new(1).unwrap())`, or equivalently `NumThreads::sequential()`.\n/// This will lead to a sequential execution of the defined computation on the main thread.\n/// Both in terms of used resources and computation time, this mode is not similar but **identical** to a sequential execution using the regular sequential `Iterator`s.\n///\n/// Lastly, `NumThreads::Max(t)` where `t >= 2` can be used in the following scenarios:\n/// * We have a strict limit on the resources that we can use for this computation, even if the hardware has more resources.\n///   Parallel execution will ensure that `t` will never be exceeded.\n/// * We have a computation which is extremely time-critical and our benchmarks show that `t` outperforms the `NumThreads::Auto` on the corresponding system.\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]\npub enum NumThreads {\n    /// This setting assumes that it can use all available threads; however, the computation will spawn new threads only when required.\n    /// In other words, when we can dynamically decide that the task is not large enough to justify spawning a new thread, the parallel execution will avoid it.\n    #[default]\n    Auto,\n    /// Limits the maximum number of threads that can be used by the parallel execution.\n    ///\n    /// A special case is `NumThreads::Max(NonZeroUsize::new(1).unwrap())`, or equivalently `NumThreads::sequential()`.\n    /// This will lead to a sequential execution of the defined computation on the main thread.\n    /// Both in terms of used resources and computation time, this mode is not similar but **identical** to a sequential execution using the regular sequential `Iterator`s.\n    ///\n    /// Lastly, `NumThreads::Max(t)` where `t >= 2` can be used in the following scenarios:\n    /// * We have a strict limit on the resources that we can use for this computation, even if the hardware has more resources.\n    ///   Parallel execution will ensure that `t` will never be exceeded.\n    /// * We have a computation which is extremely time-critical and our benchmarks show that `t` outperforms the `NumThreads::Auto` on the corresponding system.\n    Max(NonZeroUsize),\n}\n\nconst ONE: NonZeroUsize = NonZeroUsize::new(1).expect(\"seq=1 is positive\");\n\nimpl From<usize> for NumThreads {\n    /// Converts the nonnegative integer to number of threads as follows:\n    ///\n    /// * 0 is converted to `NumThreads::Auto`,\n    /// * `n` is converted to `NumThreads::Max(n)` where `n > 0`.\n    fn from(value: usize) -> Self {\n        match value {\n            0 => Self::Auto,\n            n => Self::Max(NonZeroUsize::new(n).expect(\"must be positive\")),\n        }\n    }\n}\n\nimpl NumThreads {\n    /// Equivalent to `NumThreads::Max(NonZeroUsize::new(1).unwrap())`.\n    ///\n    /// This will lead to a sequential execution of the defined computation on the main thread.\n    /// Both in terms of used resources and computation time, this mode is not similar but **identical** to a sequential execution using the regular sequential `Iterator`s.\n    pub const fn sequential() -> Self {\n        NumThreads::Max(ONE)\n    }\n\n    /// Returns true if number of threads is set to 1.\n    ///\n    /// Note that in this case the computation will be executed sequentially using regular iterators.\n    pub fn is_sequential(self) -> bool {\n        matches!(self, Self::Max(n) if n == ONE)\n    }\n}\n"
  },
  {
    "path": "src/parameters/params.rs",
    "content": "use super::{chunk_size::ChunkSize, iteration_order::IterationOrder, num_threads::NumThreads};\n\n/// Parameters of a parallel computation.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]\npub struct Params {\n    /// Number of threads to be used in the parallel computation.\n    ///\n    /// See [`NumThreads`] for details.\n    pub num_threads: NumThreads,\n    /// Chunk size to be used in the parallel computation.\n    ///\n    /// See [`ChunkSize`] for details.\n    pub chunk_size: ChunkSize,\n    /// Ordering of outputs of the parallel computation that is important when the outputs\n    /// are collected into a collection.\n    ///\n    /// See [`IterationOrder`] for details.\n    pub iteration_order: IterationOrder,\n}\n\nimpl Params {\n    /// Crates parallel computation parameters for the given configurations.\n    pub fn new(\n        num_threads: impl Into<NumThreads>,\n        chunk_size: impl Into<ChunkSize>,\n        iteration_order: IterationOrder,\n    ) -> Self {\n        Self {\n            num_threads: num_threads.into(),\n            chunk_size: chunk_size.into(),\n            iteration_order,\n        }\n    }\n\n    /// Returns true if number of threads is set to 1.\n    ///\n    /// Note that in this case the computation will be executed sequentially using regular iterators.\n    pub fn is_sequential(self) -> bool {\n        self.num_threads.is_sequential()\n    }\n\n    // helpers\n\n    pub(crate) fn with_num_threads(self, num_threads: impl Into<NumThreads>) -> Self {\n        Self {\n            num_threads: num_threads.into(),\n            chunk_size: self.chunk_size,\n            iteration_order: self.iteration_order,\n        }\n    }\n\n    pub(crate) fn with_chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self {\n        Self {\n            num_threads: self.num_threads,\n            chunk_size: chunk_size.into(),\n            iteration_order: self.iteration_order,\n        }\n    }\n\n    pub(crate) fn with_collect_ordering(self, iteration_order: IterationOrder) -> Self {\n        Self {\n            num_threads: self.num_threads,\n            chunk_size: self.chunk_size,\n            iteration_order,\n        }\n    }\n}\n"
  },
  {
    "path": "src/runner/computation_kind.rs",
    "content": "/// Computation kind.\n#[derive(Clone, Copy)]\npub enum ComputationKind {\n    /// Computation where outputs are collected into a collection.\n    Collect,\n    /// Computation where the inputs or intermediate results are reduced to a single value.\n    Reduce,\n    /// Computation which allows for early returns, such as `find` operation.\n    EarlyReturn,\n}\n"
  },
  {
    "path": "src/runner/implementations/mod.rs",
    "content": "#[cfg(test)]\nmod tests;\n\nmod runner_with_pool;\npub use runner_with_pool::RunnerWithPool;\n\nmod sequential;\npub use sequential::SequentialPool;\n\n#[cfg(feature = \"std\")]\nmod std_runner;\n#[cfg(feature = \"std\")]\npub use std_runner::StdDefaultPool;\n\n#[cfg(feature = \"pond\")]\nmod pond;\n#[cfg(feature = \"pond\")]\npub use pond::PondPool;\n\n#[cfg(feature = \"poolite\")]\nmod poolite;\n\n#[cfg(feature = \"rayon-core\")]\nmod rayon_core;\n\n#[cfg(feature = \"scoped-pool\")]\nmod scoped_pool;\n\n#[cfg(feature = \"scoped_threadpool\")]\nmod scoped_threadpool;\n\n#[cfg(feature = \"yastl\")]\nmod yastl;\n#[cfg(feature = \"yastl\")]\npub use yastl::YastlPool;\n"
  },
  {
    "path": "src/runner/implementations/pond.rs",
    "content": "use crate::par_thread_pool::ParThreadPool;\nuse core::num::NonZeroUsize;\nuse pond::{Pool, Scope};\n\n/// A wrapper for `pond::Pool` and number of threads it was built with.\n///\n/// NOTE: The reason why `pond::Pool` does not directly implement `ParThreadPool`\n/// is simply to be able to provide `max_num_threads` which is the argument used\n/// to create the pool with.\n///\n/// Following constructor of the `pond::Pool` is made available to `PondPool`:\n/// * [`PondPool::new_threads_unbounded`]\npub struct PondPool(Pool, NonZeroUsize);\n\nimpl PondPool {\n    /// Spawn a number of threads. The pool's queue of pending jobs is limited.\n    /// The backlog is unbounded as in unbounded.\n    pub fn new_threads_unbounded(num_threads: usize) -> Self {\n        let num_threads = num_threads.min(1);\n        let pool = Pool::new_threads_unbounded(num_threads);\n        #[allow(clippy::missing_panics_doc)]\n        Self(pool, NonZeroUsize::new(num_threads).expect(\">0\"))\n    }\n\n    /// Reference to wrapped `pond::Pool`.\n    pub fn inner(&self) -> &Pool {\n        &self.0\n    }\n\n    /// Mutable reference to wrapped `pond::Pool`.\n    pub fn inner_mut(&mut self) -> &mut Pool {\n        &mut self.0\n    }\n\n    /// Returns the wrapped `pond::Pool`.\n    pub fn into_inner(self) -> Pool {\n        self.0\n    }\n}\n\nimpl ParThreadPool for PondPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = Scope<'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(Scope<'env, 'scope>) + Send,\n    {\n        self.0.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        self.1\n    }\n}\n\nimpl ParThreadPool for &mut PondPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = Scope<'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(Scope<'env, 'scope>) + Send,\n    {\n        self.0.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        self.1\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/poolite.rs",
    "content": "use crate::par_thread_pool::ParThreadPool;\nuse core::num::NonZeroUsize;\nuse poolite::{Pool, Scoped};\n\nimpl ParThreadPool for Pool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s Scoped<'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.push(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s Scoped<'env, 'scope>) + Send,\n    {\n        self.scoped(f);\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new(self.threads_future().max(1)).expect(\">0\")\n    }\n}\n\nimpl ParThreadPool for &Pool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s Scoped<'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.push(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s Scoped<'env, 'scope>) + Send,\n    {\n        self.scoped(f);\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new(self.threads_future().max(1)).expect(\">0\")\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/rayon_core.rs",
    "content": "use crate::par_thread_pool::ParThreadPool;\nuse core::num::NonZeroUsize;\nuse rayon_core::ThreadPool;\n\nimpl ParThreadPool for ThreadPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s rayon_core::Scope<'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.spawn(move |_| work());\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s rayon_core::Scope<'scope>) + Send,\n    {\n        self.scope(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new(self.current_num_threads().max(1)).expect(\">0\")\n    }\n}\n\nimpl ParThreadPool for &rayon_core::ThreadPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s rayon_core::Scope<'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.spawn(move |_| work());\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s rayon_core::Scope<'scope>) + Send,\n    {\n        self.scope(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new(self.current_num_threads().max(1)).expect(\">0\")\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/runner_with_pool.rs",
    "content": "#[cfg(feature = \"std\")]\nuse crate::executor::ParallelExecutorWithDiagnostics;\nuse crate::{DefaultExecutor, ParThreadPool, ParallelExecutor, runner::ParallelRunner};\nuse core::marker::PhantomData;\n\n/// Parallel runner with a given pool of type `P` and parallel executor of `R`.\n///\n/// A `RunnerWithPool` can always be created from owned `pool` implementing [`ParThreadPool`], but also from\n/// * `&pool` in most cases,\n/// * `&mut pool` in others.\n///\n/// Note that default parallel runner; i.e., [`DefaultRunner`] is:\n/// * `RunnerWithPool<StdDefaultPool>` when \"std\" feature is enabled,\n/// * `RunnerWithPool<SequentialPool>` when \"std\" feature is disabled.\n///\n/// [`DefaultRunner`]: crate::DefaultRunner\n///\n/// # Examples\n///\n/// ```\n/// use orx_parallel::*;\n///\n/// // parallel computation generic over parallel runner; and hence, the thread pool\n/// fn run_with_runner<R: ParallelRunner>(runner: R, input: &[usize]) -> Vec<String> {\n///     input\n///         .par()\n///         .with_runner(runner)\n///         .flat_map(|x| [*x, 2 * x, x / 7])\n///         .map(|x| x.to_string())\n///         .collect()\n/// }\n///\n/// let vec: Vec<_> = (0..42).collect();\n/// let input = vec.as_slice();\n///\n/// // runs sequentially on the main thread\n/// let runner = RunnerWithPool::from(SequentialPool);\n/// let expected = run_with_runner(runner, input);\n///\n/// // uses native threads\n/// #[cfg(feature = \"std\")]\n/// {\n///     let runner = RunnerWithPool::from(StdDefaultPool::default());\n///     let result = run_with_runner(runner, input);\n///     assert_eq!(&expected, &result);\n/// }\n///\n/// // uses rayon-core ThreadPool with 8 threads\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"rayon-core\")]\n/// {\n///     let pool = rayon_core::ThreadPoolBuilder::new()\n///         .num_threads(8)\n///         .build()\n///         .unwrap();\n///     let result = run_with_runner(RunnerWithPool::from(&pool), input);\n///     assert_eq!(&expected, &result);\n/// }\n///\n/// // uses scoped-pool Pool with 8 threads\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"scoped-pool\")]\n/// {\n///     let pool = scoped_pool::Pool::new(8);\n///     let result = run_with_runner(RunnerWithPool::from(&pool), input);\n///     assert_eq!(&expected, &result);\n/// }\n///\n/// // uses scoped_threadpool Pool with 8 threads\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"scoped_threadpool\")]\n/// {\n///     let mut pool = scoped_threadpool::Pool::new(8);\n///     let result = run_with_runner(RunnerWithPool::from(&mut pool), input); // requires &mut pool\n///     assert_eq!(&expected, &result);\n/// }\n///\n/// // uses yastl Pool wrapped as YastlPool with 8 threads\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"yastl\")]\n/// {\n///     let pool = YastlPool::new(8);\n///     let result = run_with_runner(RunnerWithPool::from(&pool), input);\n///     assert_eq!(&expected, &result);\n/// }\n///\n/// // uses pond Pool wrapped as PondPool with 8 threads\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"pond\")]\n/// {\n///     let mut pool = PondPool::new_threads_unbounded(8);\n///     let result = run_with_runner(RunnerWithPool::from(&mut pool), input); // requires &mut pool\n///     assert_eq!(&expected, &result);\n/// }\n///\n/// // uses poolite Pool with 8 threads\n/// #[cfg(not(miri))]\n/// #[cfg(feature = \"poolite\")]\n/// {\n///     let pool = poolite::Pool::with_builder(poolite::Builder::new().min(8).max(8)).unwrap();\n///     let result = run_with_runner(RunnerWithPool::from(&pool), input);\n///     assert_eq!(&expected, &result);\n/// }\n/// ```\n#[derive(Clone)]\npub struct RunnerWithPool<P, R = DefaultExecutor>\nwhere\n    P: ParThreadPool,\n    R: ParallelExecutor,\n{\n    pool: P,\n    runner: PhantomData<R>,\n}\n\nimpl<P, R> Default for RunnerWithPool<P, R>\nwhere\n    P: ParThreadPool + Default,\n    R: ParallelExecutor,\n{\n    fn default() -> Self {\n        Self {\n            pool: Default::default(),\n            runner: PhantomData,\n        }\n    }\n}\n\nimpl<P: ParThreadPool> From<P> for RunnerWithPool<P, DefaultExecutor> {\n    fn from(pool: P) -> Self {\n        Self {\n            pool,\n            runner: PhantomData,\n        }\n    }\n}\n\nimpl<P, R> RunnerWithPool<P, R>\nwhere\n    P: ParThreadPool,\n    R: ParallelExecutor,\n{\n    /// Converts the runner into the wrapped underlying pool.\n    ///\n    /// Note that a `RunnerWithPool` can always be created from owned `pool`, but also from\n    /// * `&pool` in most cases,\n    /// * `&mut pool` in others.\n    ///\n    /// This function is only relevant when the runner is created from owned pool, in which case\n    /// `into_inner_pool` can be used to get back ownership of the pool.\n    ///\n    /// # Example\n    ///\n    /// The following example demonstrates the use case for rayon-core thread pool; however, it\n    /// holds for all thread pool implementations.\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// let vec: Vec<_> = (0..42).collect();\n    /// let input = vec.as_slice();\n    ///\n    /// #[cfg(not(miri))]\n    /// #[cfg(feature = \"rayon-core\")]\n    /// {\n    ///     let pool = rayon_core::ThreadPoolBuilder::new()\n    ///         .num_threads(8)\n    ///         .build()\n    ///         .unwrap();\n    ///\n    ///     // create runner owning the pool\n    ///     let mut runner = RunnerWithPool::from(pool);\n    ///\n    ///     // use runner, and hence the pool, in parallel computations\n    ///     let sum = input.par().with_runner(&mut runner).sum();\n    ///     let max = input.par().with_runner(&mut runner).max();\n    ///     let txt: Vec<_> = input\n    ///         .par()\n    ///         .with_runner(&mut runner)\n    ///         .map(|x| x.to_string())\n    ///         .collect();\n    ///\n    ///     // get back ownership of the pool\n    ///     let pool: rayon_core::ThreadPool = runner.into_inner_pool();\n    /// }\n    /// ```\n    pub fn into_inner_pool(self) -> P {\n        self.pool\n    }\n\n    /// Converts the runner into one using the [`ParallelExecutor`] `Q` rather than `R`.\n    pub fn with_executor<Q: ParallelExecutor>(self) -> RunnerWithPool<P, Q> {\n        RunnerWithPool {\n            pool: self.pool,\n            runner: PhantomData,\n        }\n    }\n\n    /// Converts executor of this runner `R` into one with diagnostics; i.e.,`ParallelExecutorWithDiagnostics<R>`.\n    ///\n    /// Note that [`ParallelExecutorWithDiagnostics`] prints the diagnostics on the stdout. Therefore, it must\n    /// only be used while testing a program, not in production.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use orx_parallel::*;\n    ///\n    /// // normal execution\n    ///\n    /// let range = 0..4096;\n    /// let sum = range\n    ///     .par()\n    ///     .map(|x| x + 1)\n    ///     .filter(|x| x.is_multiple_of(2))\n    ///     .sum();\n    /// assert_eq!(sum, 4196352);\n    ///\n    /// // execution with diagnostics\n    ///\n    /// let range = 0..4096;\n    /// let sum = range\n    ///     .par()\n    ///     .with_runner(DefaultRunner::default().with_diagnostics())\n    ///     .map(|x| x + 1)\n    ///     .filter(|x| x.is_multiple_of(2))\n    ///     .sum();\n    /// assert_eq!(sum, 4196352);\n    ///\n    /// // prints diagnostics, which looks something like the following:\n    /// //\n    /// // - Number of threads used = 5\n    /// //\n    /// // - [Thread idx]: num_calls, num_tasks, avg_chunk_size, first_chunk_sizes\n    /// //   - [0]: 25, 1600, 64, [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]\n    /// //   - [1]: 26, 1664, 64, [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]\n    /// //   - [2]: 13, 832, 64, [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]\n    /// //   - [3]: 0, 0, 0, []\n    /// //   - [4]: 0, 0, 0, []\n    /// ```\n    #[cfg(feature = \"std\")]\n    pub fn with_diagnostics(self) -> RunnerWithPool<P, ParallelExecutorWithDiagnostics<R>> {\n        RunnerWithPool {\n            pool: self.pool,\n            runner: PhantomData,\n        }\n    }\n}\n\nimpl<P, R> ParallelRunner for RunnerWithPool<P, R>\nwhere\n    P: ParThreadPool,\n    R: ParallelExecutor,\n{\n    type Executor = R;\n\n    type ThreadPool = P;\n\n    fn thread_pool(&self) -> &Self::ThreadPool {\n        &self.pool\n    }\n\n    fn thread_pool_mut(&mut self) -> &mut Self::ThreadPool {\n        &mut self.pool\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/scoped_pool.rs",
    "content": "use crate::par_thread_pool::ParThreadPool;\nuse core::num::NonZeroUsize;\nuse scoped_pool::{Pool, Scope};\n\nimpl ParThreadPool for Pool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s Scope<'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&Scope<'scope>) + Send,\n    {\n        self.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new(self.workers().max(1)).expect(\">0\")\n    }\n}\n\nimpl ParThreadPool for &Pool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s Scope<'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&Scope<'scope>) + Send,\n    {\n        self.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> core::num::NonZeroUsize {\n        NonZeroUsize::new(self.workers().max(1)).expect(\">0\")\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/scoped_threadpool.rs",
    "content": "use crate::par_thread_pool::ParThreadPool;\nuse core::num::NonZeroUsize;\nuse scoped_threadpool::Pool;\n\nimpl ParThreadPool for Pool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s scoped_threadpool::Scope<'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s scoped_threadpool::Scope<'env, 'scope>) + Send,\n    {\n        self.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new((self.thread_count() as usize).max(1)).expect(\">0\")\n    }\n}\n\nimpl ParThreadPool for &mut Pool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s scoped_threadpool::Scope<'env, 'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s scoped_threadpool::Scope<'env, 'scope>) + Send,\n    {\n        self.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new((self.thread_count() as usize).max(1)).expect(\">0\")\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/sequential.rs",
    "content": "use crate::ParThreadPool;\nuse core::num::NonZeroUsize;\n\n/// A 'thread pool' with [`max_num_threads`] of 1.\n/// All computations using this thread pool are executed sequentially by the main thread.\n///\n/// This is the default thread pool used when \"std\" feature is disabled.\n/// Note that the thread pool to be used for a parallel computation can be set by the\n/// [`with_runner`] transformation separately for each parallel iterator.\n///\n/// [`max_num_threads`]: ParThreadPool::max_num_threads\n/// [`with_runner`]: crate::ParIter::with_runner\n#[derive(Default, Clone)]\npub struct SequentialPool;\n\nimpl ParThreadPool for SequentialPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = ()\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(_: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        work()\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(()) + Send,\n    {\n        f(())\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        NonZeroUsize::new(1).expect(\">0\")\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/std_runner.rs",
    "content": "use crate::par_thread_pool::ParThreadPool;\nuse core::num::NonZeroUsize;\n\nconst MAX_UNSET_NUM_THREADS: NonZeroUsize = NonZeroUsize::new(8).expect(\">0\");\n\n/// Native standard thread pool.\n///\n/// This is the default thread pool used when \"std\" feature is enabled.\n/// Note that the thread pool to be used for a parallel computation can be set by the\n/// [`with_runner`] transformation separately for each parallel iterator.\n///\n/// Uses `std::thread::scope` and `scope.spawn(..)` to distribute work to threads.\n///\n/// Value of [`max_num_threads`] is determined as the minimum of:\n///\n/// * the available parallelism of the host obtained via `std::thread::available_parallelism()`, and\n/// * the upper bound set by the environment variable \"ORX_PARALLEL_MAX_NUM_THREADS\", when set.\n///\n/// [`max_num_threads`]: ParThreadPool::max_num_threads\n/// [`with_runner`]: crate::ParIter::with_runner\n#[derive(Clone)]\npub struct StdDefaultPool {\n    max_num_threads: NonZeroUsize,\n}\n\nimpl StdDefaultPool {\n    /// By default (`StdDefaultPool::default()`), std thread pool assumes that all threads are available\n    /// for the parallel computations.\n    ///\n    /// Constructing the pool with this method makes sure that parallel computations cannot use more than\n    /// `max_num_threads` threads.\n    pub fn with_max_num_threads(max_num_threads: NonZeroUsize) -> Self {\n        let mut pool = Self::default();\n        if max_num_threads < pool.max_num_threads {\n            pool.max_num_threads = max_num_threads;\n        }\n        pool\n    }\n}\n\nimpl Default for StdDefaultPool {\n    fn default() -> Self {\n        let env_max_num_threads = crate::env::max_num_threads_by_env_variable();\n\n        let ava_max_num_threads = std::thread::available_parallelism().ok();\n\n        let max_num_threads = match (env_max_num_threads, ava_max_num_threads) {\n            (Some(env), Some(ava)) => env.min(ava),\n            (Some(env), None) => env,\n            (None, Some(ava)) => ava,\n            (None, None) => MAX_UNSET_NUM_THREADS,\n        };\n\n        Self { max_num_threads }\n    }\n}\n\nimpl ParThreadPool for StdDefaultPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s std::thread::Scope<'s, 'env>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        self.max_num_threads\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s std::thread::Scope<'s, 'env>) + Send,\n    {\n        std::thread::scope(f)\n    }\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.spawn(work);\n    }\n}\n\nimpl ParThreadPool for &StdDefaultPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s std::thread::Scope<'s, 'env>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        self.max_num_threads\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s std::thread::Scope<'s, 'env>) + Send,\n    {\n        std::thread::scope(f)\n    }\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.spawn(work);\n    }\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/mod.rs",
    "content": "#[cfg(feature = \"pond\")]\nmod pond;\n\n#[cfg(feature = \"poolite\")]\nmod poolite;\n\n#[cfg(feature = \"rayon-core\")]\nmod rayon_core;\n\n#[cfg(feature = \"scoped-pool\")]\nmod scoped_pool;\n\n#[cfg(feature = \"scoped_threadpool\")]\nmod scoped_threadpool;\n\n#[cfg(feature = \"std\")]\nmod std;\n\n#[cfg(feature = \"yastl\")]\nmod yastl;\n\nmod sequential;\n\nmod utils;\n\nuse utils::run_map;\n"
  },
  {
    "path": "src/runner/implementations/tests/pond.rs",
    "content": "use super::run_map;\nuse crate::{\n    IterationOrder,\n    runner::implementations::{PondPool, RunnerWithPool},\n};\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n// TODO: miri test terminates with: the main thread terminated without waiting for all remaining threads\n#[cfg(not(miri))]\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_pond_map(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let mut pool = PondPool::new_threads_unbounded(nt);\n    let orch: RunnerWithPool<_> = (&mut pool).into();\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/poolite.rs",
    "content": "use super::run_map;\nuse crate::{IterationOrder, runner::implementations::RunnerWithPool};\nuse poolite::{Builder, Pool};\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n// `poolite::Builder::new()` fails miri test\n#[cfg(not(miri))]\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_poolite_map(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let pool = Pool::with_builder(Builder::new().max(nt).min(nt)).unwrap();\n    let orch: RunnerWithPool<_> = (&pool).into();\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/rayon_core.rs",
    "content": "use super::run_map;\nuse crate::{IterationOrder, runner::implementations::RunnerWithPool};\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n// TODO: rayon_core pool fails the miri test (integer-to-pointer cast crossbeam-epoch-0.9.18/src/atomic.rs:204:11)\n#[cfg(not(miri))]\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_rayon_map(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let pool = rayon_core::ThreadPoolBuilder::new()\n        .num_threads(nt)\n        .build()\n        .unwrap();\n    let orch: RunnerWithPool<_> = (&pool).into();\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/scoped_pool.rs",
    "content": "use super::run_map;\nuse crate::{IterationOrder, runner::implementations::RunnerWithPool};\nuse scoped_pool::Pool;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n// `scoped_pool::Pool::new(nt)` fails miri test\n#[cfg(not(miri))]\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_scoped_pool_map(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let pool = Pool::new(nt);\n    let orch = RunnerWithPool::from(&pool);\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/scoped_threadpool.rs",
    "content": "use super::run_map;\nuse crate::{IterationOrder, runner::implementations::RunnerWithPool};\nuse scoped_threadpool::Pool;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n// TODO: miri test terminates with: the main thread terminated without waiting for all remaining threads\n#[cfg(not(miri))]\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_scoped_threadpool_map(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let mut pool = Pool::new(nt as u32);\n    let orch: RunnerWithPool<_> = (&mut pool).into();\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/sequential.rs",
    "content": "use super::run_map;\nuse crate::{IterationOrder, RunnerWithPool, runner::implementations::sequential::SequentialPool};\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_scoped_threadpool_map(n: usize, _: usize, chunk: usize, ordering: IterationOrder) {\n    let orch = RunnerWithPool::from(SequentialPool);\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/std.rs",
    "content": "use super::run_map;\nuse crate::{\n    DefaultRunner, IterationOrder, RunnerWithPool,\n    runner::implementations::std_runner::StdDefaultPool,\n};\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_scoped_threadpool_map(n: usize, _: usize, chunk: usize, ordering: IterationOrder) {\n    let orch = DefaultRunner::default();\n    run_map(n, chunk, ordering, orch);\n\n    let pool = StdDefaultPool::default();\n    let orch: RunnerWithPool<_> = (&pool).into();\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/utils.rs",
    "content": "use crate::{IntoParIter, IterationOrder, ParIter, runner::ParallelRunner};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::SplitVec;\n\npub fn run_map(n: usize, chunk: usize, ordering: IterationOrder, mut orch: impl ParallelRunner) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let value = || map(i.to_string());\n        output.push(value());\n        expected.push(value());\n    }\n    expected.extend(input.clone().into_iter().map(map));\n\n    let mut output = input\n        .into_par()\n        .with_runner(&mut orch)\n        .chunk_size(chunk)\n        .iteration_order(ordering)\n        .map(map)\n        .collect_into(output);\n\n    if matches!(ordering, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n"
  },
  {
    "path": "src/runner/implementations/tests/yastl.rs",
    "content": "use super::run_map;\nuse crate::{\n    IterationOrder,\n    runner::implementations::{RunnerWithPool, YastlPool},\n};\nuse test_case::test_matrix;\nuse yastl::ThreadConfig;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n// TODO: miri test terminates with: the main thread terminated without waiting for all remaining threads\n#[cfg(not(miri))]\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn pool_yastl_map(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let pool = YastlPool::new(nt);\n    let orch: RunnerWithPool<_> = (&pool).into();\n    run_map(n, chunk, ordering, orch);\n\n    let pool = YastlPool::with_config(nt, ThreadConfig::new());\n    let orch: RunnerWithPool<_> = (pool).into();\n    run_map(n, chunk, ordering, orch);\n}\n"
  },
  {
    "path": "src/runner/implementations/yastl.rs",
    "content": "use crate::ParThreadPool;\nuse core::num::NonZeroUsize;\nuse yastl::{Pool, Scope, ThreadConfig};\n\n/// A wrapper for `yastl::Pool` and number of threads it was built with.\n///\n/// NOTE: The reason why `yastl::Pool` does not directly implement `ParThreadPool`\n/// is simply to be able to provide `max_num_threads` which is the argument used\n/// to create the pool with.\n///\n/// Two constructors of the `yastl::Pool` are made available to `YastlPool`:\n/// * [`YastlPool::new`]\n/// * [`YastlPool::with_config`]\n#[derive(Clone)]\npub struct YastlPool(Pool, NonZeroUsize);\n\nimpl YastlPool {\n    /// Create a new Pool that will execute it's tasks on `num_threads` worker threads.\n    pub fn new(num_threads: usize) -> Self {\n        let num_threads = num_threads.min(1);\n        let pool = Pool::new(num_threads);\n        #[allow(clippy::missing_panics_doc)]\n        Self(pool, NonZeroUsize::new(num_threads).expect(\">0\"))\n    }\n\n    /// Create a new Pool that will execute it's tasks on `num_threads` worker threads and\n    /// spawn them using the given `config`.\n    pub fn with_config(num_threads: usize, config: ThreadConfig) -> Self {\n        let num_threads = num_threads.min(1);\n        let pool = Pool::with_config(num_threads, config);\n        #[allow(clippy::missing_panics_doc)]\n        Self(pool, NonZeroUsize::new(num_threads).expect(\">0\"))\n    }\n\n    /// Reference to wrapped `yastl::Pool`.\n    pub fn inner(&self) -> &Pool {\n        &self.0\n    }\n\n    /// Mutable reference to wrapped `yastl::Pool`.\n    pub fn inner_mut(&mut self) -> &mut Pool {\n        &mut self.0\n    }\n\n    /// Returns the wrapped `yastl::Pool`.\n    pub fn into_inner(self) -> Pool {\n        self.0\n    }\n}\n\nimpl ParThreadPool for YastlPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s Scope<'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s Scope<'scope>) + Send,\n    {\n        self.0.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        self.1\n    }\n}\n\nimpl ParThreadPool for &YastlPool {\n    type ScopeRef<'s, 'env, 'scope>\n        = &'s Scope<'scope>\n    where\n        'scope: 's,\n        'env: 'scope + 's;\n\n    fn run_in_scope<'s, 'env, 'scope, W>(s: &Self::ScopeRef<'s, 'env, 'scope>, work: W)\n    where\n        'scope: 's,\n        'env: 'scope + 's,\n        W: Fn() + Send + 'scope + 'env,\n    {\n        s.execute(work);\n    }\n\n    fn scoped_computation<'env, 'scope, F>(&'env mut self, f: F)\n    where\n        'env: 'scope,\n        for<'s> F: FnOnce(&'s Scope<'scope>) + Send,\n    {\n        self.0.scoped(f)\n    }\n\n    fn max_num_threads(&self) -> NonZeroUsize {\n        self.1\n    }\n}\n"
  },
  {
    "path": "src/runner/mod.rs",
    "content": "mod computation_kind;\nmod implementations;\nmod num_spawned;\nmod parallel_runner;\n\npub(crate) use parallel_runner::{SharedStateOf, ThreadRunnerOf};\n\npub use computation_kind::ComputationKind;\npub use implementations::{RunnerWithPool, SequentialPool};\npub use num_spawned::NumSpawned;\npub use parallel_runner::ParallelRunner;\n\n#[cfg(feature = \"pond\")]\npub use implementations::PondPool;\n\n#[cfg(feature = \"std\")]\npub use implementations::StdDefaultPool;\n\n#[cfg(feature = \"yastl\")]\npub use implementations::YastlPool;\n\n// DEFAULT\n\n/// Default pool used by orx-parallel computations:\n///\n/// * [`StdDefaultPool`] when \"std\" feature is enabled,\n/// * [`SequentialPool`] otherwise.\n#[cfg(feature = \"std\")]\npub type DefaultPool = StdDefaultPool;\n/// Default pool used by orx-parallel computations:\n///\n/// * `StdDefaultPool` when \"std\" feature is enabled,\n/// * [`SequentialPool`] otherwise.\n#[cfg(not(feature = \"std\"))]\npub type DefaultPool = SequentialPool;\n\n/// Default runner used by orx-parallel computations, using the [`DefaultPool`]:\n///\n/// * [`RunnerWithPool`] with [`StdDefaultPool`] when \"std\" feature is enabled,\n/// * [`RunnerWithPool`] with [`SequentialPool`] otherwise.\npub type DefaultRunner = RunnerWithPool<DefaultPool>;\n"
  },
  {
    "path": "src/runner/num_spawned.rs",
    "content": "/// Number of spawned threads to execute a parallel computation.\n#[derive(Clone, Copy)]\npub struct NumSpawned(usize);\n\nimpl NumSpawned {\n    /// Zero.\n    pub fn zero() -> Self {\n        Self(0)\n    }\n\n    /// Adds one to the spawned thread count.\n    pub fn increment(&mut self) {\n        self.0 += 1;\n    }\n\n    /// Converts into usize.\n    pub fn into_inner(self) -> usize {\n        self.0\n    }\n}\n\nimpl core::ops::Rem for NumSpawned {\n    type Output = usize;\n\n    fn rem(self, rhs: Self) -> Self::Output {\n        self.0 % rhs.0\n    }\n}\n"
  },
  {
    "path": "src/runner/parallel_runner.rs",
    "content": "use crate::{\n    NumThreads, ParallelExecutor, Params,\n    generic_values::runner_results::{Fallibility, Infallible, Never},\n    par_thread_pool::{ParThreadPool, ParThreadPoolCompute},\n    runner::{ComputationKind, NumSpawned},\n};\nuse alloc::vec::Vec;\nuse core::num::NonZeroUsize;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// Parallel runner defining how the threads must be spawned and job must be distributed.\npub trait ParallelRunner {\n    /// Parallel executor responsible for distribution of tasks to the threads.\n    type Executor: ParallelExecutor;\n\n    /// Thread pool responsible for providing threads to the parallel computation.\n    type ThreadPool: ParThreadPool;\n\n    /// Creates a new parallel executor for a parallel computation.\n    fn new_executor(\n        &self,\n        kind: ComputationKind,\n        params: Params,\n        initial_input_len: Option<usize>,\n    ) -> Self::Executor {\n        let max_num_threads = self.max_num_threads_for_computation(params, initial_input_len);\n        <Self::Executor as ParallelExecutor>::new(kind, params, initial_input_len, max_num_threads)\n    }\n\n    /// Reference to the underlying thread pool.\n    fn thread_pool(&self) -> &Self::ThreadPool;\n\n    /// Mutable reference to the underlying thread pool.\n    fn thread_pool_mut(&mut self) -> &mut Self::ThreadPool;\n\n    // derived\n\n    /// Runs `thread_do` using threads provided by the thread pool.\n    fn run_all<I, F>(\n        &mut self,\n        params: Params,\n        iter: I,\n        kind: ComputationKind,\n        thread_do: F,\n    ) -> NumSpawned\n    where\n        I: ConcurrentIter,\n        F: Fn(NumSpawned, &I, &SharedStateOf<Self>, ThreadRunnerOf<Self>) + Sync,\n    {\n        let executor = self.new_executor(kind, params, iter.try_get_len());\n        let state = executor.new_shared_state();\n        let do_spawn = |num_spawned| executor.do_spawn_new(num_spawned, &state, &iter);\n        let work = |num_spawned: NumSpawned| {\n            let thread_idx = num_spawned.into_inner();\n            thread_do(\n                num_spawned,\n                &iter,\n                &state,\n                executor.new_thread_executor(thread_idx, &state),\n            );\n        };\n        let result = self.thread_pool_mut().run_in_pool(do_spawn, work);\n        executor.complete_task(state);\n        result\n    }\n\n    /// Runs `thread_map` using threads provided by the thread pool.\n    fn map_all<F, I, M, T>(\n        &mut self,\n        params: Params,\n        iter: I,\n        kind: ComputationKind,\n        thread_map: M,\n    ) -> (NumSpawned, Result<Vec<T>, F::Error>)\n    where\n        F: Fallibility,\n        I: ConcurrentIter,\n        M: Fn(NumSpawned, &I, &SharedStateOf<Self>, ThreadRunnerOf<Self>) -> Result<T, F::Error>\n            + Sync,\n        T: Send,\n        F::Error: Send,\n    {\n        let iter_len = iter.try_get_len();\n        let executor = self.new_executor(kind, params, iter_len);\n        let state = executor.new_shared_state();\n        let do_spawn = |num_spawned| executor.do_spawn_new(num_spawned, &state, &iter);\n        let work = |num_spawned: NumSpawned| {\n            let thread_idx = num_spawned.into_inner();\n            thread_map(\n                num_spawned,\n                &iter,\n                &state,\n                executor.new_thread_executor(thread_idx, &state),\n            )\n        };\n        let max_num_threads = self.max_num_threads_for_computation(params, iter_len);\n        let result =\n            self.thread_pool_mut()\n                .map_in_pool::<F, _, _, _>(do_spawn, work, max_num_threads);\n        executor.complete_task(state);\n        result\n    }\n\n    /// Runs infallible `thread_map` using threads provided by the thread pool.\n    fn map_infallible<I, M, T>(\n        &mut self,\n        params: Params,\n        iter: I,\n        kind: ComputationKind,\n        thread_map: M,\n    ) -> (NumSpawned, Result<Vec<T>, Never>)\n    where\n        I: ConcurrentIter,\n        M: Fn(NumSpawned, &I, &SharedStateOf<Self>, ThreadRunnerOf<Self>) -> Result<T, Never>\n            + Sync,\n        T: Send,\n    {\n        self.map_all::<Infallible, _, _, _>(params, iter, kind, thread_map)\n    }\n\n    /// Returns the maximum number of threads that can be used for the computation defined by\n    /// the `params` and input `iter_len`.\n    fn max_num_threads_for_computation(\n        &self,\n        params: Params,\n        iter_len: Option<usize>,\n    ) -> NonZeroUsize {\n        let pool = self.thread_pool().max_num_threads();\n\n        let env = crate::env::max_num_threads_by_env_variable().unwrap_or(NonZeroUsize::MAX);\n\n        let req = match (iter_len, params.num_threads) {\n            (Some(len), NumThreads::Auto) => NonZeroUsize::new(len.max(1)).expect(\">0\"),\n            (Some(len), NumThreads::Max(nt)) => NonZeroUsize::new(len.max(1)).expect(\">0\").min(nt),\n            (None, NumThreads::Auto) => NonZeroUsize::MAX,\n            (None, NumThreads::Max(nt)) => nt,\n        };\n\n        req.min(pool.min(env))\n    }\n}\n\npub(crate) type SharedStateOf<C> =\n    <<C as ParallelRunner>::Executor as ParallelExecutor>::SharedState;\npub(crate) type ThreadRunnerOf<C> =\n    <<C as ParallelRunner>::Executor as ParallelExecutor>::ThreadExecutor;\n\n// auto impl for &mut pool\n\nimpl<O> ParallelRunner for &'_ mut O\nwhere\n    O: ParallelRunner,\n{\n    type Executor = O::Executor;\n\n    type ThreadPool = O::ThreadPool;\n\n    fn thread_pool(&self) -> &Self::ThreadPool {\n        O::thread_pool(self)\n    }\n\n    fn thread_pool_mut(&mut self) -> &mut Self::ThreadPool {\n        O::thread_pool_mut(self)\n    }\n}\n"
  },
  {
    "path": "src/special_type_sets/mod.rs",
    "content": "mod sum;\n\npub use sum::Sum;\n"
  },
  {
    "path": "src/special_type_sets/sum.rs",
    "content": "use core::ops::Add;\n\n/// Number that can be summed over.\npub trait Sum<Output> {\n    /// Zero.\n    fn zero() -> Output;\n\n    /// Maps the number to owned value.\n    fn map(a: Self) -> Output;\n\n    /// Maps the number to owned value.\n    fn u_map<U>(_: &mut U, a: Self) -> Output;\n\n    /// Returns sum of `a` and `b`.\n    fn reduce(a: Output, b: Output) -> Output;\n\n    /// Returns sum of `a` and `b`.\n    fn u_reduce<U>(_: &mut U, a: Output, b: Output) -> Output;\n}\n\nimpl<X> Sum<X> for X\nwhere\n    X: Default + Add<X, Output = X>,\n{\n    fn zero() -> X {\n        X::default()\n    }\n\n    #[inline(always)]\n    fn map(a: Self) -> X {\n        a\n    }\n\n    #[inline(always)]\n    fn u_map<U>(_: &mut U, a: Self) -> X {\n        a\n    }\n\n    #[inline(always)]\n    fn reduce(a: X, b: X) -> X {\n        a + b\n    }\n\n    #[inline(always)]\n    fn u_reduce<U>(_: &mut U, a: X, b: X) -> X {\n        a + b\n    }\n}\n\nimpl<'a, X> Sum<X> for &'a X\nwhere\n    X: Default + Add<X, Output = X> + Copy,\n    &'a X: Add<&'a X, Output = X>,\n{\n    fn zero() -> X {\n        X::default()\n    }\n\n    #[inline(always)]\n    fn map(a: Self) -> X {\n        *a\n    }\n\n    #[inline(always)]\n    fn u_map<U>(_: &mut U, a: Self) -> X {\n        *a\n    }\n\n    #[inline(always)]\n    fn reduce(a: X, b: X) -> X {\n        a + b\n    }\n\n    #[inline(always)]\n    fn u_reduce<U>(_: &mut U, a: X, b: X) -> X {\n        a + b\n    }\n}\n\nimpl<'a, X> Sum<X> for &'a mut X\nwhere\n    X: Default + Add<X, Output = X> + Copy,\n    &'a X: Add<&'a X, Output = X>,\n{\n    fn zero() -> X {\n        X::default()\n    }\n\n    #[inline(always)]\n    fn map(a: Self) -> X {\n        *a\n    }\n\n    #[inline(always)]\n    fn u_map<U>(_: &mut U, a: Self) -> X {\n        *a\n    }\n\n    #[inline(always)]\n    fn reduce(a: X, b: X) -> X {\n        a + b\n    }\n\n    #[inline(always)]\n    fn u_reduce<U>(_: &mut U, a: X, b: X) -> X {\n        a + b\n    }\n}\n"
  },
  {
    "path": "src/test_utils.rs",
    "content": "/// Input size.\n#[cfg(not(miri))]\npub const N: &[usize] = &[8025, 42735];\n/// Number of threads.\n#[cfg(not(miri))]\npub const NT: &[usize] = &[0, 1, 2, 4];\n/// Chunk size.\n#[cfg(not(miri))]\npub const CHUNK: &[usize] = &[0, 1, 64, 1024];\n\n/// Input size.\n#[cfg(miri)]\npub const N: &[usize] = &[57];\n/// Number of threads.\n#[cfg(miri)]\npub const NT: &[usize] = &[1, 2];\n/// Chunk size.\n#[cfg(miri)]\npub const CHUNK: &[usize] = &[4];\n\n/// Test all combinations of the settings with the `test` method.\npub fn test_n_nt_chunk<T>(n: &[usize], nt: &[usize], chunk: &[usize], test: T)\nwhere\n    T: Fn(usize, usize, usize),\n{\n    for n in n {\n        for nt in nt {\n            for chunk in chunk {\n                test(*n, *nt, *chunk);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/collect_into/collect.rs",
    "content": "use crate::Params;\nuse crate::generic_values::runner_results::{\n    Fallibility, Infallible, ParallelCollect, ParallelCollectArbitrary, Stop,\n};\nuse crate::runner::{NumSpawned, ParallelRunner};\nuse crate::using::executor::parallel_compute as prc;\nuse crate::using::using_variants::Using;\nuse crate::{IterationOrder, generic_values::Values};\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub fn map_collect_into<'using, U, R, I, O, M1, P>(\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    map1: M1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    O: Send,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    match (params.is_sequential(), params.iteration_order) {\n        (true, _) => (\n            NumSpawned::zero(),\n            map_collect_into_seq(using, iter, map1, pinned_vec),\n        ),\n        #[cfg(test)]\n        (false, IterationOrder::Arbitrary) => {\n            prc::collect_arbitrary::m(using, orchestrator, params, iter, map1, pinned_vec)\n        }\n        (false, _) => prc::collect_ordered::m(using, orchestrator, params, iter, map1, pinned_vec),\n    }\n}\n\nfn map_collect_into_seq<'using, U, I, O, M1, P>(using: U, iter: I, map1: M1, mut pinned_vec: P) -> P\nwhere\n    U: Using<'using>,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    O: Send,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    let mut u = using.into_inner();\n    let iter = iter.into_seq_iter();\n    for i in iter {\n        pinned_vec.push(map1(&mut u, i));\n    }\n    pinned_vec\n}\n\npub fn xap_collect_into<'using, U, R, I, Vo, X1, P>(\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values<Fallibility = Infallible>,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    match (params.is_sequential(), params.iteration_order) {\n        (true, _) => (\n            NumSpawned::zero(),\n            xap_collect_into_seq(using, iter, xap1, pinned_vec),\n        ),\n        (false, IterationOrder::Arbitrary) => {\n            let (num_threads, result) =\n                prc::collect_arbitrary::x(using, orchestrator, params, iter, xap1, pinned_vec);\n            let pinned_vec = match result {\n                ParallelCollectArbitrary::AllOrUntilWhileCollected { pinned_vec } => pinned_vec,\n            };\n            (num_threads, pinned_vec)\n        }\n        (false, IterationOrder::Ordered) => {\n            let (num_threads, result) =\n                prc::collect_ordered::x(using, orchestrator, params, iter, xap1, pinned_vec);\n            let pinned_vec = match result {\n                ParallelCollect::AllCollected { pinned_vec } => pinned_vec,\n                ParallelCollect::StoppedByWhileCondition {\n                    pinned_vec,\n                    stopped_idx: _,\n                } => pinned_vec,\n            };\n            (num_threads, pinned_vec)\n        }\n    }\n}\n\nfn xap_collect_into_seq<'using, U, I, Vo, X1, P>(\n    using: U,\n    iter: I,\n    xap1: X1,\n    mut pinned_vec: P,\n) -> P\nwhere\n    U: Using<'using>,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let mut u = using.into_inner();\n    let iter = iter.into_seq_iter();\n    for i in iter {\n        let vt = xap1(&mut u, i);\n        let done = vt.push_to_pinned_vec(&mut pinned_vec);\n        if Vo::sequential_push_to_stop(done).is_some() {\n            break;\n        }\n    }\n\n    pinned_vec\n}\n\npub fn xap_try_collect_into<'using, U, R, I, Vo, X1, P>(\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (\n    NumSpawned,\n    Result<P, <Vo::Fallibility as Fallibility>::Error>,\n)\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    match (params.is_sequential(), params.iteration_order) {\n        (true, _) => (\n            NumSpawned::zero(),\n            xap_try_collect_into_seq(using, iter, xap1, pinned_vec),\n        ),\n        (false, IterationOrder::Arbitrary) => {\n            let (nt, result) =\n                prc::collect_arbitrary::x(using, orchestrator, params, iter, xap1, pinned_vec);\n            (nt, result.into_result())\n        }\n        (false, IterationOrder::Ordered) => {\n            let (nt, result) =\n                prc::collect_ordered::x(using, orchestrator, params, iter, xap1, pinned_vec);\n            (nt, result.into_result())\n        }\n    }\n}\n\nfn xap_try_collect_into_seq<'using, U, I, Vo, X1, P>(\n    using: U,\n    iter: I,\n    xap1: X1,\n    mut pinned_vec: P,\n) -> Result<P, <Vo::Fallibility as Fallibility>::Error>\nwhere\n    U: Using<'using>,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let mut u = using.into_inner();\n    let iter = iter.into_seq_iter();\n    for i in iter {\n        let vt = xap1(&mut u, i);\n        let done = vt.push_to_pinned_vec(&mut pinned_vec);\n        if let Some(stop) = Vo::sequential_push_to_stop(done) {\n            match stop {\n                Stop::DueToWhile => return Ok(pinned_vec),\n                Stop::DueToError { error } => return Err(error),\n            }\n        }\n    }\n\n    Ok(pinned_vec)\n}\n"
  },
  {
    "path": "src/using/collect_into/fixed_vec.rs",
    "content": "use crate::Params;\nuse crate::generic_values::TransformableValues;\nuse crate::generic_values::runner_results::Infallible;\nuse crate::runner::ParallelRunner;\nuse crate::using::Using;\nuse crate::using::collect_into::u_par_collect_into::UParCollectIntoCore;\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::FixedVec;\n\nimpl<O> UParCollectIntoCore<O> for FixedVec<O>\nwhere\n    O: Send + Sync,\n{\n    fn u_m_collect_into<'using, U, R, I, M1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        map1: M1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    {\n        let vec = Vec::from(self);\n        FixedVec::from(vec.u_m_collect_into(using, orchestrator, params, iter, map1))\n    }\n\n    fn u_x_collect_into<'using, U, R, I, Vo, X1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    {\n        let vec = Vec::from(self);\n        FixedVec::from(vec.u_x_collect_into(using, orchestrator, params, iter, xap1))\n    }\n\n    fn u_x_try_collect_into<'using, U, R, I, Vo, X1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as crate::generic_values::runner_results::Fallibility>::Error>\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n        Vo: crate::generic_values::Values<Item = O>,\n        Self: Sized,\n    {\n        let vec = Vec::from(self);\n        vec.u_x_try_collect_into(using, orchestrator, params, iter, xap1)\n            .map(FixedVec::from)\n    }\n}\n"
  },
  {
    "path": "src/using/collect_into/mod.rs",
    "content": "pub(crate) mod collect;\nmod fixed_vec;\nmod split_vec;\nmod u_par_collect_into;\nmod vec;\n\npub(crate) use u_par_collect_into::UParCollectIntoCore;\n"
  },
  {
    "path": "src/using/collect_into/split_vec.rs",
    "content": "use crate::Params;\nuse crate::collect_into::utils::split_vec_reserve;\nuse crate::generic_values::TransformableValues;\nuse crate::generic_values::runner_results::Infallible;\nuse crate::runner::ParallelRunner;\nuse crate::using::Using;\nuse crate::using::collect_into::collect::{\n    map_collect_into, xap_collect_into, xap_try_collect_into,\n};\nuse crate::using::collect_into::u_par_collect_into::UParCollectIntoCore;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_split_vec::{GrowthWithConstantTimeAccess, PseudoDefault, SplitVec};\n\nimpl<O, G> UParCollectIntoCore<O> for SplitVec<O, G>\nwhere\n    O: Send + Sync,\n    G: GrowthWithConstantTimeAccess,\n    Self: PseudoDefault,\n{\n    fn u_m_collect_into<'using, U, R, I, M1>(\n        mut self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        map1: M1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    {\n        split_vec_reserve(&mut self, params.is_sequential(), iter.try_get_len());\n        let (_, pinned_vec) = map_collect_into(using, orchestrator, params, iter, map1, self);\n        pinned_vec\n    }\n\n    fn u_x_collect_into<'using, U, R, I, Vo, X1>(\n        mut self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    {\n        split_vec_reserve(&mut self, params.is_sequential(), iter.try_get_len());\n        let (_num_spawned, pinned_vec) =\n            xap_collect_into(using, orchestrator, params, iter, xap1, self);\n        pinned_vec\n    }\n\n    fn u_x_try_collect_into<'using, U, R, I, Vo, X1>(\n        mut self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as crate::generic_values::runner_results::Fallibility>::Error>\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n        Vo: crate::generic_values::Values<Item = O>,\n        Self: Sized,\n    {\n        split_vec_reserve(&mut self, params.is_sequential(), iter.try_get_len());\n        let (_num_spawned, result) =\n            xap_try_collect_into(using, orchestrator, params, iter, xap1, self);\n        result\n    }\n}\n"
  },
  {
    "path": "src/using/collect_into/u_par_collect_into.rs",
    "content": "use crate::Params;\nuse crate::collect_into::ParCollectIntoCore;\nuse crate::generic_values::runner_results::{Fallibility, Infallible};\nuse crate::generic_values::{TransformableValues, Values};\nuse crate::runner::ParallelRunner;\nuse crate::using::using_variants::Using;\nuse orx_concurrent_iter::ConcurrentIter;\n\npub trait UParCollectIntoCore<O>: ParCollectIntoCore<O> {\n    fn u_m_collect_into<'using, U, R, I, M1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        map1: M1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(&mut U::Item, I::Item) -> O + Sync;\n\n    fn u_x_collect_into<'using, U, R, I, Vo, X1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync;\n\n    fn u_x_try_collect_into<'using, U, R, I, Vo, X1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as Fallibility>::Error>\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n        Vo: Values<Item = O>,\n        Self: Sized;\n}\n"
  },
  {
    "path": "src/using/collect_into/vec.rs",
    "content": "use crate::Params;\nuse crate::collect_into::utils::extend_vec_from_split;\nuse crate::generic_values::TransformableValues;\nuse crate::generic_values::runner_results::Infallible;\nuse crate::runner::ParallelRunner;\nuse crate::using::collect_into::collect::map_collect_into;\nuse crate::using::collect_into::u_par_collect_into::UParCollectIntoCore;\nuse crate::using::using_variants::Using;\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::FixedVec;\nuse orx_split_vec::SplitVec;\n\nimpl<O> UParCollectIntoCore<O> for Vec<O>\nwhere\n    O: Send + Sync,\n{\n    fn u_m_collect_into<'using, U, R, I, M1>(\n        mut self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        map1: M1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    {\n        match iter.try_get_len() {\n            None => {\n                let split_vec = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n                let split_vec = split_vec.u_m_collect_into(using, orchestrator, params, iter, map1);\n                extend_vec_from_split(self, split_vec)\n            }\n            Some(len) => {\n                self.reserve(len);\n                let fixed_vec = FixedVec::from(self);\n                let (_, fixed_vec) =\n                    map_collect_into(using, orchestrator, params, iter, map1, fixed_vec);\n                Vec::from(fixed_vec)\n            }\n        }\n    }\n\n    fn u_x_collect_into<'using, U, R, I, Vo, X1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Self\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        Vo: TransformableValues<Item = O, Fallibility = Infallible>,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    {\n        let split_vec = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n        let split_vec = split_vec.u_x_collect_into(using, orchestrator, params, iter, xap1);\n        extend_vec_from_split(self, split_vec)\n    }\n\n    fn u_x_try_collect_into<'using, U, R, I, Vo, X1>(\n        self,\n        using: U,\n        orchestrator: R,\n        params: Params,\n        iter: I,\n        xap1: X1,\n    ) -> Result<Self, <Vo::Fallibility as crate::generic_values::runner_results::Fallibility>::Error>\n    where\n        U: Using<'using>,\n        R: ParallelRunner,\n        I: ConcurrentIter,\n        X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n        Vo: crate::generic_values::Values<Item = O>,\n        Self: Sized,\n    {\n        let split_vec = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n        let result = split_vec.u_x_try_collect_into(using, orchestrator, params, iter, xap1);\n        result.map(|split_vec| extend_vec_from_split(self, split_vec))\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/mod.rs",
    "content": "#[cfg(test)]\nmod tests;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with None.\npub mod u_fallible_option;\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub mod u_fallible_result;\n\nmod u_map;\nmod u_par;\nmod u_xap;\n\npub use u_map::UParMap;\npub use u_par::UPar;\npub use u_xap::UParXap;\n"
  },
  {
    "path": "src/using/computational_variants/tests/copied.rs",
    "content": "use super::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::vec::Vec;\nuse std::string::ToString;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<usize>>(n: usize) -> O {\n    (0..n).collect()\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input: Vec<_> = input::<Vec<_>>(n);\n        let expected: usize = input.iter().copied().sum();\n        let par = || {\n            input\n                .par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n        };\n\n        let output = par().copied().sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let map = |x: usize| x + 1;\n        let expected: usize = input.iter().copied().map(&map).sum();\n        let par = || {\n            input\n                .par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n        };\n\n        let output = par().copied().map(make_u_map(map)).sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().map(make_u_map(map)).sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let flat_map = |x: usize| [x, x + 1, x + 2];\n        let expected: usize = input.iter().copied().flat_map(&flat_map).sum();\n        let par = || {\n            input\n                .par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n        };\n\n        let output = par().copied().flat_map(make_u_map(flat_map)).sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().flat_map(make_u_map(flat_map)).sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: usize| (!x.is_multiple_of(3)).then_some(x + 1);\n        let expected: usize = input.iter().copied().filter_map(&filter_map).sum();\n        let par = || {\n            input\n                .par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n        };\n\n        let output = par().copied().filter_map(make_u_map(filter_map)).sum();\n        assert_eq!(output, expected);\n\n        let output = par().cloned().filter_map(make_u_map(filter_map)).sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn copied_cloned_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: usize| (!x.is_multiple_of(3)).then_some(x + 1);\n        let filter = |x: &usize| x % 3 != 1;\n        let flat_map = |x: usize| [x, x + 1, x + 2];\n        let expected: usize = input\n            .iter()\n            .copied()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .flat_map(&flat_map)\n            .sum();\n        let par = || {\n            input\n                .par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n        };\n\n        let output = par()\n            .copied()\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .flat_map(make_u_map(flat_map))\n            .sum();\n        assert_eq!(output, expected);\n\n        let output = par()\n            .cloned()\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .flat_map(make_u_map(flat_map))\n            .sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/count.rs",
    "content": "use super::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = n;\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = n;\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.map(make_u_map(|x| format!(\"{}!\", x)));\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n        let expected = input.clone().into_iter().flat_map(&flat_map).count();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.flat_map(make_u_map(flat_map));\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let expected = input.clone().into_iter().filter_map(&filter_map).count();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.filter_map(make_u_map(filter_map));\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn count_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n        let expected = input\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .flat_map(&flat_map)\n            .count();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .flat_map(make_u_map(flat_map));\n        let output = par.count();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/fallible_option.rs",
    "content": "use crate::using::computational_variants::tests::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[test_matrix(NT, CHUNK)]\nfn fallible_option_collect_empty(nt: &[usize], chunk: &[usize]) {\n    let test = |_, nt, chunk| {\n        let input = || input::<Vec<_>>(0);\n\n        let par = input()\n            .into_iter()\n            .map(|_| None::<String>)\n            .collect::<Vec<_>>()\n            .into_par()\n            .using_clone(\"XyZw\".to_string())\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .into_fallible_option();\n        let output: Option<Vec<_>> = par.collect();\n\n        assert_eq!(output, Some(Vec::new()));\n    };\n    test_n_nt_chunk(&[0], nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_option_collect_partial_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input()\n            .into_par()\n            .using_clone(\"XyZw\".to_string())\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(make_u_map(|x| (x != \"50\").then_some(x)))\n            .into_fallible_option()\n            .filter(make_u_filter(&|x: &String| !x.ends_with('9')))\n            .flat_map(make_u_map(|x| [format!(\"{x}?\"), x]))\n            .map(make_u_map(|x| format!(\"{x}!\")));\n        let output: Option<Vec<_>> = par.collect();\n\n        assert_eq!(output, None);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_option_collect_complete_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let expected: Vec<_> = input()\n            .into_iter()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"))\n            .filter_map(Some)\n            .collect();\n\n        let par = input()\n            .into_par()\n            .using_clone(\"XyZw\".to_string())\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(make_u_map(|x| (x != \"xyz\").then_some(x)))\n            .into_fallible_option()\n            .filter(make_u_filter(&|x: &String| !x.ends_with('9')))\n            .flat_map(make_u_map(|x| [format!(\"{x}?\"), x]))\n            .map(make_u_map(|x| format!(\"{x}!\")))\n            .filter_map(make_u_map(Some));\n        let output: Option<Vec<_>> = par.collect();\n\n        assert_eq!(output, Some(expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/fallible_result.rs",
    "content": "use crate::using::computational_variants::tests::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[derive(Debug, PartialEq, Eq)]\nstruct MyErr(String);\nimpl MyErr {\n    fn new() -> Self {\n        Self(\"error\".to_string())\n    }\n}\n\n#[test_matrix(NT, CHUNK)]\nfn fallible_result_collect_empty(nt: &[usize], chunk: &[usize]) {\n    let test = |_, nt, chunk| {\n        let input = || input::<Vec<_>>(0);\n\n        let par = input()\n            .into_iter()\n            .map(|_| Err::<String, _>(MyErr::new()))\n            .collect::<Vec<_>>()\n            .into_par()\n            .using_clone(\"XyZw\".to_string())\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .into_fallible_result();\n        let output: Result<Vec<_>, MyErr> = par.collect();\n\n        assert_eq!(output, Ok(Vec::new()));\n    };\n    test_n_nt_chunk(&[0], nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_result_collect_partial_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input()\n            .into_par()\n            .using_clone(\"XyZw\".to_string())\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(make_u_map(|x| match x == \"50\" {\n                true => Err(MyErr::new()),\n                false => Ok(x),\n            }))\n            .into_fallible_result()\n            .filter(make_u_filter(&|x: &String| !x.ends_with('9')))\n            .flat_map(make_u_map(|x| [format!(\"{x}?\"), x]))\n            .map(make_u_map(|x| format!(\"{x}!\")));\n        let output: Result<Vec<_>, MyErr> = par.collect();\n\n        assert_eq!(output, Err(MyErr::new()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn fallible_result_collect_complete_success(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let expected: Vec<_> = input()\n            .into_iter()\n            .filter(|x| !x.ends_with('9'))\n            .flat_map(|x| [format!(\"{x}?\"), x])\n            .map(|x| format!(\"{x}!\"))\n            .filter_map(Some)\n            .collect();\n\n        let par = input()\n            .into_par()\n            .using_clone(\"XyZw\".to_string())\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .map(make_u_map(|x| match x == \"xyz\" {\n                true => Err(MyErr::new()),\n                false => Ok(x),\n            }))\n            .into_fallible_result()\n            .filter(make_u_filter(&|x: &String| !x.ends_with('9')))\n            .flat_map(make_u_map(|x| [format!(\"{x}?\"), x]))\n            .map(make_u_map(|x| format!(\"{x}!\")))\n            .filter_map(make_u_map(Some));\n        let output: Result<Vec<_>, MyErr> = par.collect();\n\n        assert_eq!(output, Ok(expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/flatten.rs",
    "content": "use super::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse alloc::{format, vec};\nuse test_case::test_matrix;\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || {\n            (0..n)\n                .map(|i| [i.to_string(), (i + 1).to_string()])\n                .collect::<Vec<_>>()\n        };\n\n        let expected: Vec<_> = input().into_iter().flatten().collect();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<_> = par.flatten().collect();\n\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || (0..n).collect::<Vec<_>>();\n        let map = |i: usize| vec![i.to_string(), (i + 1).to_string()];\n\n        #[allow(clippy::map_flatten)]\n        let expected: Vec<_> = input().into_iter().map(&map).flatten().collect();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<_> = par.map(make_u_map(map)).flatten().collect();\n\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || (0..n).map(|i| i.to_string()).collect::<Vec<_>>();\n        let filter_map = |x: String| {\n            x.starts_with('3')\n                .then(|| vec![x.clone(), format!(\"{}!\", x)])\n        };\n\n        #[allow(clippy::map_flatten)]\n        let expected: Vec<_> = input()\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .flatten()\n            .collect();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<_> = par.filter_map(make_u_map(filter_map)).flatten().collect();\n\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn flatten_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || (0..n).map(|i| i.to_string()).collect::<Vec<_>>();\n        let filter_map = |x: String| {\n            x.starts_with('3')\n                .then(|| vec![x.clone(), format!(\"{}!\", x)])\n        };\n        let filter = |x: &Vec<String>| x.len() == 2;\n        let map = |mut x: Vec<String>| {\n            x.push(\"lorem\".to_string());\n            x\n        };\n        #[allow(clippy::map_flatten)]\n        let expected: Vec<_> = input()\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .map(&map)\n            .flatten()\n            .collect();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<_> = par\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .map(make_u_map(map))\n            .flatten()\n            .collect();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/for_each.rs",
    "content": "use super::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_vec::ConcurrentVec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn sorted(mut x: Vec<String>) -> Vec<String> {\n    x.sort();\n    x\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let vec = ConcurrentVec::new();\n        par.for_each(make_u_map(|x| {\n            _ = vec.push(x);\n        }));\n\n        assert_eq!(sorted(vec.to_vec()), sorted(input()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let map = |x| format!(\"{}!\", x);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.map(make_u_map(map));\n        let vec = ConcurrentVec::new();\n        par.for_each(make_u_map(|x| {\n            _ = vec.push(x);\n        }));\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().map(map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.flat_map(make_u_map(flat_map));\n        let vec = ConcurrentVec::new();\n        par.for_each(make_u_map(|x| {\n            _ = vec.push(x);\n        }));\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().flat_map(flat_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.filter_map(make_u_map(filter_map));\n        let vec = ConcurrentVec::new();\n        par.for_each(make_u_map(|x| {\n            _ = vec.push(x);\n        }));\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().filter_map(filter_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn for_each_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .flat_map(make_u_map(flat_map));\n        let vec = ConcurrentVec::new();\n        par.for_each(make_u_map(|x| {\n            _ = vec.push(x);\n        }));\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(\n                input()\n                    .into_iter()\n                    .filter_map(filter_map)\n                    .filter(filter)\n                    .flat_map(flat_map)\n                    .collect()\n            )\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/inspect.rs",
    "content": "use super::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_vec::ConcurrentVec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn sorted(mut x: Vec<String>) -> Vec<String> {\n    x.sort();\n    x\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let vec = ConcurrentVec::new();\n\n        par.inspect(|u, x| {\n            let u = u.as_mut_str();\n            u.get_mut(0..2).expect(\"len>1\").make_ascii_uppercase();\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(sorted(vec.to_vec()), sorted(input()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let map = |x| format!(\"{}!\", x);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.map(make_u_map(map));\n        let vec = ConcurrentVec::new();\n        par.inspect(|u, x| {\n            let u = u.as_mut_str();\n            u.get_mut(0..2).expect(\"len>1\").make_ascii_uppercase();\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().map(map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.flat_map(make_u_map(flat_map));\n        let vec = ConcurrentVec::new();\n        par.inspect(|u, x| {\n            let u = u.as_mut_str();\n            u.get_mut(0..2).expect(\"len>1\").make_ascii_uppercase();\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().flat_map(flat_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.filter_map(make_u_map(filter_map));\n        let vec = ConcurrentVec::new();\n        par.inspect(|u, x| {\n            let u = u.as_mut_str();\n            u.get_mut(0..2).expect(\"len>1\").make_ascii_uppercase();\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(input().into_iter().filter_map(filter_map).collect())\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn inspect_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n\n        let par = input()\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .flat_map(make_u_map(flat_map));\n        let vec = ConcurrentVec::new();\n        par.inspect(|u, x| {\n            let u = u.as_mut_str();\n            u.get_mut(0..2).expect(\"len>1\").make_ascii_uppercase();\n            _ = vec.push(x.clone());\n        })\n        .count();\n\n        assert_eq!(\n            sorted(vec.to_vec()),\n            sorted(\n                input()\n                    .into_iter()\n                    .filter_map(filter_map)\n                    .filter(filter)\n                    .flat_map(flat_map)\n                    .collect()\n            )\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/iter_consuming.rs",
    "content": "use super::utils::make_u_map;\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Collection;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\nconst N_OFFSET: usize = 13;\n\nfn offset() -> Vec<String> {\n    vec![\"x\".to_string(); N_OFFSET]\n}\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(\n    with_offset: bool,\n    input: &impl Collection<Item = String>,\n    map: impl Fn(String) -> String,\n) -> Vec<String> {\n    match with_offset {\n        true => {\n            let mut vec = offset();\n            vec.extend(input.iter().cloned().map(map));\n            vec\n        }\n        false => input.iter().cloned().map(map).collect(),\n    }\n}\n\n// collect - empty\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn empty_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &vec, |x| x);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input\n            .iter_into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn empty_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(false, &vec, |x| x);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input\n            .iter_into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: C = par.collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn map_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &vec, map);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input\n            .iter_into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.map(make_u_map(map)).collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(false, &vec, map);\n        let input = vec.into_iter().filter(|x| x.as_str() != \"?\");\n        let par = input\n            .iter_into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: C = par.map(make_u_map(map)).collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/iter_ref.rs",
    "content": "use super::utils::make_u_map;\nuse crate::{collect_into::ParCollectIntoCore, test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::{Collection, IntoCloningIterable};\nuse orx_split_vec::{Doubling, Linear, PseudoDefault, SplitVec};\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(input: &impl Collection<Item = String>, map: impl Fn(String) -> String) -> Vec<String> {\n    input.iter().cloned().map(map).collect()\n}\n\n// collect - empty\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, |x| x);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(Vec::new());\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(FixedVec::pseudo_default());\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(SplitVec::<_, Doubling>::pseudo_default());\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(SplitVec::<_, Linear>::pseudo_default());\n        assert!(output.is_equal_to_ref(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, |x| x);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: FixedVec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: SplitVec<&String, Doubling> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: SplitVec<&String, Linear> = par.collect();\n        assert!(output.is_equal_to_ref(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, map2);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<String> = par.map(make_u_map(map)).collect_into(vec![]);\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<_>>(n);\n        let expected = expected(&vec, map2);\n        let input = vec.iter().filter(|x| x.as_str() != \"?\").into_iterable();\n\n        let par = input\n            .par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<String> = par.map(make_u_map(map)).collect();\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/map/collect.rs",
    "content": "use super::super::utils::make_u_map;\nuse crate::using::UsingClone;\nuse crate::using::collect_into::collect::map_collect_into;\nuse crate::{IterationOrder, Params, runner::DefaultRunner};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn m_map_collect(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let value = || map(i.to_string());\n        output.push(value());\n        expected.push(value());\n    }\n    expected.extend(input.clone().into_iter().map(map));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let (_, mut output) = map_collect_into(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_map(map),\n        output,\n    );\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/map/find.rs",
    "content": "use crate::using::UsingClone;\nuse crate::using::computational_variants::tests::utils::make_u_map;\nuse crate::{\n    Params, default_fns::map_self, runner::DefaultRunner, using::executor::parallel_compute,\n};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n\n    let expected = input.clone().into_iter().next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n\n    let output = parallel_compute::next::m(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_map(map_self),\n    )\n    .1;\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_map_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n\n    let expected = input.clone().into_iter().map(map).next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let output = parallel_compute::next::m(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_map(map),\n    )\n    .1;\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/map/mod.rs",
    "content": "mod collect;\nmod find;\nmod reduce;\n"
  },
  {
    "path": "src/using/computational_variants/tests/map/reduce.rs",
    "content": "use crate::using::UsingClone;\nuse crate::using::computational_variants::tests::utils::{make_u_map, make_u_reduce};\nuse crate::{\n    Params, default_fns::map_self, runner::DefaultRunner, using::executor::parallel_compute,\n};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let reduce = |x: String, y: String| match x < y {\n        true => y,\n        false => x,\n    };\n\n    let expected = input.clone().into_iter().reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let (_, output) = parallel_compute::reduce::m(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_map(map_self),\n        make_u_reduce(reduce),\n    );\n\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn m_map_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let map = |x: String| format!(\"{}!\", x);\n    let reduce = |x: String, y: String| match x < y {\n        true => y,\n        false => x,\n    };\n\n    let expected = input.clone().into_iter().map(map).reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let (_, output) = parallel_compute::reduce::m(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_map(map),\n        make_u_reduce(reduce),\n    );\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/min_max.rs",
    "content": "use crate::using::computational_variants::tests::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse core::cmp::Ordering;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn cmp(a: &usize, b: &usize) -> Ordering {\n    match a < b {\n        true => Ordering::Less,\n        false => Ordering::Greater,\n    }\n}\n\nfn key(a: &usize) -> u64 {\n    *a as u64 + 10\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || {\n            input::<Vec<_>>(n)\n                .iter()\n                .map(|x| x.parse::<usize>().expect(\"is-ok\"))\n                .collect::<Vec<_>>()\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n        };\n\n        assert_eq!(par().min(), input().iter().min().copied());\n        assert_eq!(par().max(), input().iter().max().copied());\n\n        assert_eq!(par().min_by(cmp), input().into_iter().min_by(cmp));\n        assert_eq!(par().max_by(cmp), input().into_iter().max_by(cmp));\n\n        assert_eq!(par().min_by_key(key), input().into_iter().min_by_key(key));\n        assert_eq!(par().max_by_key(key), input().into_iter().max_by_key(key));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let map = |x: String| x.parse::<usize>().expect(\"is-ok\");\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n                .map(make_u_map(map))\n        };\n\n        assert_eq!(par().min(), input().into_iter().map(&map).min());\n        assert_eq!(par().max(), input().into_iter().map(&map).max());\n\n        assert_eq!(par().min_by(cmp), input().into_iter().map(&map).min_by(cmp));\n        assert_eq!(par().max_by(cmp), input().into_iter().map(&map).max_by(cmp));\n\n        assert_eq!(\n            par().min_by_key(key),\n            input().into_iter().map(&map).min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input().into_iter().map(&map).max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let flat_map = |x: String| {\n            let n = x.len();\n            let a = x.parse::<usize>().expect(\"is-ok\");\n            (0..n).map(|i| a + i).collect::<Vec<_>>()\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n                .flat_map(make_u_map(flat_map))\n        };\n\n        assert_eq!(par().min(), input().into_iter().flat_map(&flat_map).min());\n        assert_eq!(par().max(), input().into_iter().flat_map(&flat_map).max());\n\n        assert_eq!(\n            par().min_by(cmp),\n            input().into_iter().flat_map(&flat_map).min_by(cmp)\n        );\n        assert_eq!(\n            par().max_by(cmp),\n            input().into_iter().flat_map(&flat_map).max_by(cmp)\n        );\n\n        assert_eq!(\n            par().min_by_key(key),\n            input().into_iter().flat_map(&flat_map).min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input().into_iter().flat_map(&flat_map).max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| {\n            x.starts_with('3')\n                .then(|| x.parse::<usize>().expect(\"is-ok\"))\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n                .filter_map(make_u_map(filter_map))\n        };\n\n        assert_eq!(\n            par().min(),\n            input().into_iter().filter_map(&filter_map).min()\n        );\n        assert_eq!(\n            par().max(),\n            input().into_iter().filter_map(&filter_map).max()\n        );\n\n        assert_eq!(\n            par().min_by(cmp),\n            input().into_iter().filter_map(&filter_map).min_by(cmp)\n        );\n        assert_eq!(\n            par().max_by(cmp),\n            input().into_iter().filter_map(&filter_map).max_by(cmp)\n        );\n\n        assert_eq!(\n            par().min_by_key(key),\n            input().into_iter().filter_map(&filter_map).min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input().into_iter().filter_map(&filter_map).max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn min_max_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = || input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| {\n            let n = x.len();\n            let a = x.parse::<usize>().expect(\"is-ok\");\n            (0..n).map(|i| a + i).collect::<Vec<_>>()\n        };\n\n        let par = || {\n            input()\n                .into_par()\n                .num_threads(nt)\n                .chunk_size(chunk)\n                .using_clone(\"XyZw\".to_string())\n                .filter_map(make_u_map(filter_map))\n                .filter(make_u_filter(&filter))\n                .flat_map(make_u_map(flat_map))\n        };\n\n        assert_eq!(\n            par().min(),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .min()\n        );\n        assert_eq!(\n            par().max(),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .max()\n        );\n\n        assert_eq!(\n            par().min_by(cmp),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .min_by(cmp)\n        );\n        assert_eq!(\n            par().max_by(cmp),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .max_by(cmp)\n        );\n\n        assert_eq!(\n            par().min_by_key(key),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .min_by_key(key)\n        );\n        assert_eq!(\n            par().max_by_key(key),\n            input()\n                .into_iter()\n                .filter_map(&filter_map)\n                .filter(&filter)\n                .flat_map(&flat_map)\n                .max_by_key(key)\n        );\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/mod.rs",
    "content": "mod utils;\n\nmod copied;\nmod count;\nmod fallible_option;\nmod fallible_result;\nmod flatten;\nmod for_each;\nmod inspect;\nmod iter_consuming;\nmod iter_ref;\nmod map;\nmod min_max;\nmod range;\nmod slice;\nmod sum;\nmod vectors;\nmod xap;\n"
  },
  {
    "path": "src/using/computational_variants/tests/range.rs",
    "content": "use crate::using::computational_variants::tests::utils::make_u_map;\nuse crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Iterable;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\nconst N_OFFSET: usize = 13;\n\nfn offset() -> Vec<usize> {\n    vec![9; N_OFFSET]\n}\n\nfn expected<T>(\n    with_offset: bool,\n    input: impl Iterable<Item = usize>,\n    map: impl Fn(usize) -> T + Copy,\n) -> Vec<T> {\n    match with_offset {\n        true => {\n            let mut vec: Vec<_> = offset().into_iter().map(map).collect();\n            vec.extend(input.iter().map(map));\n            vec\n        }\n        false => input.iter().map(map).collect(),\n    }\n}\n\n// collect - empty\n\n#[test_matrix(\n    [Vec::<usize>::new(), SplitVec::<usize>::new(), FixedVec::<usize>::new(0), Vec::<usize>::from_iter(offset()), SplitVec::<usize>::from_iter(offset()), FixedVec::<usize>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn empty_collect_into<C>(output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<usize> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let input = 0..n;\n        let expected = expected(!output.is_empty(), input.clone(), |x| x);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<usize>::new(), SplitVec::<usize>::new(), FixedVec::<usize>::new(0)],\n    N, NT, CHUNK)\n]\nfn empty_collect<C>(_: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<usize>,\n{\n    let test = |n, nt, chunk| {\n        let input = 0..n;\n        let expected = expected(false, input.clone(), |x| x);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: C = par.collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect_into<C>(output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let map = |x: usize| x.to_string();\n        let input = 0..n;\n        let expected = expected(!output.is_empty(), input.clone(), map);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.map(make_u_map(map)).collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect<C>(_: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let map = |x: usize| x.to_string();\n        let input = 0..n;\n        let expected = expected(false, input.clone(), map);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: C = par.map(make_u_map(map)).collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/slice.rs",
    "content": "use crate::using::computational_variants::tests::utils::make_u_map;\nuse crate::{collect_into::ParCollectIntoCore, test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Collection;\nuse orx_split_vec::{Doubling, Linear, PseudoDefault, SplitVec};\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(input: &impl Collection<Item = String>, map: impl Fn(String) -> String) -> Vec<String> {\n    input.iter().cloned().map(map).collect()\n}\n\n// collect - empty\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, |x| x);\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(Vec::new());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(FixedVec::pseudo_default());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(SplitVec::<_, Doubling>::pseudo_default());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(SplitVec::<_, Linear>::pseudo_default());\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn empty_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, |x| x);\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: FixedVec<&String> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: SplitVec<&String, Doubling> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: SplitVec<&String, Linear> = par.collect();\n        assert!(output.is_equal_to_ref(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect_into(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, map2);\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<String> = par.map(make_u_map(map)).collect_into(vec![]);\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn map_collect(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let map = |x: &String| format!(\"{}!\", x);\n        let map2 = |x: String| format!(\"{}!\", x);\n\n        let vec = input::<Vec<String>>(n);\n        let input = vec.as_slice();\n        let expected = expected(&vec, map2);\n\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: Vec<String> = par.map(make_u_map(map)).collect();\n        assert!(output.is_equal_to(expected.as_slice()));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/sum.rs",
    "content": "use crate::using::computational_variants::tests::utils::{make_u_filter, make_u_map};\nuse crate::{test_utils::*, *};\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse test_case::test_matrix;\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_empty(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input: Vec<_> = input::<Vec<_>>(n).iter().map(|x| x.len()).collect();\n        let expected: usize = input.iter().sum();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let map = |x: String| x.len();\n        let expected: usize = input.clone().into_iter().map(&map).sum();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.map(make_u_map(map));\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_xap_flat_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let flat_map = |x: String| x.chars().map(|x| x.to_string().len()).collect::<Vec<_>>();\n        let expected: usize = input.clone().into_iter().flat_map(&flat_map).sum();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.flat_map(make_u_map(flat_map));\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_xap_filter_map(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x.len());\n        let expected: usize = input.clone().into_iter().filter_map(&filter_map).sum();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par.filter_map(make_u_map(filter_map));\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(N, NT, CHUNK)]\nfn sum_xap_filter_xap(n: &[usize], nt: &[usize], chunk: &[usize]) {\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let filter_map = |x: String| x.starts_with('3').then_some(x);\n        let filter = |x: &String| x.ends_with('3');\n        let flat_map = |x: String| x.chars().map(|x| x.to_string().len()).collect::<Vec<_>>();\n        let expected: usize = input\n            .clone()\n            .into_iter()\n            .filter_map(&filter_map)\n            .filter(&filter)\n            .flat_map(&flat_map)\n            .sum();\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let par = par\n            .filter_map(make_u_map(filter_map))\n            .filter(make_u_filter(&filter))\n            .flat_map(make_u_map(flat_map));\n        let output = par.sum();\n        assert_eq!(output, expected);\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/utils.rs",
    "content": "use std::string::String;\n\npub(super) fn make_u_map<I, O>(\n    map: impl Fn(I) -> O + Clone,\n) -> impl Fn(&mut String, I) -> O + Clone {\n    move |u: &mut String, x: I| {\n        let u = u.as_mut_str();\n        u.get_mut(0..2)\n            .expect(\"must have len>1\")\n            .make_ascii_uppercase();\n        map(x)\n    }\n}\n\npub(super) fn make_u_xap<I, O>(\n    map: impl Fn(I) -> O + Clone,\n) -> impl Fn(*mut String, I) -> O + Clone {\n    move |u: *mut String, x: I| {\n        // SAFETY: TODO-USING\n        let u = unsafe { &mut *u };\n        let u = u.as_mut_str();\n        u.get_mut(0..2)\n            .expect(\"must have len>1\")\n            .make_ascii_uppercase();\n        map(x)\n    }\n}\n\npub(super) fn make_u_filter<I>(\n    filter: &impl Fn(&I) -> bool,\n) -> impl Fn(&mut String, &I) -> bool + Clone {\n    |u: &mut String, x: &I| {\n        let u = u.as_mut_str();\n        u.get_mut(0..2)\n            .expect(\"must have len>1\")\n            .make_ascii_uppercase();\n        filter(x)\n    }\n}\n\npub(super) fn make_u_reduce<I>(\n    reduce: impl Fn(I, I) -> I + Clone,\n) -> impl Fn(&mut String, I, I) -> I + Clone {\n    move |u: &mut String, x: I, y: I| {\n        let u = u.as_mut_str();\n        u.get_mut(0..2)\n            .expect(\"must have len>1\")\n            .make_ascii_uppercase();\n        reduce(x, y)\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/vectors.rs",
    "content": "use crate::using::computational_variants::tests::utils::make_u_map;\nuse crate::{test_utils::*, *};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse orx_fixed_vec::FixedVec;\nuse orx_iterable::Collection;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\nconst N_OFFSET: usize = 13;\n\nfn offset() -> Vec<String> {\n    vec![\"x\".to_string(); N_OFFSET]\n}\n\nfn input<O: FromIterator<String>>(n: usize) -> O {\n    let elem = |x: usize| (x + 10).to_string();\n    (0..n).map(elem).collect()\n}\n\nfn expected(\n    with_offset: bool,\n    input: &impl Collection<Item = String>,\n    map: impl Fn(String) -> String,\n) -> Vec<String> {\n    match with_offset {\n        true => {\n            let mut vec = offset();\n            vec.extend(input.iter().cloned().map(map));\n            vec\n        }\n        false => input.iter().cloned().map(map).collect(),\n    }\n}\n\n// collect - empty\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\nN, NT, CHUNK)\n]\nfn empty_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &input, |x| x);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn empty_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let input = input::<Vec<_>>(n);\n        let expected = expected(false, &input, |x| x);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: C = par.collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n// collect - map\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0), Vec::<String>::from_iter(offset()), SplitVec::<String>::from_iter(offset()), FixedVec::<String>::from_iter(offset()) ],\n    N, NT, CHUNK)\n]\nfn map_collect_into<I, C>(_: I, output: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String> + Clone,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let input = input::<Vec<_>>(n);\n        let expected = expected(!output.is_empty(), &input, map);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output = par.map(make_u_map(map)).collect_into(output.clone());\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n\n#[test_matrix(\n    [Vec::<String>::new()],\n    [Vec::<String>::new(), SplitVec::<String>::new(), FixedVec::<String>::new(0)],\n    N, NT, CHUNK)\n]\nfn map_collect<I, C>(_: I, _: C, n: &[usize], nt: &[usize], chunk: &[usize])\nwhere\n    I: FromIterator<String> + Collection<Item = String> + IntoParIter<Item = String>,\n    C: ParCollectInto<String>,\n{\n    let test = |n, nt, chunk| {\n        let map = |x| format!(\"{}!\", x);\n        let input = input::<Vec<_>>(n);\n        let expected = expected(false, &input, map);\n        let par = input\n            .into_par()\n            .num_threads(nt)\n            .chunk_size(chunk)\n            .using_clone(\"XyZw\".to_string());\n        let output: C = par.map(make_u_map(map)).collect();\n        assert!(output.is_equal_to(&expected));\n    };\n    test_n_nt_chunk(n, nt, chunk, test);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/xap/collect.rs",
    "content": "use crate::generic_values::Vector;\nuse crate::runner::DefaultRunner;\nuse crate::using::UsingClone;\nuse crate::using::computational_variants::UParXap;\nuse crate::using::computational_variants::tests::utils::make_u_xap;\nuse crate::using::u_par_iter::ParIterUsing;\nuse crate::{IterationOrder, Params};\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse orx_pinned_vec::PinnedVec;\nuse orx_split_vec::SplitVec;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test]\nfn todo_panic_at_con_bag_new() {\n    // TODO: this code panics when ParThreadPool::map uses ConcurrentBag::new rather than ConcurrentBag::with_fixed_capacity\n    let n = 10;\n    let nt = 2;\n    let chunk = 1;\n    let ordering = IterationOrder::Arbitrary;\n\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let i = i.to_string();\n        for x in fmap(i) {\n            output.push(x.clone());\n            expected.push(x);\n        }\n    }\n    expected.extend(input.clone().into_iter().flat_map(&fmap));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let mut output = x.collect_into(output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn x_flat_map_collect(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let i = i.to_string();\n        for x in fmap(i) {\n            output.push(x.clone());\n            expected.push(x);\n        }\n    }\n    expected.extend(input.clone().into_iter().flat_map(&fmap));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let mut output = x.collect_into(output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64],\n    [IterationOrder::Ordered, IterationOrder::Arbitrary])\n]\nfn x_filter_map_collect(n: usize, nt: usize, chunk: usize, ordering: IterationOrder) {\n    let offset = 33;\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| (!x.starts_with('3')).then_some(format!(\"{}!\", x));\n    let xmap = |x: String| Vector(fmap(x));\n\n    let mut output = SplitVec::with_doubling_growth_and_max_concurrent_capacity();\n    let mut expected = Vec::new();\n\n    for i in 0..offset {\n        let i = i.to_string();\n        if let Some(x) = fmap(i) {\n            output.push(x.clone());\n            expected.push(x);\n        }\n    }\n    expected.extend(input.clone().into_iter().flat_map(&fmap));\n\n    let params = Params::new(nt, chunk, ordering);\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let mut output = x.collect_into(output);\n\n    if !params.is_sequential() && matches!(params.iteration_order, IterationOrder::Arbitrary) {\n        expected.sort();\n        output.sort();\n    }\n\n    assert_eq!(expected, output.to_vec());\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/xap/find.rs",
    "content": "use crate::ParIterUsing;\nuse crate::Params;\nuse crate::generic_values::Vector;\nuse crate::runner::DefaultRunner;\nuse crate::using::UsingClone;\nuse crate::using::computational_variants::UParXap;\nuse crate::using::computational_variants::tests::utils::make_u_xap;\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_flat_map_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n\n    let expected = input.clone().into_iter().flat_map(fmap).next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let output = x.first();\n\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_filter_map_find(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| (!x.starts_with('3')).then_some(format!(\"{}!\", x));\n    let xmap = |x: String| Vector(fmap(x));\n\n    let expected = input.clone().into_iter().filter_map(fmap).next();\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let output = x.first();\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/using/computational_variants/tests/xap/mod.rs",
    "content": "mod collect;\nmod find;\nmod reduce;\n"
  },
  {
    "path": "src/using/computational_variants/tests/xap/reduce.rs",
    "content": "use crate::ParIterUsing;\nuse crate::Params;\nuse crate::generic_values::Vector;\nuse crate::runner::DefaultRunner;\nuse crate::using::UsingClone;\nuse crate::using::computational_variants::UParXap;\nuse crate::using::computational_variants::tests::utils::make_u_reduce;\nuse crate::using::computational_variants::tests::utils::make_u_xap;\nuse alloc::format;\nuse alloc::string::{String, ToString};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::IntoConcurrentIter;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_flat_map_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| x.chars().map(|x| x.to_string()).collect::<Vec<_>>();\n    let xmap = |x: String| Vector(fmap(x));\n    let reduce = |x: String, y: String| match x > y {\n        true => x,\n        false => y,\n    };\n\n    let expected = input.clone().into_iter().flat_map(fmap).reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let output = x.reduce(make_u_reduce(reduce));\n\n    assert_eq!(expected, output);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn x_filter_map_reduce(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let fmap = |x: String| (!x.starts_with('3')).then_some(format!(\"{}!\", x));\n    let xmap = |x: String| Vector(fmap(x));\n    let reduce = |x: String, y: String| match x > y {\n        true => x,\n        false => y,\n    };\n\n    let expected = input.clone().into_iter().filter_map(fmap).reduce(reduce);\n\n    let params = Params::new(nt, chunk, Default::default());\n    let iter = input.into_con_iter();\n    let x = UParXap::new(\n        UsingClone::new(\"XyZw\".to_string()),\n        DefaultRunner::default(),\n        params,\n        iter,\n        make_u_xap(xmap),\n    );\n\n    let output = x.reduce(make_u_reduce(reduce));\n\n    assert_eq!(expected, output);\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_fallible_option.rs",
    "content": "use crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto,\n    par_iter_option::ResultIntoOption,\n    runner::{DefaultRunner, ParallelRunner},\n    using::{ParIterOptionUsing, ParIterResultUsing, Using},\n};\nuse core::marker::PhantomData;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with None.\npub struct UParOption<'using, U, F, T, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    F: ParIterResultUsing<'using, U, R, Item = T, Err = ()>,\n    U: Using<'using>,\n{\n    par: F,\n    phantom: PhantomData<(&'using (), U, T, R)>,\n}\n\nimpl<'using, U, F, T, R> UParOption<'using, U, F, T, R>\nwhere\n    R: ParallelRunner,\n    F: ParIterResultUsing<'using, U, R, Item = T, Err = ()>,\n    U: Using<'using>,\n{\n    pub(crate) fn new(par: F) -> Self {\n        Self {\n            par,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'using, U, F, T, R> ParIterOptionUsing<'using, U, R> for UParOption<'using, U, F, T, R>\nwhere\n    R: ParallelRunner,\n    F: ParIterResultUsing<'using, U, R, Item = T, Err = ()>,\n    U: Using<'using>,\n{\n    type Item = T;\n\n    // params transformations\n\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self {\n        Self::new(self.par.num_threads(num_threads))\n    }\n\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self {\n        Self::new(self.par.chunk_size(chunk_size))\n    }\n\n    fn iteration_order(self, order: IterationOrder) -> Self {\n        Self::new(self.par.iteration_order(order))\n    }\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterOptionUsing<'using, U, Q, Item = Self::Item> {\n        UParOption::<U, _, _, _>::new(self.par.with_runner(orchestrator))\n    }\n\n    // computation transformations\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIterOptionUsing<'using, U, R, Item = Out>\n    where\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone,\n        Out: Send,\n    {\n        UParOption::<U, _, _, _>::new(self.par.map(map))\n    }\n\n    fn filter<Filter>(\n        self,\n        filter: Filter,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = Self::Item>\n    where\n        Self: Sized,\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n        Self::Item: Send,\n    {\n        UParOption::<U, _, _, _>::new(self.par.filter(filter))\n    }\n\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = IOut::Item>\n    where\n        Self: Sized,\n        IOut: IntoIterator,\n        IOut::Item: Send,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone,\n    {\n        UParOption::<U, _, _, _>::new(self.par.flat_map(flat_map))\n    }\n\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = Out>\n    where\n        Self: Sized,\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone,\n        Out: Send,\n    {\n        UParOption::<U, _, _, _>::new(self.par.filter_map(filter_map))\n    }\n\n    fn inspect<Operation>(\n        self,\n        operation: Operation,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = Self::Item>\n    where\n        Self: Sized,\n        Operation: Fn(&mut U::Item, &Self::Item) + Sync + Clone,\n        Self::Item: Send,\n    {\n        UParOption::<U, _, _, _>::new(self.par.inspect(operation))\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>,\n    {\n        self.par.collect_into(output).into_option()\n    }\n\n    fn collect<C>(self) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>,\n    {\n        self.par.collect().into_option()\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        self.par.reduce(reduce).into_option()\n    }\n\n    // early exit\n\n    fn first(self) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send,\n    {\n        self.par.first().into_option()\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_fallible_result/mod.rs",
    "content": "mod u_map_result;\nmod u_par_result;\nmod u_xap_result;\n\npub use u_map_result::UParMapResult;\npub use u_par_result::UParResult;\npub use u_xap_result::UParXapResult;\n"
  },
  {
    "path": "src/using/computational_variants/u_fallible_result/u_map_result.rs",
    "content": "use crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::executor::parallel_compute as prc;\nuse crate::using::{ParIterResultUsing, UParMap, Using};\nuse crate::{IterationOrder, ParCollectInto, ParIterUsing};\nuse core::marker::PhantomData;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub struct UParMapResult<'using, U, I, T, E, O, M1, R = DefaultRunner>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    O: IntoResult<T, E>,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    par: UParMap<'using, U, I, O, M1, R>,\n    phantom: PhantomData<(T, E)>,\n}\n\nimpl<'using, U, I, T, E, O, M1, R> UParMapResult<'using, U, I, T, E, O, M1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    O: IntoResult<T, E>,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    pub(crate) fn new(par: UParMap<'using, U, I, O, M1, R>) -> Self {\n        Self {\n            par,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'using, U, I, T, E, O, M1, R> ParIterResultUsing<'using, U, R>\n    for UParMapResult<'using, U, I, T, E, O, M1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    O: IntoResult<T, E>,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    type Item = T;\n\n    type Err = E;\n\n    type RegularItem = O;\n\n    type RegularParIter = UParMap<'using, U, I, O, M1, R>;\n\n    fn con_iter_len(&self) -> Option<usize> {\n        self.par.con_iter().try_get_len()\n    }\n\n    fn into_regular_par(self) -> Self::RegularParIter {\n        self.par\n    }\n\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self {\n        Self {\n            par: regular_par,\n            phantom: PhantomData,\n        }\n    }\n\n    // params transformations\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResultUsing<'using, U, Q, Item = Self::Item, Err = Self::Err> {\n        let (using, _, params, iter, m1) = self.par.destruct();\n        UParMapResult {\n            par: UParMap::new(using, orchestrator, params, iter, m1),\n            phantom: PhantomData,\n        }\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (using, orchestrator, params, iter, m1) = self.par.destruct();\n        let x1 = |u: *mut U::Item, i: I::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            m1(u, i).into_result()\n        };\n        output.u_x_try_collect_into(using, orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (using, orchestrator, params, iter, m1) = self.par.destruct();\n        let x1 = |u: *mut U::Item, i: I::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            m1(u, i).into_result()\n        };\n        let reduce = move |u: *mut U::Item, a: Self::Item, b: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            reduce(u, a, b)\n        };\n        prc::reduce::x(using, orchestrator, params, iter, x1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (using, orchestrator, params, iter, m1) = self.par.destruct();\n        let x1 = |u: *mut U::Item, i: I::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            m1(u, i).into_result()\n        };\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_, result) = prc::next::x(using, orchestrator, params, iter, x1);\n                result.map(|x: Option<(usize, T)>| x.map(|y| y.1))\n            }\n            IterationOrder::Arbitrary => {\n                let (_, result) = prc::next_any::x(using, orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_fallible_result/u_par_result.rs",
    "content": "use crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::executor::parallel_compute as prc;\nuse crate::using::{ParIterResultUsing, UPar, Using};\nuse crate::{IterationOrder, ParCollectInto, ParIterUsing};\nuse core::marker::PhantomData;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub struct UParResult<'using, U, I, T, E, R = DefaultRunner>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    I::Item: IntoResult<T, E>,\n{\n    par: UPar<'using, U, I, R>,\n    phantom: PhantomData<(T, E)>,\n}\n\nimpl<'using, U, I, T, E, R> UParResult<'using, U, I, T, E, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    I::Item: IntoResult<T, E>,\n{\n    pub(crate) fn new(par: UPar<'using, U, I, R>) -> Self {\n        Self {\n            par,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'using, U, I, T, E, R> ParIterResultUsing<'using, U, R> for UParResult<'using, U, I, T, E, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    I::Item: IntoResult<T, E>,\n{\n    type Item = T;\n\n    type Err = E;\n\n    type RegularItem = I::Item;\n\n    type RegularParIter = UPar<'using, U, I, R>;\n\n    fn con_iter_len(&self) -> Option<usize> {\n        self.par.con_iter().try_get_len()\n    }\n\n    fn into_regular_par(self) -> Self::RegularParIter {\n        self.par\n    }\n\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self {\n        Self {\n            par: regular_par,\n            phantom: PhantomData,\n        }\n    }\n\n    // params transformations\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResultUsing<'using, U, Q, Item = Self::Item, Err = Self::Err> {\n        let (using, _, params, iter) = self.par.destruct();\n        UParResult {\n            par: UPar::new(using, orchestrator, params, iter),\n            phantom: PhantomData,\n        }\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (using, orchestrator, params, iter) = self.par.destruct();\n        let x1 = |_: *mut U::Item, i: I::Item| i.into_result();\n        output.u_x_try_collect_into(using, orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (using, orchestrator, params, iter) = self.par.destruct();\n        let x1 = |_: *mut U::Item, i: I::Item| i.into_result();\n        let reduce = move |u: *mut U::Item, a: Self::Item, b: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            reduce(u, a, b)\n        };\n        prc::reduce::x(using, orchestrator, params, iter, x1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (using, orchestrator, params, iter) = self.par.destruct();\n        let x1 = |_: *mut U::Item, i: I::Item| i.into_result();\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_, result) = prc::next::x(using, orchestrator, params, iter, x1);\n                result.map(|x: Option<(usize, T)>| x.map(|y| y.1))\n            }\n            IterationOrder::Arbitrary => {\n                let (_, result) = prc::next_any::x(using, orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_fallible_result/u_xap_result.rs",
    "content": "use crate::generic_values::TransformableValues;\nuse crate::generic_values::runner_results::Infallible;\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::executor::parallel_compute as prc;\nuse crate::using::{ParIterResultUsing, UParXap, Using};\nuse crate::{IterationOrder, ParCollectInto, Params};\nuse core::marker::PhantomData;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\npub struct UParXapResult<'using, U, I, T, E, Vo, X1, R = DefaultRunner>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues,\n    Vo::Item: IntoResult<T, E>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    phantom: PhantomData<(&'using (), T, E)>,\n}\n\nimpl<'using, U, I, T, E, Vo, X1, R> UParXapResult<'using, U, I, T, E, Vo, X1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues,\n    Vo::Item: IntoResult<T, E>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    pub(crate) fn new(using: U, orchestrator: R, params: Params, iter: I, xap1: X1) -> Self {\n        Self {\n            using,\n            orchestrator,\n            params,\n            iter,\n            xap1,\n            phantom: PhantomData,\n        }\n    }\n\n    fn destruct(self) -> (U, R, Params, I, X1) {\n        (\n            self.using,\n            self.orchestrator,\n            self.params,\n            self.iter,\n            self.xap1,\n        )\n    }\n}\n\nimpl<'using, U, I, T, E, Vo, X1, R> ParIterResultUsing<'using, U, R>\n    for UParXapResult<'using, U, I, T, E, Vo, X1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    Vo::Item: IntoResult<T, E>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    type Item = T;\n\n    type Err = E;\n\n    type RegularItem = Vo::Item;\n\n    type RegularParIter = UParXap<'using, U, I, Vo, X1, R>;\n\n    fn con_iter_len(&self) -> Option<usize> {\n        self.iter.try_get_len()\n    }\n\n    fn into_regular_par(self) -> Self::RegularParIter {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self {\n        let (using, orchestrator, params, iter, x1) = regular_par.destruct();\n        Self::new(using, orchestrator, params, iter, x1)\n    }\n\n    // params transformations\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResultUsing<'using, U, Q, Item = Self::Item, Err = Self::Err> {\n        let (using, _, params, iter, x1) = self.destruct();\n        UParXapResult::new(using, orchestrator, params, iter, x1)\n    }\n\n    // collect\n\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        let x1 = |u: *mut U::Item, i: I::Item| x1(u, i).map_while_ok(|x| x.into_result());\n        output.u_x_try_collect_into(using, orchestrator, params, iter, x1)\n    }\n\n    // reduce\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        let x1 = |u: *mut U::Item, i: I::Item| x1(u, i).map_while_ok(|x| x.into_result());\n        let reduce = move |u: *mut U::Item, a: Self::Item, b: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            reduce(u, a, b)\n        };\n        prc::reduce::x(using, orchestrator, params, iter, x1, reduce).1\n    }\n\n    // early exit\n\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        let x1 = |u: *mut U::Item, i: I::Item| x1(u, i).map_while_ok(|x| x.into_result());\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_, result) = prc::next::x(using, orchestrator, params, iter, x1);\n                result.map(|x: Option<(usize, T)>| x.map(|y| y.1))\n            }\n            IterationOrder::Arbitrary => {\n                let (_, result) = prc::next_any::x(using, orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_map.rs",
    "content": "use core::marker::PhantomData;\n\nuse crate::ParIterUsing;\nuse crate::generic_values::Vector;\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::ParIterResultUsing;\nuse crate::using::computational_variants::u_fallible_result::UParMapResult;\nuse crate::using::computational_variants::u_xap::UParXap;\nuse crate::using::executor::parallel_compute as prc;\nuse crate::using::using_variants::Using;\nuse crate::{ChunkSize, IterationOrder, NumThreads, ParCollectInto, Params};\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator that maps inputs.\npub struct UParMap<'using, U, I, O, M1, R = DefaultRunner>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    map1: M1,\n    phantom: PhantomData<&'using ()>,\n}\n\nimpl<'using, U, I, O, M1, R> UParMap<'using, U, I, O, M1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    pub(crate) fn new(using: U, orchestrator: R, params: Params, iter: I, map1: M1) -> Self {\n        Self {\n            using,\n            orchestrator,\n            params,\n            iter,\n            map1,\n            phantom: PhantomData,\n        }\n    }\n\n    pub(crate) fn destruct(self) -> (U, R, Params, I, M1) {\n        (\n            self.using,\n            self.orchestrator,\n            self.params,\n            self.iter,\n            self.map1,\n        )\n    }\n}\n\nunsafe impl<'using, U, I, O, M1, R> Send for UParMap<'using, U, I, O, M1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n}\n\nunsafe impl<'using, U, I, O, M1, R> Sync for UParMap<'using, U, I, O, M1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n}\n\nimpl<'using, U, I, O, M1, R> ParIterUsing<'using, U, R> for UParMap<'using, U, I, O, M1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    type Item = O;\n\n    fn con_iter(&self) -> &impl ConcurrentIter {\n        &self.iter\n    }\n\n    fn params(&self) -> Params {\n        self.params\n    }\n\n    fn num_threads(mut self, num_threads: impl Into<NumThreads>) -> Self {\n        self.params = self.params.with_num_threads(num_threads);\n        self\n    }\n\n    fn chunk_size(mut self, chunk_size: impl Into<ChunkSize>) -> Self {\n        self.params = self.params.with_chunk_size(chunk_size);\n        self\n    }\n\n    fn iteration_order(mut self, collect: IterationOrder) -> Self {\n        self.params = self.params.with_collect_ordering(collect);\n        self\n    }\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterUsing<'using, U, Q, Item = Self::Item> {\n        let (using, _, params, iter, x1) = self.destruct();\n        UParMap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n        let m1 = move |u: &mut U::Item, x: I::Item| {\n            let v1 = m1(u, x);\n            map(u, v1)\n        };\n        UParMap::new(using, orchestrator, params, iter, m1)\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIterUsing<'using, U, R, Item = Self::Item>\n    where\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            let value = m1(u, i);\n            filter(u, &value).then_some(value)\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            let a = m1(u, i);\n            Vector(flat_map(u, a))\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            let a = m1(u, i);\n            filter_map(u, a)\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn into_fallible_result<Out, Err>(\n        self,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Out, Err = Err>\n    where\n        Self::Item: IntoResult<Out, Err>,\n    {\n        UParMapResult::new(self)\n    }\n\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n        output.u_m_collect_into(using, orchestrator, params, iter, m1)\n    }\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n        prc::reduce::m(using, orchestrator, params, iter, m1, reduce).1\n    }\n\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n    {\n        let (using, orchestrator, params, iter, m1) = self.destruct();\n        match params.iteration_order {\n            IterationOrder::Ordered => prc::next::m(using, orchestrator, params, iter, m1).1,\n            IterationOrder::Arbitrary => prc::next_any::m(using, orchestrator, params, iter, m1).1,\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_par.rs",
    "content": "use core::marker::PhantomData;\n\nuse crate::ParIterUsing;\nuse crate::default_fns::u_map_self;\nuse crate::generic_values::Vector;\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::ParIterResultUsing;\nuse crate::using::computational_variants::u_fallible_result::UParResult;\nuse crate::using::computational_variants::u_map::UParMap;\nuse crate::using::computational_variants::u_xap::UParXap;\nuse crate::using::executor::parallel_compute as prc;\nuse crate::using::using_variants::Using;\nuse crate::{ChunkSize, IterationOrder, NumThreads, ParCollectInto, Params};\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// A parallel iterator.\npub struct UPar<'using, U, I, R = DefaultRunner>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    phantom: PhantomData<&'using ()>,\n}\n\nimpl<'using, U, I, R> UPar<'using, U, I, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    pub(crate) fn new(using: U, orchestrator: R, params: Params, iter: I) -> Self {\n        Self {\n            using,\n            orchestrator,\n            params,\n            iter,\n            phantom: PhantomData,\n        }\n    }\n\n    pub(crate) fn destruct(self) -> (U, R, Params, I) {\n        (self.using, self.orchestrator, self.params, self.iter)\n    }\n}\n\nunsafe impl<'using, U, I, R> Send for UPar<'using, U, I, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n}\n\nunsafe impl<'using, U, I, R> Sync for UPar<'using, U, I, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n}\n\nimpl<'using, U, I, R> ParIterUsing<'using, U, R> for UPar<'using, U, I, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n{\n    type Item = I::Item;\n\n    fn con_iter(&self) -> &impl ConcurrentIter {\n        &self.iter\n    }\n\n    fn params(&self) -> Params {\n        self.params\n    }\n\n    fn num_threads(mut self, num_threads: impl Into<NumThreads>) -> Self {\n        self.params = self.params.with_num_threads(num_threads);\n        self\n    }\n\n    fn chunk_size(mut self, chunk_size: impl Into<ChunkSize>) -> Self {\n        self.params = self.params.with_chunk_size(chunk_size);\n        self\n    }\n\n    fn iteration_order(mut self, collect: IterationOrder) -> Self {\n        self.params = self.params.with_collect_ordering(collect);\n        self\n    }\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterUsing<'using, U, Q, Item = Self::Item> {\n        let (using, _, params, iter) = self.destruct();\n        UPar::new(using, orchestrator, params, iter)\n    }\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        UParMap::new(using, orchestrator, params, iter, map)\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIterUsing<'using, U, R, Item = Self::Item>\n    where\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        let x1 = move |u: *mut U::Item, i: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            filter(u, &i).then_some(i)\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        let x1 = move |u: *mut U::Item, i: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            Vector(flat_map(u, i))\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        let x1 = move |u: *mut U::Item, i: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            filter_map(u, i)\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn into_fallible_result<Out, Err>(\n        self,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Out, Err = Err>\n    where\n        Self::Item: IntoResult<Out, Err>,\n    {\n        UParResult::new(self)\n    }\n\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        output.u_m_collect_into(using, orchestrator, params, iter, u_map_self)\n    }\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        prc::reduce::m(using, orchestrator, params, iter, u_map_self, reduce).1\n    }\n\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n    {\n        let (using, orchestrator, params, iter) = self.destruct();\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                prc::next::m(using, orchestrator, params, iter, u_map_self).1\n            }\n            IterationOrder::Arbitrary => {\n                prc::next_any::m(using, orchestrator, params, iter, u_map_self).1\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/computational_variants/u_xap.rs",
    "content": "use core::marker::PhantomData;\n\nuse crate::par_iter_result::IntoResult;\nuse crate::using::ParIterResultUsing;\nuse crate::using::computational_variants::u_fallible_result::UParXapResult;\nuse crate::using::executor::parallel_compute as prc;\nuse crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParIterUsing, Params,\n    generic_values::{TransformableValues, runner_results::Infallible},\n    runner::{DefaultRunner, ParallelRunner},\n    using::using_variants::Using,\n};\nuse orx_concurrent_iter::ConcurrentIter;\n// use crate::runner::parallel_runner_compute as prc;\n\npub struct UParXap<'using, U, I, Vo, X1, R = DefaultRunner>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    using: U,\n    orchestrator: R,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    phantom: PhantomData<&'using ()>,\n}\n\nimpl<'using, U, I, Vo, X1, R> UParXap<'using, U, I, Vo, X1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    pub(crate) fn new(using: U, orchestrator: R, params: Params, iter: I, xap1: X1) -> Self {\n        Self {\n            using,\n            orchestrator,\n            params,\n            iter,\n            xap1,\n            phantom: PhantomData,\n        }\n    }\n\n    pub(crate) fn destruct(self) -> (U, R, Params, I, X1) {\n        (\n            self.using,\n            self.orchestrator,\n            self.params,\n            self.iter,\n            self.xap1,\n        )\n    }\n}\n\nunsafe impl<'using, U, I, Vo, X1, R> Send for UParXap<'using, U, I, Vo, X1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n}\n\nunsafe impl<'using, U, I, Vo, X1, R> Sync for UParXap<'using, U, I, Vo, X1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n}\n\nimpl<'using, U, I, Vo, X1, R> ParIterUsing<'using, U, R> for UParXap<'using, U, I, Vo, X1, R>\nwhere\n    U: Using<'using>,\n    R: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: TransformableValues<Fallibility = Infallible>,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    type Item = Vo::Item;\n\n    fn con_iter(&self) -> &impl ConcurrentIter {\n        &self.iter\n    }\n\n    fn params(&self) -> Params {\n        self.params\n    }\n\n    fn num_threads(mut self, num_threads: impl Into<NumThreads>) -> Self {\n        self.params = self.params.with_num_threads(num_threads);\n        self\n    }\n\n    fn chunk_size(mut self, chunk_size: impl Into<ChunkSize>) -> Self {\n        self.params = self.params.with_chunk_size(chunk_size);\n        self\n    }\n\n    fn iteration_order(mut self, collect: IterationOrder) -> Self {\n        self.params = self.params.with_collect_ordering(collect);\n        self\n    }\n\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterUsing<'using, U, Q, Item = Self::Item> {\n        let (using, _, params, iter, x1) = self.destruct();\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn map<Out, Map>(self, map: Map) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n\n        let map = move |u: *mut U::Item, i: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            map(u, i)\n        };\n\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            let vo = x1(u, i);\n            vo.u_map(u, map.clone())\n        };\n\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn filter<Filter>(self, filter: Filter) -> impl ParIterUsing<'using, U, R, Item = Self::Item>\n    where\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n\n        let filter = move |u: *mut U::Item, i: &Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            filter(u, i)\n        };\n\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            let vo = x1(u, i);\n            vo.u_filter(u, filter.clone())\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n\n        let flat_map = move |u: *mut U::Item, i: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            flat_map(u, i)\n        };\n\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            let vo = x1(u, i);\n            vo.u_flat_map(u, flat_map.clone())\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n\n        let filter_map = move |u: *mut U::Item, i: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            filter_map(u, i)\n        };\n\n        let x1 = move |u: *mut U::Item, i: I::Item| {\n            let vo = x1(u, i);\n            vo.u_filter_map(u, filter_map.clone())\n        };\n        UParXap::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn into_fallible_result<Out, Err>(\n        self,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Out, Err = Err>\n    where\n        Self::Item: IntoResult<Out, Err>,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        UParXapResult::new(using, orchestrator, params, iter, x1)\n    }\n\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        output.u_x_collect_into(using, orchestrator, params, iter, x1)\n    }\n\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        let reduce = move |u: *mut U::Item, a: Self::Item, b: Self::Item| {\n            // SAFETY: TODO-USING\n            let u = unsafe { &mut *u };\n            reduce(u, a, b)\n        };\n\n        let (_, Ok(acc)) = prc::reduce::x(using, orchestrator, params, iter, x1, reduce);\n        acc\n    }\n\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n    {\n        let (using, orchestrator, params, iter, x1) = self.destruct();\n        match params.iteration_order {\n            IterationOrder::Ordered => {\n                let (_num_threads, Ok(result)) =\n                    prc::next::x(using, orchestrator, params, iter, x1);\n                result.map(|x| x.1)\n            }\n            IterationOrder::Arbitrary => {\n                let (_num_threads, Ok(result)) =\n                    prc::next_any::x(using, orchestrator, params, iter, x1);\n                result\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/using/executor/mod.rs",
    "content": "pub(super) mod parallel_compute;\nmod thread_compute;\n"
  },
  {
    "path": "src/using/executor/parallel_compute/collect_arbitrary.rs",
    "content": "use crate::Params;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::ParallelCollectArbitrary;\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf, ThreadRunnerOf};\nuse crate::using::executor::thread_compute as th;\nuse crate::using::using_variants::Using;\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\n#[cfg(test)]\npub fn m<'using, U, C, I, O, M1, P>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    let capacity_bound = pinned_vec.capacity_bound();\n    let offset = pinned_vec.len();\n    let mut bag: ConcurrentBag<O, P> = pinned_vec.into();\n    match iter.try_get_len() {\n        Some(iter_len) => bag.reserve_maximum_capacity(offset + iter_len),\n        None => bag.reserve_maximum_capacity(capacity_bound),\n    };\n    let thread_work =\n        |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n            let u = using.create(nt.into_inner());\n            th::collect_arbitrary::m(u, thread_runner, iter, state, &map1, &bag);\n        };\n    let num_spawned = orchestrator.run_all(params, iter, ComputationKind::Collect, thread_work);\n\n    let values = bag.into_inner();\n    (num_spawned, values)\n}\n\npub fn x<'using, U, C, I, Vo, X1, P>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (NumSpawned, ParallelCollectArbitrary<Vo, P>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let capacity_bound = pinned_vec.capacity_bound();\n    let offset = pinned_vec.len();\n\n    let mut bag: ConcurrentBag<Vo::Item, P> = pinned_vec.into();\n    match iter.try_get_len() {\n        Some(iter_len) => bag.reserve_maximum_capacity(offset + iter_len),\n        None => bag.reserve_maximum_capacity(capacity_bound),\n    };\n\n    let thread_map =\n        |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n            let u = using.create(nt.into_inner());\n            th::collect_arbitrary::x(u, thread_runner, iter, state, &xap1, &bag).into_result()\n        };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n\n    let result = match result {\n        Err(error) => ParallelCollectArbitrary::StoppedByError { error },\n        Ok(_) => ParallelCollectArbitrary::AllOrUntilWhileCollected {\n            pinned_vec: bag.into_inner(),\n        },\n    };\n\n    (num_spawned, result)\n}\n"
  },
  {
    "path": "src/using/executor/parallel_compute/collect_ordered.rs",
    "content": "use crate::Params;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{Fallibility, ParallelCollect};\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf, ThreadRunnerOf};\nuse crate::using::executor::thread_compute as th;\nuse crate::using::using_variants::Using;\nuse orx_concurrent_iter::ConcurrentIter;\nuse orx_concurrent_ordered_bag::ConcurrentOrderedBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub fn m<'using, U, C, I, O, M1, P>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n    pinned_vec: P,\n) -> (NumSpawned, P)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    P: IntoConcurrentPinnedVec<O>,\n{\n    let offset = pinned_vec.len();\n    let o_bag: ConcurrentOrderedBag<O, P> = pinned_vec.into();\n\n    let thread_do =\n        |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n            let u = using.create(nt.into_inner());\n            th::collect_ordered::m(u, thread_runner, iter, state, &map1, &o_bag, offset);\n        };\n    let num_spawned = orchestrator.run_all(params, iter, ComputationKind::Collect, thread_do);\n\n    let values = unsafe { o_bag.into_inner().unwrap_only_if_counts_match() };\n    (num_spawned, values)\n}\n\npub fn x<'using, U, C, I, Vo, X1, P>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    pinned_vec: P,\n) -> (NumSpawned, ParallelCollect<Vo, P>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    <Vo::Fallibility as Fallibility>::Error: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n{\n    let thread_map =\n        |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n            let u = using.create(nt.into_inner());\n            th::collect_ordered::x(u, thread_runner, iter, state, &xap1).into_result()\n        };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n\n    let result = match result {\n        Err(error) => ParallelCollect::StoppedByError { error },\n        Ok(results) => ParallelCollect::reduce(results, pinned_vec),\n    };\n    (num_spawned, result)\n}\n"
  },
  {
    "path": "src/using/executor/parallel_compute/mod.rs",
    "content": "pub(crate) mod collect_arbitrary;\npub(crate) mod collect_ordered;\npub(crate) mod next;\npub(crate) mod next_any;\npub(crate) mod reduce;\n"
  },
  {
    "path": "src/using/executor/parallel_compute/next.rs",
    "content": "use crate::Params;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{Fallibility, NextSuccess, NextWithIdx};\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf};\nuse crate::using::executor::thread_compute as th;\nuse crate::using::using_variants::Using;\nuse orx_concurrent_iter::ConcurrentIter;\n\npub fn m<'using, U, C, I, O, M1>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n) -> (NumSpawned, Option<O>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    let thread_map = |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner| {\n        let u = using.create(nt.into_inner());\n        Ok(th::next::m(u, thread_runner, iter, state, &map1))\n    };\n    let (num_spawned, result) =\n        orchestrator.map_infallible(params, iter, ComputationKind::Collect, thread_map);\n\n    let next = match result {\n        Ok(results) => results\n            .into_iter()\n            .flatten()\n            .min_by_key(|x| x.0)\n            .map(|x| x.1),\n    };\n    (num_spawned, next)\n}\n\ntype ResultNext<Vo> = Result<\n    Option<(usize, <Vo as Values>::Item)>,\n    <<Vo as Values>::Fallibility as Fallibility>::Error,\n>;\n\npub fn x<'using, U, C, I, Vo, X1>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n) -> (NumSpawned, ResultNext<Vo>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    let thread_map = |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, th_runner| {\n        let u = using.create(nt.into_inner());\n        match th::next::x(u, th_runner, iter, state, &xap1) {\n            NextWithIdx::Found { idx, value } => Ok(Some(NextSuccess::Found { idx, value })),\n            NextWithIdx::NotFound => Ok(None),\n            NextWithIdx::StoppedByWhileCondition { idx } => {\n                Ok(Some(NextSuccess::StoppedByWhileCondition { idx }))\n            }\n            NextWithIdx::StoppedByError { error } => Err(error),\n        }\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n    let next = result.map(|results| NextSuccess::reduce(results.into_iter().flatten()));\n    (num_spawned, next)\n}\n"
  },
  {
    "path": "src/using/executor/parallel_compute/next_any.rs",
    "content": "use crate::Params;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::Fallibility;\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf};\nuse crate::using::executor::thread_compute as th;\nuse crate::using::using_variants::Using;\nuse orx_concurrent_iter::ConcurrentIter;\n\npub fn m<'using, U, C, I, O, M1>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n) -> (NumSpawned, Option<O>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n{\n    let thread_map = |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner| {\n        let u = using.create(nt.into_inner());\n        Ok(th::next_any::m(u, thread_runner, iter, state, &map1))\n    };\n    let (num_spawned, result) =\n        orchestrator.map_infallible(params, iter, ComputationKind::Collect, thread_map);\n\n    let next = match result {\n        Ok(results) => results.into_iter().flatten().next(),\n    };\n    (num_spawned, next)\n}\n\ntype ResultNextAny<Vo> =\n    Result<Option<<Vo as Values>::Item>, <<Vo as Values>::Fallibility as Fallibility>::Error>;\n\npub fn x<'using, U, C, I, Vo, X1>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n) -> (NumSpawned, ResultNextAny<Vo>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n{\n    let thread_map = |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, th_runner| {\n        let u = using.create(nt.into_inner());\n        th::next_any::x(u, th_runner, iter, state, &xap1)\n    };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n    let next = result.map(|results| results.into_iter().flatten().next());\n    (num_spawned, next)\n}\n"
  },
  {
    "path": "src/using/executor/parallel_compute/reduce.rs",
    "content": "use crate::Params;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::Fallibility;\nuse crate::runner::{ComputationKind, NumSpawned, ParallelRunner, SharedStateOf, ThreadRunnerOf};\nuse crate::using::executor::thread_compute as th;\nuse crate::using::using_variants::Using;\nuse orx_concurrent_iter::ConcurrentIter;\n\npub fn m<'using, U, C, I, O, M1, Red>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    map1: M1,\n    reduce: Red,\n) -> (NumSpawned, Option<O>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    M1: Fn(&mut U::Item, I::Item) -> O + Sync,\n    Red: Fn(&mut U::Item, O, O) -> O + Sync,\n    O: Send,\n{\n    let thread_map =\n        |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n            let u = using.create(nt.into_inner());\n            Ok(th::reduce::m(u, thread_runner, iter, state, &map1, &reduce))\n        };\n    let (num_spawned, result) =\n        orchestrator.map_infallible(params, iter, ComputationKind::Collect, thread_map);\n\n    let mut u = using.into_inner();\n    let acc = match result {\n        Ok(results) => results\n            .into_iter()\n            .flatten()\n            .reduce(|a, b| reduce(&mut u, a, b)),\n    };\n\n    (num_spawned, acc)\n}\n\ntype ResultReduce<Vo> =\n    Result<Option<<Vo as Values>::Item>, <<Vo as Values>::Fallibility as Fallibility>::Error>;\n\npub fn x<'using, U, C, I, Vo, X1, Red>(\n    using: U,\n    mut orchestrator: C,\n    params: Params,\n    iter: I,\n    xap1: X1,\n    reduce: Red,\n) -> (NumSpawned, ResultReduce<Vo>)\nwhere\n    U: Using<'using>,\n    C: ParallelRunner,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U::Item, I::Item) -> Vo + Sync,\n    Red: Fn(*mut U::Item, Vo::Item, Vo::Item) -> Vo::Item + Sync,\n{\n    let thread_map =\n        |nt: NumSpawned, iter: &I, state: &SharedStateOf<C>, thread_runner: ThreadRunnerOf<C>| {\n            let u = using.create(nt.into_inner());\n            th::reduce::x(u, thread_runner, iter, state, &xap1, &reduce).into_result()\n        };\n    let (num_spawned, result) = orchestrator.map_all::<Vo::Fallibility, _, _, _>(\n        params,\n        iter,\n        ComputationKind::Collect,\n        thread_map,\n    );\n    let mut u = using.into_inner();\n    let acc = result.map(|results| {\n        results\n            .into_iter()\n            .flatten()\n            .reduce(|a, b| reduce(&mut u, a, b))\n    });\n    (num_spawned, acc)\n}\n"
  },
  {
    "path": "src/using/executor/thread_compute/collect_arbitrary.rs",
    "content": "use crate::ThreadExecutor;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{Stop, ThreadCollectArbitrary};\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\n// m\n\n#[cfg(test)]\npub fn m<U, C, I, O, M1, P>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n    bag: &ConcurrentBag<O, P>,\n) where\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(&mut U, I::Item) -> O,\n    P: IntoConcurrentPinnedVec<O>,\n    O: Send,\n{\n    let u = &mut using;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(value) => _ = bag.push(map1(u, value)),\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => _ = bag.extend(chunk.map(|x| map1(u, x))),\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n}\n\n// x\n\npub fn x<U, C, I, Vo, X1, P>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n    bag: &ConcurrentBag<Vo::Item, P>,\n) -> ThreadCollectArbitrary<Vo::Fallibility>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(*mut U, I::Item) -> Vo,\n    P: IntoConcurrentPinnedVec<Vo::Item>,\n    Vo::Item: Send,\n{\n    let u = &mut using;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(value) => {\n                    // TODO: possible to try to get len and bag.extend(values_vt.values()) when available, same holds for chunk below\n                    let vo = xap1(u, value);\n                    let done = vo.push_to_bag(bag);\n\n                    if let Some(stop) = Vo::arbitrary_push_to_stop(done) {\n                        iter.skip_to_end();\n                        runner.complete_chunk(shared_state, chunk_size);\n                        runner.complete_task(shared_state);\n                        match stop {\n                            Stop::DueToWhile => {\n                                return ThreadCollectArbitrary::StoppedByWhileCondition;\n                            }\n                            Stop::DueToError { error } => {\n                                return ThreadCollectArbitrary::StoppedByError { error };\n                            }\n                        }\n                    }\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        for value in chunk {\n                            let vo = xap1(u, value);\n                            let done = vo.push_to_bag(bag);\n\n                            if let Some(stop) = Vo::arbitrary_push_to_stop(done) {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                match stop {\n                                    Stop::DueToWhile => {\n                                        return ThreadCollectArbitrary::StoppedByWhileCondition;\n                                    }\n                                    Stop::DueToError { error } => {\n                                        return ThreadCollectArbitrary::StoppedByError { error };\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n\n    ThreadCollectArbitrary::AllCollected\n}\n"
  },
  {
    "path": "src/using/executor/thread_compute/collect_ordered.rs",
    "content": "use crate::ThreadExecutor;\nuse crate::generic_values::Values;\nuse crate::generic_values::runner_results::{StopWithIdx, ThreadCollect};\nuse alloc::vec::Vec;\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\nuse orx_concurrent_ordered_bag::ConcurrentOrderedBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\n\npub fn m<U, C, I, O, M1, P>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n    o_bag: &ConcurrentOrderedBag<O, P>,\n    offset: usize,\n) where\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(&mut U, I::Item) -> O,\n    P: IntoConcurrentPinnedVec<O>,\n    O: Send,\n{\n    let u = &mut using;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, value)) => unsafe { o_bag.set_value(offset + idx, map1(u, value)) },\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((begin_idx, chunk)) => {\n                        let values = chunk.map(|x| map1(u, x));\n                        unsafe { o_bag.set_values(offset + begin_idx, values) };\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n}\n\npub fn x<U, C, I, Vo, X1>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n) -> ThreadCollect<Vo>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(*mut U, I::Item) -> Vo,\n{\n    let u = &mut using;\n    let mut collected = Vec::new();\n    let out_vec = &mut collected;\n\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, i)) => {\n                    let vo = xap1(u, i);\n                    let done = vo.push_to_vec_with_idx(idx, out_vec);\n                    if let Some(stop) = Vo::ordered_push_to_stop(done) {\n                        iter.skip_to_end();\n                        runner.complete_chunk(shared_state, chunk_size);\n                        runner.complete_task(shared_state);\n                        match stop {\n                            StopWithIdx::DueToWhile { idx } => {\n                                return ThreadCollect::StoppedByWhileCondition {\n                                    vec: collected,\n                                    stopped_idx: idx,\n                                };\n                            }\n                            StopWithIdx::DueToError { idx: _, error } => {\n                                return ThreadCollect::StoppedByError { error };\n                            }\n                        }\n                    }\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((chunk_begin_idx, chunk)) => {\n                        for (within_chunk_idx, value) in chunk.enumerate() {\n                            let vo = xap1(u, value);\n                            let done = vo.push_to_vec_with_idx(chunk_begin_idx, out_vec);\n                            if let Some(stop) = Vo::ordered_push_to_stop(done) {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                match stop {\n                                    StopWithIdx::DueToWhile { idx } => {\n                                        return ThreadCollect::StoppedByWhileCondition {\n                                            vec: collected,\n                                            stopped_idx: idx + within_chunk_idx,\n                                        };\n                                    }\n                                    StopWithIdx::DueToError { idx: _, error } => {\n                                        return ThreadCollect::StoppedByError { error };\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n\n    ThreadCollect::AllCollected { vec: collected }\n}\n"
  },
  {
    "path": "src/using/executor/thread_compute/mod.rs",
    "content": "pub(super) mod collect_arbitrary;\npub(super) mod collect_ordered;\npub(super) mod next;\npub(super) mod next_any;\npub(super) mod reduce;\n"
  },
  {
    "path": "src/using/executor/thread_compute/next.rs",
    "content": "use crate::{\n    ThreadExecutor,\n    generic_values::Values,\n    generic_values::runner_results::{Next, NextWithIdx},\n};\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\n\npub fn m<U, C, I, O, M1>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n) -> Option<(usize, O)>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(&mut U, I::Item) -> O,\n{\n    let u = &mut using;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, i)) => {\n                    let first = map1(u, i);\n                    iter.skip_to_end();\n                    runner.complete_chunk(shared_state, chunk_size);\n                    runner.complete_task(shared_state);\n                    return Some((idx, first));\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((idx, mut chunk)) => {\n                        if let Some(i) = chunk.next() {\n                            let first = map1(u, i);\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Some((idx, first));\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    None\n}\n\npub fn x<U, C, I, Vo, X1>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n) -> NextWithIdx<Vo>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(*mut U, I::Item) -> Vo,\n{\n    let u = &mut using as *mut U;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller_with_idx();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some((idx, i)) => {\n                    let vt = xap1(u, i);\n                    match vt.next() {\n                        Next::Done { value } => {\n                            if let Some(value) = value {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                return NextWithIdx::Found { idx, value };\n                            }\n                        }\n                        Next::StoppedByError { error } => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return NextWithIdx::StoppedByError { error };\n                        }\n                        Next::StoppedByWhileCondition => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return NextWithIdx::StoppedByWhileCondition { idx };\n                        }\n                    }\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull_with_idx() {\n                    Some((idx, chunk)) => {\n                        for i in chunk {\n                            let vt = xap1(u, i);\n                            match vt.next() {\n                                Next::Done { value } => {\n                                    if let Some(value) = value {\n                                        iter.skip_to_end();\n                                        runner.complete_chunk(shared_state, chunk_size);\n                                        runner.complete_task(shared_state);\n                                        return NextWithIdx::Found { idx, value };\n                                    }\n                                }\n                                Next::StoppedByError { error } => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return NextWithIdx::StoppedByError { error };\n                                }\n                                Next::StoppedByWhileCondition => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return NextWithIdx::StoppedByWhileCondition { idx };\n                                }\n                            }\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    NextWithIdx::NotFound\n}\n"
  },
  {
    "path": "src/using/executor/thread_compute/next_any.rs",
    "content": "use crate::{\n    ThreadExecutor,\n    generic_values::Values,\n    generic_values::runner_results::{Fallibility, Next},\n};\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\n\npub fn m<U, C, I, O, M1>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n) -> Option<O>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    O: Send,\n    M1: Fn(&mut U, I::Item) -> O,\n{\n    let u = &mut using;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let first = map1(u, i);\n                    iter.skip_to_end();\n                    runner.complete_chunk(shared_state, chunk_size);\n                    runner.complete_task(shared_state);\n                    return Some(first);\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(mut chunk) => {\n                        if let Some(i) = chunk.next() {\n                            let first = map1(u, i);\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Some(first);\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    None\n}\n\npub fn x<U, C, I, Vo, X1>(\n    mut using: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n) -> Result<Option<Vo::Item>, <Vo::Fallibility as Fallibility>::Error>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    Vo::Item: Send,\n    X1: Fn(*mut U, I::Item) -> Vo,\n{\n    let u = &mut using as *mut U;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let vt = xap1(u, i);\n                    match vt.next() {\n                        Next::Done { value } => {\n                            if let Some(value) = value {\n                                iter.skip_to_end();\n                                runner.complete_chunk(shared_state, chunk_size);\n                                runner.complete_task(shared_state);\n                                return Ok(Some(value));\n                            }\n                        }\n                        Next::StoppedByError { error } => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Err(error);\n                        }\n                        Next::StoppedByWhileCondition => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            return Ok(None);\n                        }\n                    }\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        for i in chunk {\n                            let vt = xap1(u, i);\n                            match vt.next() {\n                                Next::Done { value } => {\n                                    if let Some(value) = value {\n                                        iter.skip_to_end();\n                                        runner.complete_chunk(shared_state, chunk_size);\n                                        runner.complete_task(shared_state);\n                                        return Ok(Some(value));\n                                    }\n                                }\n                                Next::StoppedByError { error } => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return Err(error);\n                                }\n                                Next::StoppedByWhileCondition => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    return Ok(None);\n                                }\n                            }\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    Ok(None)\n}\n"
  },
  {
    "path": "src/using/executor/thread_compute/reduce.rs",
    "content": "use crate::{\n    ThreadExecutor,\n    generic_values::{\n        Values,\n        runner_results::{Reduce, StopReduce},\n    },\n};\nuse orx_concurrent_iter::{ChunkPuller, ConcurrentIter};\n\n// m\n\npub fn m<U, C, I, O, M1, Red>(\n    mut u: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    map1: &M1,\n    reduce: &Red,\n) -> Option<O>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    M1: Fn(&mut U, I::Item) -> O,\n    Red: Fn(&mut U, O, O) -> O,\n{\n    let u = &mut u;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    let mut acc = None;\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let y = map1(u, i);\n                    acc = match acc {\n                        Some(x) => Some(reduce(u, x, y)),\n                        None => Some(y),\n                    };\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        let mut res = None;\n                        for x in chunk {\n                            let b = map1(u, x);\n                            res = match res {\n                                Some(a) => Some(reduce(u, a, b)),\n                                None => Some(b),\n                            }\n                        }\n                        acc = match acc {\n                            Some(x) => match res {\n                                Some(y) => Some(reduce(u, x, y)),\n                                None => Some(x),\n                            },\n                            None => res,\n                        };\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n    acc\n}\n\n// x\n\npub fn x<U, C, I, Vo, X1, Red>(\n    mut u: U,\n    mut runner: C,\n    iter: &I,\n    shared_state: &C::SharedState,\n    xap1: &X1,\n    reduce: &Red,\n) -> Reduce<Vo>\nwhere\n    C: ThreadExecutor,\n    I: ConcurrentIter,\n    Vo: Values,\n    X1: Fn(*mut U, I::Item) -> Vo,\n    Red: Fn(*mut U, Vo::Item, Vo::Item) -> Vo::Item,\n{\n    let u = &mut u as *mut U;\n    let mut chunk_puller = iter.chunk_puller(0);\n    let mut item_puller = iter.item_puller();\n\n    let mut acc = None;\n    loop {\n        let chunk_size = runner.next_chunk_size(shared_state, iter);\n\n        runner.begin_chunk(chunk_size);\n\n        match chunk_size {\n            0 | 1 => match item_puller.next() {\n                Some(i) => {\n                    let vo = xap1(u, i);\n                    let reduce = vo.u_acc_reduce(u, acc, reduce);\n                    acc = match Vo::reduce_to_stop(reduce) {\n                        Ok(acc) => acc,\n                        Err(stop) => {\n                            iter.skip_to_end();\n                            runner.complete_chunk(shared_state, chunk_size);\n                            runner.complete_task(shared_state);\n                            match stop {\n                                StopReduce::DueToWhile { acc } => {\n                                    return Reduce::StoppedByWhileCondition { acc };\n                                }\n                                StopReduce::DueToError { error } => {\n                                    return Reduce::StoppedByError { error };\n                                }\n                            }\n                        }\n                    };\n                }\n                None => break,\n            },\n            c => {\n                if c > chunk_puller.chunk_size() {\n                    chunk_puller = iter.chunk_puller(c);\n                }\n\n                match chunk_puller.pull() {\n                    Some(chunk) => {\n                        for i in chunk {\n                            let vo = xap1(u, i);\n                            let reduce = vo.u_acc_reduce(u, acc, reduce);\n                            acc = match Vo::reduce_to_stop(reduce) {\n                                Ok(acc) => acc,\n                                Err(stop) => {\n                                    iter.skip_to_end();\n                                    runner.complete_chunk(shared_state, chunk_size);\n                                    runner.complete_task(shared_state);\n                                    match stop {\n                                        StopReduce::DueToWhile { acc } => {\n                                            return Reduce::StoppedByWhileCondition { acc };\n                                        }\n                                        StopReduce::DueToError { error } => {\n                                            return Reduce::StoppedByError { error };\n                                        }\n                                    }\n                                }\n                            };\n                        }\n                    }\n                    None => break,\n                }\n            }\n        }\n\n        runner.complete_chunk(shared_state, chunk_size);\n    }\n\n    runner.complete_task(shared_state);\n\n    Reduce::Done { acc }\n}\n"
  },
  {
    "path": "src/using/mod.rs",
    "content": "mod collect_into;\nmod computational_variants;\nmod executor;\nmod u_par_iter;\nmod u_par_iter_option;\nmod u_par_iter_result;\nmod using_variants;\n\npub(crate) use collect_into::UParCollectIntoCore;\npub(crate) use computational_variants::{UPar, UParMap, UParXap};\npub use u_par_iter::ParIterUsing;\npub use u_par_iter_option::ParIterOptionUsing;\npub use u_par_iter_result::ParIterResultUsing;\npub use using_variants::{Using, UsingClone, UsingFun};\n"
  },
  {
    "path": "src/using/u_par_iter.rs",
    "content": "use crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto, Params, RunnerWithPool, Sum,\n    par_iter_option::IntoOption,\n    par_iter_result::IntoResult,\n    runner::{DefaultRunner, ParallelRunner},\n    using::{\n        ParIterOptionUsing, ParIterResultUsing,\n        computational_variants::u_fallible_option::UParOption, using_variants::Using,\n    },\n};\nuse crate::{ParThreadPool, default_fns::*};\nuse core::cmp::Ordering;\nuse orx_concurrent_iter::ConcurrentIter;\n\n/// Parallel iterator which allows mutable access to a variable of type `U` within its iterator methods.\n///\n/// Note that one variable will be created per thread used by the parallel computation.\npub trait ParIterUsing<'using, U, R = DefaultRunner>: Sized + Send + Sync\nwhere\n    R: ParallelRunner,\n    U: Using<'using>,\n{\n    /// Element type of the parallel iterator.\n    type Item;\n\n    /// Returns a reference to the input concurrent iterator.\n    fn con_iter(&self) -> &impl ConcurrentIter;\n\n    /// Parameters of the parallel iterator.\n    ///\n    /// See [crate::ParIter::params] for details.\n    fn params(&self) -> Params;\n\n    // params transformations\n\n    /// Sets the number of threads to be used in the parallel execution.\n    /// Integers can be used as the argument with the following mapping:\n    ///\n    /// * `0` -> `NumThreads::Auto`\n    /// * `1` -> `NumThreads::sequential()`\n    /// * `n > 0` -> `NumThreads::Max(n)`\n    ///\n    ///     /// Parameters of the parallel iterator.\n    ///\n    /// See [crate::ParIter::num_threads] for details.\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;\n\n    /// Sets the number of elements to be pulled from the concurrent iterator during the\n    /// parallel execution. When integers are used as argument, the following mapping applies:\n    ///\n    /// * `0` -> `ChunkSize::Auto`\n    /// * `n > 0` -> `ChunkSize::Exact(n)`\n    ///\n    /// Please use the default enum constructor for creating `ChunkSize::Min` variant.\n    ///\n    /// See [crate::ParIter::chunk_size] for details.\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;\n\n    /// Sets the iteration order of the parallel computation.\n    ///\n    /// See [crate::ParIter::iteration_order] for details.\n    fn iteration_order(self, collect: IterationOrder) -> Self;\n\n    /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].\n    ///\n    /// See [`ParIter::with_runner`] for details.\n    ///\n    /// [`DefaultRunner`]: crate::DefaultRunner\n    /// [`ParIter::with_runner`]: crate::ParIter::with_runner\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterUsing<'using, U, Q, Item = Self::Item>;\n\n    /// Rather than [`DefaultPool`], uses the parallel runner with the given `pool` implementing\n    /// [`ParThreadPool`].\n    ///\n    /// See [`ParIter::with_pool`] for details.\n    ///\n    /// [`DefaultPool`]: crate::DefaultPool\n    /// [`ParIter::with_pool`]: crate::ParIter::with_pool\n    fn with_pool<P: ParThreadPool>(\n        self,\n        pool: P,\n    ) -> impl ParIterUsing<'using, U, RunnerWithPool<P, R::Executor>, Item = Self::Item>\n    where\n        Self: Sized,\n    {\n        let runner = RunnerWithPool::from(pool).with_executor::<R::Executor>();\n        self.with_runner(runner)\n    }\n\n    // transformations into fallible computations\n\n    /// Transforms a parallel iterator where elements are of the result type; i.e., `ParIterUsing<U, R, Item = Result<T, E>>`,\n    ///  into fallible parallel iterator with item type `T` and error type `E`; i.e., into `ParIterResultUsing<U, R, Item = T, Err = E>`.\n    ///\n    /// `ParIterResultUsing` is also a parallel iterator; however, with methods specialized for handling fallible computations\n    /// as follows:\n    ///\n    /// * All of its methods are based on the success path with item type of `T`.\n    /// * However, computations short-circuit and immediately return the observed error if any of the items\n    ///   is of the `Err` variant of the result enum.\n    ///\n    /// See [`ParIterUsing`] for details.\n    ///\n    /// Unlike [crate::ParIter::into_fallible_result], the methods of `ParIterResultUsing` give a mutable reference to the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn into_fallible_result<T, E>(self) -> impl ParIterResultUsing<'using, U, R, Item = T, Err = E>\n    where\n        Self::Item: IntoResult<T, E>;\n\n    /// Transforms a parallel iterator where elements are of the option type; i.e., `ParIterUsing<U, R, Item = Option<T>>`,\n    ///  into fallible parallel iterator with item type `T`; i.e., into `ParIterOptionUsing<U, R, Item = T>`.\n    ///\n    /// `ParIterOptionUsing` is also a parallel iterator; however, with methods specialized for handling fallible computations\n    /// as follows:\n    ///\n    /// * All of its methods are based on the success path with item type of `T`.\n    /// * However, computations short-circuit and immediately return None if any of the items\n    ///   is of the `None` variant of the option enum.\n    ///\n    /// See [`ParIterOptionUsing`] for details.\n    ///\n    /// Unlike [crate::ParIter::into_fallible_option], the methods of `ParIterOptionUsing` give a mutable reference to the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn into_fallible_option<T>(self) -> impl ParIterOptionUsing<'using, U, R, Item = T>\n    where\n        Self::Item: IntoOption<T>,\n    {\n        UParOption::new(\n            self.map(|_, x| x.into_result_with_unit_err())\n                .into_fallible_result(),\n        )\n    }\n\n    // computation transformations\n\n    /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.\n    ///\n    /// Unlike [crate::ParIter::map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn map<Out, Map>(self, map: Map) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone;\n\n    /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.\n    ///\n    /// Unlike [crate::ParIter::filter], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn filter<Filter>(self, filter: Filter) -> impl ParIterUsing<'using, U, R, Item = Self::Item>\n    where\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone;\n\n    /// Creates an iterator that works like map, but flattens nested structure.\n    ///\n    /// Unlike [crate::ParIter::flat_map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = IOut::Item>\n    where\n        IOut: IntoIterator,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone;\n\n    /// Creates an iterator that both filters and maps.\n    ///\n    /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.\n    ///\n    /// `filter_map` can be used to make chains of `filter` and `map` more concise.\n    ///\n    /// Unlike [crate::ParIter::filter_map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterUsing<'using, U, R, Item = Out>\n    where\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone;\n\n    /// Does something with each element of an iterator, passing the value on.\n    ///\n    /// Unlike [crate::ParIter::inspect], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn inspect<Operation>(\n        self,\n        operation: Operation,\n    ) -> impl ParIterUsing<'using, U, R, Item = Self::Item>\n    where\n        Operation: Fn(&mut U::Item, &Self::Item) + Sync + Clone,\n    {\n        let map = move |u: &mut U::Item, x: Self::Item| {\n            operation(u, &x);\n            x\n        };\n        self.map(map)\n    }\n\n    // special item transformations\n\n    /// Creates an iterator which copies all of its elements.\n    ///\n    /// Unlike [crate::ParIter::copied], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn copied<'a, T>(self) -> impl ParIterUsing<'using, U, R, Item = T>\n    where\n        T: 'a + Copy,\n        Self: ParIterUsing<'using, U, R, Item = &'a T>,\n    {\n        self.map(u_map_copy)\n    }\n\n    /// Creates an iterator which clones all of its elements.\n    ///\n    /// Unlike [crate::ParIter::cloned], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn cloned<'a, T>(self) -> impl ParIterUsing<'using, U, R, Item = T>\n    where\n        T: 'a + Clone,\n        Self: ParIterUsing<'using, U, R, Item = &'a T>,\n    {\n        self.map(u_map_clone)\n    }\n\n    /// Creates an iterator that flattens nested structure.\n    ///\n    /// Unlike [crate::ParIter::flatten], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn flatten(self) -> impl ParIterUsing<'using, U, R, Item = <Self::Item as IntoIterator>::Item>\n    where\n        Self::Item: IntoIterator,\n    {\n        let map = |_: &mut U::Item, e: Self::Item| e.into_iter();\n        self.flat_map(map)\n    }\n\n    // collect\n\n    /// Collects all the items from an iterator into a collection.\n    ///\n    /// Unlike [crate::ParIter::collect_into], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn collect_into<C>(self, output: C) -> C\n    where\n        C: ParCollectInto<Self::Item>;\n\n    /// Transforms an iterator into a collection.\n    ///\n    /// Unlike [crate::ParIter::collect], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn collect<C>(self) -> C\n    where\n        C: ParCollectInto<Self::Item>,\n    {\n        let output = C::empty(self.con_iter().try_get_len());\n        self.collect_into(output)\n    }\n\n    // reduce\n\n    /// Reduces the elements to a single one, by repeatedly applying a reducing operation.\n    ///\n    /// See the details here: [crate::ParIter::reduce].\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync;\n\n    /// Tests if every element of the iterator matches a predicate.\n    ///\n    /// Unlike [crate::ParIter::all], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn all<Predicate>(self, predicate: Predicate) -> bool\n    where\n        Self::Item: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n    {\n        let violates = |u: &mut U::Item, x: &Self::Item| !predicate(u, x);\n        self.find(violates).is_none()\n    }\n\n    /// Tests if any element of the iterator matches a predicate.\n    ///\n    /// Unlike [crate::ParIter::any], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn any<Predicate>(self, predicate: Predicate) -> bool\n    where\n        Self::Item: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n    {\n        self.find(predicate).is_some()\n    }\n\n    /// Consumes the iterator, counting the number of iterations and returning it.\n    ///\n    /// See the details here: [crate::ParIter::count].\n    fn count(self) -> usize {\n        self.map(u_map_count).reduce(u_reduce_sum).unwrap_or(0)\n    }\n\n    /// Calls a closure on each element of an iterator.\n    ///\n    /// Unlike [crate::ParIter::for_each], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn for_each<Operation>(self, operation: Operation)\n    where\n        Operation: Fn(&mut U::Item, Self::Item) + Sync,\n    {\n        let map = |u: &mut U::Item, x| operation(u, x);\n        let _ = self.map(map).reduce(u_reduce_unit);\n    }\n\n    /// Returns the maximum element of an iterator.\n    ///\n    /// See the details here: [crate::ParIter::max].\n    fn max(self) -> Option<Self::Item>\n    where\n        Self::Item: Ord + Send,\n    {\n        self.reduce(|_, a, b| Ord::max(a, b))\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    ///\n    /// See the details here: [crate::ParIter::max_by].\n    fn max_by<Compare>(self, compare: Compare) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the maximum value from the specified function.\n    ///\n    /// See the details here: [crate::ParIter::max_by_key].\n    fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match key(&x).cmp(&key(&y)) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the minimum element of an iterator.\n    ///\n    /// See the details here: [crate::ParIter::min].\n    fn min(self) -> Option<Self::Item>\n    where\n        Self::Item: Ord + Send,\n    {\n        self.reduce(|_, a, b| Ord::min(a, b))\n    }\n\n    /// Returns the element that gives the minimum value with respect to the specified `compare` function.\n    ///\n    /// See the details here: [crate::ParIter::min_by].\n    fn min_by<Compare>(self, compare: Compare) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the minimum value from the specified function.\n    ///\n    /// See the details here: [crate::ParIter::min_by_key].\n    fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match get_key(&x).cmp(&get_key(&y)) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Sums the elements of an iterator.\n    ///\n    /// See the details here: [crate::ParIter::sum].\n    fn sum<Out>(self) -> Out\n    where\n        Self::Item: Sum<Out>,\n        Out: Send,\n    {\n        self.map(Self::Item::u_map)\n            .reduce(Self::Item::u_reduce)\n            .unwrap_or(Self::Item::zero())\n    }\n\n    // early exit\n\n    /// Returns the first (or any) element of the iterator; returns None if it is empty.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// See the details here: [crate::ParIter::first].\n    fn first(self) -> Option<Self::Item>\n    where\n        Self::Item: Send;\n\n    /// Searches for an element of an iterator that satisfies a `predicate`.\n    ///\n    /// Unlike [crate::ParIter::find], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn find<Predicate>(self, predicate: Predicate) -> Option<Self::Item>\n    where\n        Self::Item: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        self.filter(&predicate).first()\n    }\n}\n"
  },
  {
    "path": "src/using/u_par_iter_option.rs",
    "content": "use crate::default_fns::{u_map_count, u_reduce_sum, u_reduce_unit};\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::Using;\nuse crate::{\n    ChunkSize, IterationOrder, NumThreads, ParCollectInto, ParThreadPool, RunnerWithPool, Sum,\n};\nuse core::cmp::Ordering;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with None.\n///\n/// Unlike [crate::ParIterOption], the threads have access to a mutable reference of the used variable in each thread.\n///\n/// Please see [`crate::ParIterUsing`] for details and examples.\n///\n/// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\npub trait ParIterOptionUsing<'using, U, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    U: Using<'using>,\n{\n    /// Type of the success element, to be received as the Some variant iff the entire computation succeeds.\n    type Item;\n\n    // params transformations\n\n    /// Sets the number of threads to be used in the parallel execution.\n    /// Integers can be used as the argument with the following mapping:\n    ///\n    /// * `0` -> `NumThreads::Auto`\n    /// * `1` -> `NumThreads::sequential()`\n    /// * `n > 0` -> `NumThreads::Max(n)`\n    ///\n    /// See [`NumThreads`] and [`crate::ParIter::num_threads`] for details.\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;\n\n    /// Sets the number of elements to be pulled from the concurrent iterator during the\n    /// parallel execution. When integers are used as argument, the following mapping applies:\n    ///\n    /// * `0` -> `ChunkSize::Auto`\n    /// * `n > 0` -> `ChunkSize::Exact(n)`\n    ///\n    /// Please use the default enum constructor for creating `ChunkSize::Min` variant.\n    ///\n    /// See [`ChunkSize`] and [`crate::ParIter::chunk_size`] for details.\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;\n\n    /// Sets the iteration order of the parallel computation.\n    ///\n    /// See [`IterationOrder`] and [`crate::ParIter::iteration_order`] for details.\n    fn iteration_order(self, order: IterationOrder) -> Self;\n\n    /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].\n    ///\n    /// See [`ParIter::with_runner`] for details.\n    ///\n    /// [`DefaultRunner`]: crate::DefaultRunner\n    /// [`ParIter::with_runner`]: crate::ParIter::with_runner\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterOptionUsing<'using, U, Q, Item = Self::Item>;\n\n    /// Rather than [`DefaultPool`], uses the parallel runner with the given `pool` implementing\n    /// [`ParThreadPool`].\n    ///\n    /// See [`ParIter::with_pool`] for details.\n    ///\n    /// [`DefaultPool`]: crate::DefaultPool\n    /// [`ParIter::with_pool`]: crate::ParIter::with_pool\n    fn with_pool<P: ParThreadPool>(\n        self,\n        pool: P,\n    ) -> impl ParIterOptionUsing<'using, U, RunnerWithPool<P, R::Executor>, Item = Self::Item>\n    where\n        Self: Sized,\n    {\n        let runner = RunnerWithPool::from(pool).with_executor::<R::Executor>();\n        self.with_runner(runner)\n    }\n\n    // computation transformations\n\n    /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Some` variant.\n    /// Any observation of a `None` case short-circuits the computation and immediately returns None.\n    ///\n    /// Unlike [crate::ParIterOption::map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn map<Out, Map>(self, map: Map) -> impl ParIterOptionUsing<'using, U, R, Item = Out>\n    where\n        Self: Sized,\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone,\n        Out: Send;\n\n    /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Some` variant.\n    /// Any observation of a `None` case short-circuits the computation and immediately returns None.\n    ///\n    /// Unlike [crate::ParIterOption::filter], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn filter<Filter>(\n        self,\n        filter: Filter,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = Self::Item>\n    where\n        Self: Sized,\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n        Self::Item: Send;\n\n    /// Creates an iterator that works like map, but flattens nested structure.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Some` variant.\n    /// Any observation of a `None` case short-circuits the computation and immediately returns None.\n    ///\n    /// Unlike [crate::ParIterOption::flat_map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = IOut::Item>\n    where\n        Self: Sized,\n        IOut: IntoIterator,\n        IOut::Item: Send,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone;\n\n    /// Creates an iterator that both filters and maps.\n    ///\n    /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.\n    ///\n    /// `filter_map` can be used to make chains of `filter` and `map` more concise.\n    ///\n    /// Unlike [crate::ParIterOption::filter_map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = Out>\n    where\n        Self: Sized,\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone,\n        Out: Send;\n\n    /// Does something with each successful element of an iterator, passing the value on, provided that all elements are of Some variant;\n    /// short-circuits and returns None otherwise.\n    ///\n    /// Unlike [crate::ParIterOption::inspect], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn inspect<Operation>(\n        self,\n        operation: Operation,\n    ) -> impl ParIterOptionUsing<'using, U, R, Item = Self::Item>\n    where\n        Self: Sized,\n        Operation: Fn(&mut U::Item, &Self::Item) + Sync + Clone,\n        Self::Item: Send;\n\n    // collect\n\n    /// Collects all the items from an iterator into a collection iff all elements are of Some variant.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// Unlike [crate::ParIterOption::collect_into], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn collect_into<C>(self, output: C) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>;\n\n    /// Transforms an iterator into a collection iff all elements are of Ok variant.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Similar to [`Iterator::collect`], the type annotation on the left-hand-side determines\n    /// the type of the result collection; or turbofish annotation can be used.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// Unlike [crate::ParIterOption::collect], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn collect<C>(self) -> Option<C>\n    where\n        Self::Item: Send,\n        C: ParCollectInto<Self::Item>;\n\n    // reduce\n\n    /// Reduces the elements to a single one, by repeatedly applying a reducing operation.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// If the iterator is empty, returns `Some(None)`; otherwise, returns `Some` of result of the reduction.\n    ///\n    /// Unlike [crate::ParIterOption::reduce], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn reduce<Reduce>(self, reduce: Reduce) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync;\n\n    /// Tests if every element of the iterator matches a predicate.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// Unlike [crate::ParIterOption::all], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn all<Predicate>(self, predicate: Predicate) -> Option<bool>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        let violates = |u: &mut U::Item, x: &Self::Item| !predicate(u, x);\n        self.find(violates).map(|x| x.is_none())\n    }\n\n    /// Tests if any element of the iterator matches a predicate.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// Unlike [crate::ParIterOption::any], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn any<Predicate>(self, predicate: Predicate) -> Option<bool>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        self.find(predicate).map(|x| x.is_some())\n    }\n\n    /// Consumes the iterator, counting the number of iterations and returning it.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::count].\n    fn count(self) -> Option<usize>\n    where\n        Self: Sized,\n    {\n        self.map(u_map_count)\n            .reduce(u_reduce_sum)\n            .map(|x| x.unwrap_or(0))\n    }\n\n    /// Calls a closure on each element of an iterator, and returns `Ok(())` if all elements succeed.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// Unlike [crate::ParIterOption::for_each], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn for_each<Operation>(self, operation: Operation) -> Option<()>\n    where\n        Self: Sized,\n        Operation: Fn(&mut U::Item, Self::Item) + Sync,\n    {\n        let map = |u: &mut U::Item, x: Self::Item| operation(u, x);\n        self.map(map).reduce(u_reduce_unit).map(|_| ())\n    }\n\n    /// Returns Some of maximum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::max].\n    fn max(self) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Ord + Send,\n    {\n        self.reduce(|_, a, b| Ord::max(a, b))\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::max_by].\n    fn max_by<Compare>(self, compare: Compare) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the maximum value from the specified function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::max_by_key].\n    fn max_by_key<Key, GetKey>(self, key: GetKey) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match key(&x).cmp(&key(&y)) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns Some of minimum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::min].\n    fn min(self) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Ord + Send,\n    {\n        self.reduce(|_, a, b| Ord::min(a, b))\n    }\n\n    /// Returns the element that gives the minimum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::min_by].\n    fn min_by<Compare>(self, compare: Compare) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the minimum value from the specified function.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// See the details here: [crate::ParIterOption::min_by_key].\n    fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match get_key(&x).cmp(&get_key(&y)) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Sums the elements of an iterator.\n    /// Early exits and returns None if any of the elements is None.\n    ///\n    /// If the iterator is empty, returns zero; otherwise, returns `Some` of the sum.\n    ///\n    /// See the details here: [crate::ParIterOption::sum].\n    fn sum<Out>(self) -> Option<Out>\n    where\n        Self: Sized,\n        Self::Item: Sum<Out>,\n        Out: Send,\n    {\n        self.map(Self::Item::u_map)\n            .reduce(Self::Item::u_reduce)\n            .map(|x| x.unwrap_or(Self::Item::zero()))\n    }\n\n    // early exit\n\n    /// Returns the first (or any) element of the iterator.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if a None element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// See the details here: [crate::ParIter::first].\n    fn first(self) -> Option<Option<Self::Item>>\n    where\n        Self::Item: Send;\n\n    /// Returns the first (or any) element of the iterator that satisfies the `predicate`.\n    /// If the iterator is empty, `Some(None)` is returned.\n    /// Early exits and returns None if a None element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// Note that `find` itself is short-circuiting in addition to fallible computation.\n    /// Therefore, in case the fallible iterator contains both a None and a Some element,\n    /// the result is **not deterministic**:\n    /// * it might be the `None` if it is observed first;\n    /// * or `Some(element)` if the Some element satisfying the predicate is observed first.\n    ///\n    /// Unlike [crate::ParIterOption::find], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn find<Predicate>(self, predicate: Predicate) -> Option<Option<Self::Item>>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        self.filter(&predicate).first()\n    }\n}\n"
  },
  {
    "path": "src/using/u_par_iter_result.rs",
    "content": "use crate::default_fns::{u_map_count, u_reduce_sum, u_reduce_unit};\nuse crate::par_iter_result::IntoResult;\nuse crate::runner::{DefaultRunner, ParallelRunner};\nuse crate::using::Using;\nuse crate::{\n    ChunkSize, IterationOrder, NumThreads, ParIterUsing, ParThreadPool, RunnerWithPool, Sum,\n};\nuse crate::{ParCollectInto, generic_values::fallible_iterators::ResultOfIter};\nuse core::cmp::Ordering;\n\n/// A parallel iterator for which the computation either completely succeeds,\n/// or fails and **early exits** with an error.\n///\n/// Unlike [crate::ParIterResult], the threads have access to a mutable reference of the used variable in each thread.\n///\n/// Please see [`crate::ParIterUsing`] for details and examples.\n///\n/// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\npub trait ParIterResultUsing<'using, U, R = DefaultRunner>\nwhere\n    R: ParallelRunner,\n    U: Using<'using>,\n{\n    /// Type of the Ok element, to be received as the Ok variant iff the entire computation succeeds.\n    type Item;\n\n    /// Type of the Err element, to be received if any of the computations fails.\n    type Err;\n\n    /// Element type of the regular parallel iterator this fallible iterator can be converted to, simply `Result<Self::Ok, Self::Err>`.\n    type RegularItem: IntoResult<Self::Item, Self::Err>;\n\n    /// Regular parallel iterator this fallible iterator can be converted into.\n    type RegularParIter: ParIterUsing<'using, U, R, Item = Self::RegularItem>;\n\n    /// Returns a reference to the input concurrent iterator.\n    fn con_iter_len(&self) -> Option<usize>;\n\n    /// Converts this fallible iterator into a regular parallel iterator; i.e., [`ParIter`], with `Item = Result<Self::Ok, Self::Err>`.\n    fn into_regular_par(self) -> Self::RegularParIter;\n\n    /// Converts the `regular_par` iterator with `Item = Result<Self::Ok, Self::Err>` into fallible result iterator.\n    fn from_regular_par(regular_par: Self::RegularParIter) -> Self;\n\n    // params transformations\n\n    /// Sets the number of threads to be used in the parallel execution.\n    /// Integers can be used as the argument with the following mapping:\n    ///\n    /// * `0` -> `NumThreads::Auto`\n    /// * `1` -> `NumThreads::sequential()`\n    /// * `n > 0` -> `NumThreads::Max(n)`\n    ///\n    /// See [`NumThreads`] and [`ParIter::num_threads`] for details.\n    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self\n    where\n        Self: Sized,\n    {\n        Self::from_regular_par(self.into_regular_par().num_threads(num_threads))\n    }\n\n    /// Sets the number of elements to be pulled from the concurrent iterator during the\n    /// parallel execution. When integers are used as argument, the following mapping applies:\n    ///\n    /// * `0` -> `ChunkSize::Auto`\n    /// * `n > 0` -> `ChunkSize::Exact(n)`\n    ///\n    /// Please use the default enum constructor for creating `ChunkSize::Min` variant.\n    ///\n    /// See [`ChunkSize`] and [`ParIter::chunk_size`] for details.\n    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self\n    where\n        Self: Sized,\n    {\n        Self::from_regular_par(self.into_regular_par().chunk_size(chunk_size))\n    }\n\n    /// Sets the iteration order of the parallel computation.\n    ///\n    /// See [`IterationOrder`] and [`ParIter::iteration_order`] for details.\n    fn iteration_order(self, order: IterationOrder) -> Self\n    where\n        Self: Sized,\n    {\n        Self::from_regular_par(self.into_regular_par().iteration_order(order))\n    }\n\n    /// Rather than the [`DefaultRunner`], uses the parallel runner `Q` which implements [`ParallelRunner`].\n    ///\n    /// See [`ParIter::with_runner`] for details.\n    ///\n    /// [`DefaultRunner`]: crate::DefaultRunner\n    /// [`ParIter::with_runner`]: crate::ParIter::with_runner\n    fn with_runner<Q: ParallelRunner>(\n        self,\n        orchestrator: Q,\n    ) -> impl ParIterResultUsing<'using, U, Q, Item = Self::Item, Err = Self::Err>;\n\n    /// Rather than [`DefaultPool`], uses the parallel runner with the given `pool` implementing\n    /// [`ParThreadPool`].\n    ///\n    /// See [`ParIter::with_pool`] for details.\n    ///\n    /// [`DefaultPool`]: crate::DefaultPool\n    /// [`ParIter::with_pool`]: crate::ParIter::with_pool\n    fn with_pool<P: ParThreadPool>(\n        self,\n        pool: P,\n    ) -> impl ParIterResultUsing<\n        'using,\n        U,\n        RunnerWithPool<P, R::Executor>,\n        Item = Self::Item,\n        Err = Self::Err,\n    >\n    where\n        Self: Sized,\n    {\n        let runner = RunnerWithPool::from(pool).with_executor::<R::Executor>();\n        self.with_runner(runner)\n    }\n\n    // computation transformations\n\n    /// Takes a closure `map` and creates a parallel iterator which calls that closure on each element.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Ok` variant.\n    /// Any observation of an `Err` case short-circuits the computation and immediately returns the observed error.\n    ///\n    /// Unlike [crate::ParIterResult::map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn map<Out, Map>(\n        self,\n        map: Map,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Out, Err = Self::Err>\n    where\n        Self: Sized,\n        Map: Fn(&mut U::Item, Self::Item) -> Out + Sync + Clone,\n        Out: Send,\n    {\n        let par = self.into_regular_par();\n        let map = par.map(move |u, x| x.into_result().map(|inner| map.clone()(u, inner)));\n        map.into_fallible_result()\n    }\n\n    /// Creates an iterator which uses a closure `filter` to determine if an element should be yielded.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Ok` variant.\n    /// Any observation of an `Err` case short-circuits the computation and immediately returns the observed error.\n    ///\n    /// Unlike [crate::ParIterResult::filter], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn filter<Filter>(\n        self,\n        filter: Filter,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Self::Item, Err = Self::Err>\n    where\n        Self: Sized,\n        Filter: Fn(&mut U::Item, &Self::Item) -> bool + Sync + Clone,\n        Self::Item: Send,\n    {\n        let par = self.into_regular_par();\n        let filter_map = par.filter_map(move |u, x| match x.into_result() {\n            Ok(x) => match filter(u, &x) {\n                true => Some(Ok(x)),\n                false => None,\n            },\n            Err(e) => Some(Err(e)),\n        });\n        filter_map.into_fallible_result()\n    }\n\n    /// Creates an iterator that works like map, but flattens nested structure.\n    ///\n    /// Transformation is only for the success path where all elements are of the `Ok` variant.\n    /// Any observation of an `Err` case short-circuits the computation and immediately returns the observed error.\n    ///\n    /// Unlike [crate::ParIterResult::flat_map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn flat_map<IOut, FlatMap>(\n        self,\n        flat_map: FlatMap,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = IOut::Item, Err = Self::Err>\n    where\n        Self: Sized,\n        IOut: IntoIterator,\n        IOut::Item: Send,\n        FlatMap: Fn(&mut U::Item, Self::Item) -> IOut + Sync + Clone,\n    {\n        let par = self.into_regular_par();\n        let map = par.flat_map(move |u, x| match x.into_result() {\n            Ok(x) => ResultOfIter::ok(flat_map(u, x).into_iter()),\n            Err(e) => ResultOfIter::err(e),\n        });\n        map.into_fallible_result()\n    }\n\n    /// Creates an iterator that both filters and maps.\n    ///\n    /// The returned iterator yields only the values for which the supplied closure `filter_map` returns `Some(value)`.\n    ///\n    /// `filter_map` can be used to make chains of `filter` and `map` more concise.\n    /// The example below shows how a `map().filter().map()` can be shortened to a single call to `filter_map`.\n    ///\n    /// Unlike [crate::ParIterResult::filter_map], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn filter_map<Out, FilterMap>(\n        self,\n        filter_map: FilterMap,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Out, Err = Self::Err>\n    where\n        Self: Sized,\n        FilterMap: Fn(&mut U::Item, Self::Item) -> Option<Out> + Sync + Clone,\n        Out: Send,\n    {\n        let par = self.into_regular_par();\n        let filter_map = par.filter_map(move |u, x| match x.into_result() {\n            Ok(x) => filter_map(u, x).map(|x| Ok(x)),\n            Err(e) => Some(Err(e)),\n        });\n        filter_map.into_fallible_result()\n    }\n\n    /// Does something with each successful element of an iterator, passing the value on, provided that all elements are of Ok variant;\n    /// short-circuits and returns the error otherwise.\n    ///\n    /// Unlike [crate::ParIterResult::inspect], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn inspect<Operation>(\n        self,\n        operation: Operation,\n    ) -> impl ParIterResultUsing<'using, U, R, Item = Self::Item, Err = Self::Err>\n    where\n        Self: Sized,\n        Operation: Fn(&mut U::Item, &Self::Item) + Sync + Clone,\n        Self::Item: Send,\n    {\n        let map = move |u: &mut U::Item, x: Self::Item| {\n            operation(u, &x);\n            x\n        };\n        self.map(map)\n    }\n\n    // collect\n\n    /// Collects all the items from an iterator into a collection iff all elements are of Ok variant.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Unlike [crate::ParIterResult::collect_into], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn collect_into<C>(self, output: C) -> Result<C, Self::Err>\n    where\n        C: ParCollectInto<Self::Item>,\n        Self::Item: Send,\n        Self::Err: Send;\n\n    /// Transforms an iterator into a collection iff all elements are of Ok variant.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Similar to [`Iterator::collect`], the type annotation on the left-hand-side determines\n    /// the type of the result collection; or turbofish annotation can be used.\n    ///\n    /// All collections implementing [`ParCollectInto`] can be used to collect into.\n    ///\n    /// [`ParCollectInto`]: crate::ParCollectInto\n    ///\n    /// Unlike [crate::ParIterResult::collect], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn collect<C>(self) -> Result<C, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        C: ParCollectInto<Self::Item>,\n    {\n        let output = C::empty(self.con_iter_len());\n        self.collect_into(output)\n    }\n\n    // reduce\n\n    /// Reduces the elements to a single one, by repeatedly applying a reducing operation.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// If the iterator is empty, returns `Ok(None)`; otherwise, returns `Ok` of result of the reduction.\n    ///\n    /// Unlike [crate::ParIterResult::reduce], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn reduce<Reduce>(self, reduce: Reduce) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send,\n        Reduce: Fn(&mut U::Item, Self::Item, Self::Item) -> Self::Item + Sync;\n\n    /// Tests if every element of the iterator matches a predicate.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Unlike [crate::ParIterResult::all], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn all<Predicate>(self, predicate: Predicate) -> Result<bool, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        let violates = |u: &mut U::Item, x: &Self::Item| !predicate(u, x);\n        self.find(violates).map(|x| x.is_none())\n    }\n\n    /// Tests if any element of the iterator matches a predicate.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Unlike [crate::ParIterResult::any], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn any<Predicate>(self, predicate: Predicate) -> Result<bool, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        self.find(predicate).map(|x| x.is_some())\n    }\n\n    /// Consumes the iterator, counting the number of iterations and returning it.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::count].\n    fn count(self) -> Result<usize, Self::Err>\n    where\n        Self: Sized,\n        Self::Err: Send,\n    {\n        self.map(u_map_count)\n            .reduce(u_reduce_sum)\n            .map(|x| x.unwrap_or(0))\n    }\n\n    /// Calls a closure on each element of an iterator, and returns `Ok(())` if all elements succeed.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// Unlike [crate::ParIterResult::for_each], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn for_each<Operation>(self, operation: Operation) -> Result<(), Self::Err>\n    where\n        Self: Sized,\n        Self::Err: Send,\n        Operation: Fn(&mut U::Item, Self::Item) + Sync,\n    {\n        let map = |u: &mut U::Item, x: Self::Item| operation(u, x);\n        self.map(map).reduce(u_reduce_unit).map(|_| ())\n    }\n\n    /// Returns Ok of maximum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::max].\n    fn max(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Err: Send,\n        Self::Item: Ord + Send,\n    {\n        self.reduce(|_, a, b| Ord::max(a, b))\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::max_by].\n    fn max_by<Compare>(self, compare: Compare) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the maximum value from the specified function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::max_by_key].\n    fn max_by_key<Key, GetKey>(self, key: GetKey) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match key(&x).cmp(&key(&y)) {\n            Ordering::Greater | Ordering::Equal => x,\n            Ordering::Less => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns Ok of minimum element of an iterator if all elements succeed.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::min].\n    fn min(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Ord + Send,\n        Self::Err: Send,\n    {\n        self.reduce(|_, a, b| Ord::min(a, b))\n    }\n\n    /// Returns the element that gives the maximum value with respect to the specified `compare` function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::min_by].\n    fn min_by<Compare>(self, compare: Compare) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Compare: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match compare(&x, &y) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Returns the element that gives the minimum value from the specified function.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// See the details here: [crate::ParIterResult::min_by_key].\n    fn min_by_key<Key, GetKey>(self, get_key: GetKey) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Key: Ord,\n        GetKey: Fn(&Self::Item) -> Key + Sync,\n    {\n        let reduce = |_: &mut U::Item, x, y| match get_key(&x).cmp(&get_key(&y)) {\n            Ordering::Less | Ordering::Equal => x,\n            Ordering::Greater => y,\n        };\n        self.reduce(reduce)\n    }\n\n    /// Sums the elements of an iterator.\n    /// Early exits and returns the error if any of the elements is an Err.\n    ///\n    /// If the iterator is empty, returns zero; otherwise, returns `Ok` of the sum.\n    ///\n    /// See the details here: [crate::ParIterResult::sum].\n    fn sum<Out>(self) -> Result<Out, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Sum<Out>,\n        Self::Err: Send,\n        Out: Send,\n    {\n        self.map(Self::Item::u_map)\n            .reduce(Self::Item::u_reduce)\n            .map(|x| x.unwrap_or(Self::Item::zero()))\n    }\n\n    // early exit\n\n    /// Returns the first (or any) element of the iterator.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if an Err element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// See the details here: [crate::ParIter::first].\n    fn first(self) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self::Item: Send,\n        Self::Err: Send;\n\n    /// Returns the first (or any) element of the iterator that satisfies the `predicate`.\n    /// If the iterator is empty, `Ok(None)` is returned.\n    /// Early exits and returns the error if an Err element is observed first.\n    ///\n    /// * first element is returned if default iteration order `IterationOrder::Ordered` is used,\n    /// * any element is returned if `IterationOrder::Arbitrary` is set.\n    ///\n    /// Note that `find` itself is short-circuiting in addition to fallible computation.\n    /// Therefore, in case the fallible iterator contains both an Err and an Ok element,\n    /// the result is **not deterministic**:\n    /// * it might be the `Err` if it is observed first;\n    /// * or `Ok(element)` if the Ok element satisfying the predicate is observed first.\n    ///\n    /// Unlike [crate::ParIterResult::find], the closure allows access to mutable reference of the used variable.\n    ///\n    /// Please see [`crate::ParIter::using`] transformation for details and examples.\n    ///\n    /// Further documentation can be found here: [`using.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/using.md).\n    fn find<Predicate>(self, predicate: Predicate) -> Result<Option<Self::Item>, Self::Err>\n    where\n        Self: Sized,\n        Self::Item: Send,\n        Self::Err: Send,\n        Predicate: Fn(&mut U::Item, &Self::Item) -> bool + Sync,\n    {\n        self.filter(&predicate).first()\n    }\n}\n"
  },
  {
    "path": "src/using/using_variants.rs",
    "content": "/// A type that can [`create`] a value per thread, which will then be send to the thread,\n/// and used mutable by the defined computation.\n///\n/// [`create`]: crate::using::Using::create\npub trait Using<'using>: Sync {\n    /// Item to be used mutably by each threads used in parallel computation.\n    type Item: 'using;\n\n    /// Creates an instance of the variable to be used by the `thread_idx`-th thread.\n    fn create(&self, thread_idx: usize) -> Self::Item;\n\n    /// Consumes self and creates exactly one instance of the variable.\n    fn into_inner(self) -> Self::Item;\n}\n\n/// Using variant that creates instances of each thread by cloning an initial value.\npub struct UsingClone<T: Clone + 'static>(T);\n\nimpl<T: Clone + 'static> UsingClone<T> {\n    pub(crate) fn new(value: T) -> Self {\n        Self(value)\n    }\n}\n\nimpl<T: Clone + 'static> Using<'static> for UsingClone<T> {\n    type Item = T;\n\n    fn create(&self, _: usize) -> T {\n        self.0.clone()\n    }\n\n    fn into_inner(self) -> Self::Item {\n        self.0\n    }\n}\n\nunsafe impl<T: Clone + 'static> Sync for UsingClone<T> {}\n\n/// Using variant that creates instances of each thread using a closure.\npub struct UsingFun<F, T>\nwhere\n    F: Fn(usize) -> T + Sync,\n{\n    fun: F,\n}\n\nimpl<F, T> UsingFun<F, T>\nwhere\n    F: Fn(usize) -> T + Sync,\n{\n    pub(crate) fn new(fun: F) -> Self {\n        Self { fun }\n    }\n}\n\nimpl<'using, F, T> Using<'using> for UsingFun<F, T>\nwhere\n    T: 'using,\n    F: Fn(usize) -> T + Sync,\n{\n    type Item = T;\n\n    fn create(&self, thread_idx: usize) -> Self::Item {\n        (self.fun)(thread_idx)\n    }\n\n    fn into_inner(self) -> Self::Item {\n        (self.fun)(0)\n    }\n}\n"
  },
  {
    "path": "src/value_variants/whilst_iterators/whilst_atom_flat_map.rs",
    "content": "use crate::generic_values::whilst_atom::WhilstAtom;\n\npub struct WhilstAtomFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    current_iter: WhilstAtom<Vo::IntoIter>,\n}\n\nimpl<Vo> WhilstAtomFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    pub fn from_atom<T, Fm>(atom: WhilstAtom<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(flat_map(x).into_iter()),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        };\n        Self { current_iter }\n    }\n\n    pub fn u_from_atom<U, T, Fm>(u: &mut U, atom: WhilstAtom<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(&mut U, T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(flat_map(u, x).into_iter()),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        };\n        Self { current_iter }\n    }\n}\n\nimpl<Vo> Iterator for WhilstAtomFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    type Item = WhilstAtom<Vo::Item>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match &mut self.current_iter {\n            WhilstAtom::Continue(x) => x.next().map(WhilstAtom::Continue), // None if flat-map iterator is consumed\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),                    // input is Stop\n        }\n    }\n}\n"
  },
  {
    "path": "src/value_variants/whilst_iterators/whilst_option_flat_map.rs",
    "content": "use crate::generic_values::{WhilstAtom, WhilstOption};\n\npub struct WhilstOptionFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    current_iter: WhilstOption<Vo::IntoIter>,\n}\n\nimpl<Vo> WhilstOptionFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    pub fn from_option<T, Fm>(atom: WhilstOption<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstOption::ContinueSome(x) => WhilstOption::ContinueSome(flat_map(x).into_iter()),\n            WhilstOption::ContinueNone => WhilstOption::ContinueNone,\n            WhilstOption::Stop => WhilstOption::Stop,\n        };\n        Self { current_iter }\n    }\n\n    pub fn u_from_option<U, T, Fm>(u: &mut U, atom: WhilstOption<T>, flat_map: Fm) -> Self\n    where\n        Fm: Fn(&mut U, T) -> Vo,\n    {\n        let current_iter = match atom {\n            WhilstOption::ContinueSome(x) => WhilstOption::ContinueSome(flat_map(u, x).into_iter()),\n            WhilstOption::ContinueNone => WhilstOption::ContinueNone,\n            WhilstOption::Stop => WhilstOption::Stop,\n        };\n        Self { current_iter }\n    }\n}\n\nimpl<Vo> Iterator for WhilstOptionFlatMapIter<Vo>\nwhere\n    Vo: IntoIterator,\n{\n    type Item = WhilstAtom<Vo::Item>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match &mut self.current_iter {\n            WhilstOption::ContinueSome(x) => x.next().map(WhilstAtom::Continue), // None if flat-map iterator is consumed\n            WhilstOption::ContinueNone => None, // flat-map is created on None => empty iterator\n            WhilstOption::Stop => Some(WhilstAtom::Stop), // input is Stop\n        }\n    }\n}\n"
  },
  {
    "path": "src/value_variants/whilst_vector.rs",
    "content": "use super::transformable_values::TransformableValues;\nuse crate::generic_values::{\n    Values, WhilstAtom,\n    runner_results::{\n        ArbitraryPush, Fallible, Infallible, Next, OrderedPush, Reduce, SequentialPush,\n    },\n    whilst_iterators::WhilstAtomFlatMapIter,\n    whilst_vector_result::WhilstVectorResult,\n};\nuse orx_concurrent_bag::ConcurrentBag;\nuse orx_fixed_vec::IntoConcurrentPinnedVec;\nuse orx_pinned_vec::PinnedVec;\n\npub struct WhilstVector<I, T>(pub(crate) I)\nwhere\n    I: IntoIterator<Item = WhilstAtom<T>>;\n\nimpl<I, T> Values for WhilstVector<I, T>\nwhere\n    I: IntoIterator<Item = WhilstAtom<T>>,\n{\n    type Item = T;\n\n    type Fallibility = Infallible;\n\n    fn push_to_pinned_vec<P>(self, vector: &mut P) -> SequentialPush<Self::Fallibility>\n    where\n        P: PinnedVec<Self::Item>,\n    {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(x) => vector.push(x),\n                WhilstAtom::Stop => return SequentialPush::StoppedByWhileCondition,\n            }\n        }\n        SequentialPush::Done\n    }\n\n    fn push_to_vec_with_idx(\n        self,\n        idx: usize,\n        vec: &mut Vec<(usize, Self::Item)>,\n    ) -> OrderedPush<Self::Fallibility> {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(x) => vec.push((idx, x)),\n                WhilstAtom::Stop => return OrderedPush::StoppedByWhileCondition { idx },\n            }\n        }\n        OrderedPush::Done\n    }\n\n    fn push_to_bag<P>(self, bag: &ConcurrentBag<Self::Item, P>) -> ArbitraryPush<Self::Fallibility>\n    where\n        P: IntoConcurrentPinnedVec<Self::Item>,\n        Self::Item: Send,\n    {\n        for x in self.0 {\n            match x {\n                WhilstAtom::Continue(x) => _ = bag.push(x),\n                WhilstAtom::Stop => return ArbitraryPush::StoppedByWhileCondition,\n            }\n        }\n        ArbitraryPush::Done\n    }\n\n    fn acc_reduce<X>(self, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(x) => match x {\n                        WhilstAtom::Continue(x) => x,\n                        WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: None }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                WhilstAtom::Continue(x) => acc = reduce(acc, x),\n                WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: Some(acc) },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn u_acc_reduce<U, X>(self, u: &mut U, acc: Option<Self::Item>, reduce: X) -> Reduce<Self>\n    where\n        X: Fn(&mut U, Self::Item, Self::Item) -> Self::Item,\n    {\n        let mut iter = self.0.into_iter();\n\n        let mut acc = match acc {\n            Some(x) => x,\n            None => {\n                let first = iter.next();\n                match first {\n                    None => return Reduce::Done { acc: None }, // empty iterator but not stopped, acc is None\n                    Some(x) => match x {\n                        WhilstAtom::Continue(x) => x,\n                        WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: None }, // first element is stop, acc is None\n                    },\n                }\n            }\n        };\n\n        for x in iter {\n            match x {\n                WhilstAtom::Continue(x) => acc = reduce(u, acc, x),\n                WhilstAtom::Stop => return Reduce::StoppedByWhileCondition { acc: Some(acc) },\n            }\n        }\n\n        Reduce::Done { acc: Some(acc) }\n    }\n\n    fn next(self) -> Next<Self> {\n        match self.0.into_iter().next() {\n            Some(x) => match x {\n                WhilstAtom::Continue(x) => Next::Done { value: Some(x) },\n                WhilstAtom::Stop => Next::StoppedByWhileCondition,\n            },\n            None => Next::Done { value: None },\n        }\n    }\n}\n\nimpl<I, T> TransformableValues for WhilstVector<I, T>\nwhere\n    I: IntoIterator<Item = WhilstAtom<T>>,\n{\n    fn map<M, O>(\n        self,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(Self::Item) -> O,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(map(x)),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn filter<F>(\n        self,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&Self::Item) -> bool + Clone,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => match filter(&x) {\n                true => Some(WhilstAtom::Continue(x)),\n                false => None,\n            },\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n\n    fn flat_map<Fm, Vo>(\n        self,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(Self::Item) -> Vo,\n    {\n        let iter = self\n            .0\n            .into_iter()\n            .flat_map(move |atom| WhilstAtomFlatMapIter::from_atom(atom, &flat_map));\n        WhilstVector(iter)\n    }\n\n    fn filter_map<Fm, O>(\n        self,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(Self::Item) -> Option<O>,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => filter_map(x).map(WhilstAtom::Continue),\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n\n    fn whilst(\n        self,\n        whilst: impl Fn(&Self::Item) -> bool,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        Self: Sized,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => match whilst(&x) {\n                true => WhilstAtom::Continue(x),\n                false => WhilstAtom::Stop,\n            },\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn map_while_ok<Mr, O, E>(self, map_res: Mr) -> impl Values<Item = O, Fallibility = Fallible<E>>\n    where\n        Mr: Fn(Self::Item) -> Result<O, E>,\n        E: Send,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(map_res(x)),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVectorResult(iter)\n    }\n\n    fn u_map<U, M, O>(\n        self,\n        u: &mut U,\n        map: M,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        M: Fn(&mut U, Self::Item) -> O,\n    {\n        let iter = self.0.into_iter().map(move |x| match x {\n            WhilstAtom::Continue(x) => WhilstAtom::Continue(map(u, x)),\n            WhilstAtom::Stop => WhilstAtom::Stop,\n        });\n        WhilstVector(iter)\n    }\n\n    fn u_filter<U, F>(\n        self,\n        u: &mut U,\n        filter: F,\n    ) -> impl TransformableValues<Item = Self::Item, Fallibility = Self::Fallibility>\n    where\n        F: Fn(&mut U, &Self::Item) -> bool,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => match filter(u, &x) {\n                true => Some(WhilstAtom::Continue(x)),\n                false => None,\n            },\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n\n    fn u_flat_map<U, Fm, Vo>(\n        self,\n        u: &mut U,\n        flat_map: Fm,\n    ) -> impl TransformableValues<Item = Vo::Item, Fallibility = Self::Fallibility>\n    where\n        Vo: IntoIterator,\n        Fm: Fn(&mut U, Self::Item) -> Vo,\n    {\n        let iter = self\n            .0\n            .into_iter()\n            .flat_map(move |atom| WhilstAtomFlatMapIter::u_from_atom(u, atom, &flat_map));\n        WhilstVector(iter)\n    }\n\n    fn u_filter_map<U, Fm, O>(\n        self,\n        u: &mut U,\n        filter_map: Fm,\n    ) -> impl TransformableValues<Item = O, Fallibility = Self::Fallibility>\n    where\n        Fm: Fn(&mut U, Self::Item) -> Option<O>,\n    {\n        let iter = self.0.into_iter().filter_map(move |x| match x {\n            WhilstAtom::Continue(x) => filter_map(u, x).map(WhilstAtom::Continue),\n            WhilstAtom::Stop => Some(WhilstAtom::Stop),\n        });\n        WhilstVector(iter)\n    }\n}\n"
  },
  {
    "path": "tests/chain.rs",
    "content": "use orx_parallel::*;\nuse test_case::test_matrix;\n\n#[test_matrix([193], [0, 1], [0, 47])]\nfn chain_known_known(n: usize, nt: usize, chunk: usize) {\n    let a: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let b: Vec<_> = (0..n).map(|x| (n + x).to_string()).collect();\n\n    let c: Vec<_> = a\n        .par()\n        .num_threads(nt)\n        .chunk_size(chunk)\n        .chain(&b)\n        .collect();\n    assert_eq!(c.len(), 2 * n);\n    assert_eq!(c, a.iter().chain(&b).collect::<Vec<_>>());\n}\n\n#[test_matrix([193], [0, 1], [0, 47])]\nfn chain_known_unknown(n: usize, nt: usize, chunk: usize) {\n    let a: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let b: Vec<_> = (0..n)\n        .map(|x| (n + x).to_string())\n        .filter(|x| !x.starts_with('x'))\n        .collect();\n\n    let c: Vec<_> = a\n        .par()\n        .num_threads(nt)\n        .chunk_size(chunk)\n        .chain(&b)\n        .collect();\n    assert_eq!(c.len(), 2 * n);\n    assert_eq!(c, a.iter().chain(&b).collect::<Vec<_>>());\n}\n"
  },
  {
    "path": "tests/into_par.rs",
    "content": "use orx_concurrent_iter::IntoConcurrentIter;\nuse orx_parallel::IntoParIter;\n\nfn take_into_par_into_par_bounds<T>(a: impl IntoParIter<Item = T>) {\n    let _ = a.into_par();\n}\n\nfn take_into_par_into_con_iter_bounds<T>(a: impl IntoConcurrentIter<Item = T>) {\n    let _ = a.into_par();\n}\n\n#[test]\nfn vec_into_par_iter() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n\n    take_into_par_into_par_bounds::<String>(vec.clone());\n\n    take_into_par_into_con_iter_bounds::<String>(vec);\n}\n\n#[test]\nfn slice_into_par_iter() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n    let slice = vec.as_slice();\n\n    take_into_par_into_par_bounds::<&String>(slice);\n\n    take_into_par_into_con_iter_bounds::<&String>(slice);\n}\n\n#[test]\nfn range_into_par_iter() {\n    let range = 0..10;\n\n    take_into_par_into_par_bounds::<usize>(range.clone());\n\n    take_into_par_into_con_iter_bounds::<usize>(range);\n}\n"
  },
  {
    "path": "tests/iter_into_par.rs",
    "content": "use orx_concurrent_iter::IterIntoConcurrentIter;\nuse orx_parallel::IterIntoParIter;\n\nfn take_iter_into_par_iterator_bounds<I>(a: I)\nwhere\n    I: Iterator,\n    I::Item: Send + Sync,\n{\n    let _par_iter = a.iter_into_par();\n}\n\nfn take_iter_into_par_iter_into_con_iter_bounds<I>(a: I)\nwhere\n    I: IterIntoConcurrentIter,\n    I::Item: Send + Sync,\n{\n    let _par_iter = a.iter_into_par();\n}\n\nfn take_iter_into_par_iter_into_par_bounds<T: Send>(a: impl IterIntoParIter<Item = T>) {\n    let _ = a.iter_into_par();\n}\n\n#[test]\nfn iter_into_par_iter() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n\n    let iter = vec.iter().filter(|x| x.as_str() != \"x\");\n    take_iter_into_par_iterator_bounds(iter);\n\n    let iter = vec.iter().filter(|x| x.as_str() != \"x\");\n    take_iter_into_par_iter_into_con_iter_bounds(iter);\n\n    let iter = vec.iter().filter(|x| x.as_str() != \"x\");\n    take_iter_into_par_iter_into_par_bounds(iter);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/from_map.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_map_when_ok() {\n    let input = 1..1025;\n    let map = |i: usize| i - 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .map(map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_map_when_error() {\n    let input = 1..1025;\n    let map = |i: usize| i - 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .map(map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/from_par.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_par_when_ok() {\n    let input = 0..1024;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_par_when_error() {\n    let input = 0..1024;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/from_xap_chain.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_chain_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_whilst_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = input\n        .into_iter()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .collect();\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_whilst_when_err() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1024 + i, 2048 + i];\n    let filter = |i: &usize| i < &1024;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_whilst_when_err_out_of_reach() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1024 + i, 2048 + i];\n    let filter = |i: &usize| i < &1024;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let expected = input\n        .into_iter()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .collect();\n\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/from_xap_filter.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_filter_when_ok() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).filter(filter).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_when_error() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_whilst_when_ok() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024)\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_whilst_when_err() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_whilst_when_err_out_of_reach() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let expected = Ok((0..1024)\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/from_xap_filter_map.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_ok() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).filter_map(filter_map).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_error() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_whilst_when_ok() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024)\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_whilst_when_error() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_whilst_when_error_out_of_reach() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let expected = Ok((0..1024)\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/from_xap_flat_map.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).flat_map(flat_map).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_whilst_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .flat_map(flat_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = input\n        .flat_map(flat_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .collect();\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_whilst_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .flat_map(flat_map)\n        .take_while(|i| i < &2777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 2777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_whilst_when_error_out_of_reach() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .flat_map(flat_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let expected = Ok((0..1024)\n        .flat_map(flat_map)\n        .take_while(|i| i < &777)\n        .collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect/mod.rs",
    "content": "mod from_map;\nmod from_par;\nmod from_xap_chain;\nmod from_xap_filter;\nmod from_xap_filter_map;\nmod from_xap_flat_map;\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/from_map.rs",
    "content": "use orx_parallel::*;\n\nuse crate::map_while_ok_collect_arbitrary::utils::sort_if_ok;\n\n#[test]\nfn map_while_ok_from_map_when_ok() {\n    let input = 1..1025;\n    let map = |i: usize| i - 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let result = sort_if_ok(result);\n    let expected = Ok((0..1024).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_map_when_error() {\n    let input = 1..1025;\n    let map = |i: usize| i - 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/from_par.rs",
    "content": "use orx_parallel::*;\n\nuse crate::map_while_ok_collect_arbitrary::utils::sort_if_ok;\n\n#[test]\nfn map_while_ok_from_par_when_ok() {\n    let input = 0..1024;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let result = sort_if_ok(result);\n    let expected = Ok((0..1024).collect::<Vec<_>>());\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_par_when_error() {\n    let input = 0..1024;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/from_xap_chain.rs",
    "content": "use crate::map_while_ok_collect_arbitrary::utils::sort_if_ok;\nuse orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_chain_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .collect::<Vec<_>>());\n\n    let result = sort_if_ok(result);\n    let expected = sort_if_ok(expected);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_whilst_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &777);\n    assert!(all_satisfies_whilst);\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_whilst_when_err() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1024 + i, 2048 + i];\n    let filter = |i: &usize| i < &1024;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_whilst_when_err_out_of_reach() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1024 + i, 2048 + i];\n    let filter = |i: &usize| i < &1024;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &777);\n    assert!(all_satisfies_whilst);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/from_xap_filter.rs",
    "content": "use crate::map_while_ok_collect_arbitrary::utils::sort_if_ok;\nuse orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_filter_when_ok() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).filter(filter).collect::<Vec<_>>());\n\n    let result = sort_if_ok(result);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_when_error() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_whilst_when_ok() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &777);\n    assert!(all_satisfies_whilst);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_whilst_when_err() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_whilst_when_err_out_of_reach() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter(filter)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &777);\n    assert!(all_satisfies_whilst);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/from_xap_filter_map.rs",
    "content": "use crate::map_while_ok_collect_arbitrary::utils::sort_if_ok;\nuse orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_ok() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).filter_map(filter_map).collect::<Vec<_>>());\n\n    let result = sort_if_ok(result);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_error() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_whilst_when_ok() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &777);\n    assert!(all_satisfies_whilst);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_whilst_when_error() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_whilst_when_error_out_of_reach() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error = |i: &usize| (800..850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter_map(filter_map)\n        .take_while(|i| i < &777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &777);\n    assert!(all_satisfies_whilst);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/from_xap_flat_map.rs",
    "content": "use orx_parallel::*;\n\nuse crate::map_while_ok_collect_arbitrary::utils::sort_if_ok;\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n    let expected = Ok((0..1024).flat_map(flat_map).collect::<Vec<_>>());\n\n    let result = sort_if_ok(result);\n    let expected = sort_if_ok(expected);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_whilst_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1024 + i, 2048 + i];\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .clone()\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .take_while(|i| i < &2777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &2777);\n    assert!(all_satisfies_whilst);\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_whilst_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .take_while(|i| i < &2777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        number < 2777 && is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_whilst_when_error_out_of_reach() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error = |i: &usize| (2800..2850).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result: Result<Vec<_>, _> = input\n        .into_par()\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(flat_map)\n        .take_while(|i| i < &2777)\n        .map(map_res)\n        .into_fallible_result()\n        .collect();\n\n    assert!(result.is_ok());\n    let result = result.unwrap();\n    let all_satisfies_whilst = result.iter().all(|x| x < &2777);\n    assert!(all_satisfies_whilst);\n}\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/mod.rs",
    "content": "mod from_map;\nmod from_par;\nmod from_xap_chain;\nmod from_xap_filter;\nmod from_xap_filter_map;\nmod from_xap_flat_map;\nmod utils;\n"
  },
  {
    "path": "tests/map_while_ok_collect_arbitrary/utils.rs",
    "content": "pub fn sort_if_ok<T: Ord + PartialOrd, E>(res_vec: Result<Vec<T>, E>) -> Result<Vec<T>, E> {\n    res_vec.map(|mut x| {\n        x.sort();\n        x\n    })\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/from_map.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_map_when_ok() {\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = (1..1025)\n        .into_par()\n        .map(|i| i - 1)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(Some((0..1024).sum::<usize>()));\n\n    assert_eq!(result, expected);\n\n    let result = (1..1)\n        .into_par()\n        .map(|i| i - 1)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(None);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_map_when_error() {\n    let input = 1..1025;\n    let map = |i: usize| i - 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .map(map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/from_par.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_par_when_ok() {\n    let input = 0..1024;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(Some((0..1024).sum::<usize>()));\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_par_when_error() {\n    let input = 0..1024;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/from_xap_chain.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_chain_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok((0..1024)\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .reduce(|a, b| a + b));\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_chain_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let filter = |i: &usize| i < &2000;\n    let map = |i: usize| 2 * i;\n    let filter_map = |i: usize| i.is_multiple_of(2).then_some(i);\n    let map2 = |i: usize| i / 2;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .clone()\n        .into_par()\n        .flat_map(flat_map)\n        .filter(filter)\n        .map(map)\n        .filter_map(filter_map)\n        .map(map2)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/from_xap_filter.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_filter_when_ok() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(Some((0..1024).filter(filter).sum::<usize>()));\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_when_ok_but_none() {\n    let input = 0..1024;\n    let filter = |i: &usize| i > &1024;\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(None);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_when_error() {\n    let input = 0..1024;\n    let filter = |i: &usize| i % 2 == 1;\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .filter(filter)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/from_xap_filter_map.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_ok() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(Some((0..1024).filter_map(filter_map).sum::<usize>()));\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_ok_but_none() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i > 1024).then_some(i);\n    let map_res = |i: usize| match (1300..1350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(None);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_filter_map_when_error() {\n    let input = 0..1024;\n    let filter_map = |i: usize| (i % 2 == 1).then_some(i);\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .filter_map(filter_map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/from_xap_flat_map.rs",
    "content": "use orx_parallel::*;\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_ok() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(Some((0..1024).flat_map(flat_map).sum()));\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_ok_but_none() {\n    let input = 0..1024;\n    let flat_map = |_: usize| [];\n    let map_res = |i: usize| match (11300..11350).contains(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n    let expected = Ok(None);\n\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn map_while_ok_from_xap_flat_map_when_error() {\n    let input = 0..1024;\n    let flat_map = |i: usize| [i, 1000 + i, 2000 + i];\n    let is_error =\n        |i: &usize| (300..350).contains(i) || (400..450).contains(i) || (500..550).contains(i);\n    let map_res = |i: usize| match is_error(&i) {\n        true => Err(i.to_string()),\n        false => Ok(i),\n    };\n\n    let result = input\n        .into_par()\n        .flat_map(flat_map)\n        .map(map_res)\n        .into_fallible_result()\n        .reduce(|a, b| a + b);\n\n    let result = result.map_err(|e| {\n        let number = e.parse::<usize>().unwrap();\n        is_error(&number)\n    });\n    assert_eq!(result, Err(true));\n}\n"
  },
  {
    "path": "tests/map_while_ok_reduce/mod.rs",
    "content": "mod from_map;\nmod from_par;\nmod from_xap_chain;\nmod from_xap_filter;\nmod from_xap_filter_map;\nmod from_xap_flat_map;\n"
  },
  {
    "path": "tests/mut_iter.rs",
    "content": "use orx_parallel::*;\nuse std::collections::HashMap;\nuse std::hint::black_box;\nuse test_case::test_matrix;\n\n#[cfg(miri)]\nconst N: [usize; 2] = [37, 125];\n#[cfg(not(miri))]\nconst N: [usize; 2] = [1025, 4735];\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]\nstruct Data {\n    name: String,\n    number: usize,\n}\n\nfn to_output(idx: usize) -> Data {\n    let name = idx.to_string();\n    let number = idx;\n    Data { name, number }\n}\n\nfn filter(data: &&mut Data) -> bool {\n    !data.name.starts_with('3')\n}\n\nfn update(data: &mut Data) {\n    for _ in 0..50 {\n        let increment = black_box(1);\n        data.number += increment\n    }\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn mut_iter(n: usize, nt: usize, chunk: usize) {\n    let input: HashMap<usize, Data> = (0..n).map(|i| (i, to_output(i))).collect();\n    let mut expected = input.clone();\n    expected.values_mut().filter(filter).for_each(update);\n    let expected = expected;\n\n    let mut input = input.clone();\n    input\n        .values_mut()\n        .iter_into_par()\n        .num_threads(nt)\n        .chunk_size(chunk)\n        .filter(filter)\n        .for_each(update);\n    assert_eq!(expected, input);\n}\n\n#[test_matrix(\n    [0, 1, N[0], N[1]],\n    [1, 4],\n    [1, 64])\n]\nfn mut_slice(n: usize, nt: usize, chunk: usize) {\n    let input: Vec<Data> = (0..n).map(to_output).collect();\n    let mut expected = input.clone();\n    expected.iter_mut().filter(filter).for_each(update);\n    let expected = expected;\n\n    let mut input = input.clone();\n    input\n        .par_mut()\n        .num_threads(nt)\n        .chunk_size(chunk)\n        .filter(filter)\n        .for_each(update);\n    assert_eq!(expected, input);\n}\n"
  },
  {
    "path": "tests/parallel_drainable.rs",
    "content": "use core::ops::Range;\nuse orx_parallel::*;\nuse test_case::test_matrix;\n\n#[derive(Clone, Debug)]\nstruct VecAndRange(Vec<String>, Range<usize>);\n\nimpl VecAndRange {\n    fn new(n: usize) -> VecAndRange {\n        let vec: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n        let range = match n % 4 {\n            0 => 0..n,\n            1 => 0..(n / 2),\n            2 => core::cmp::min(n.saturating_sub(1), 3)..n,\n            _ => {\n                let a = core::cmp::min(n.saturating_sub(1), 3);\n                let b = core::cmp::min(a + 10, n);\n                a..b\n            }\n        };\n        Self(vec, range)\n    }\n}\n\n#[test_matrix(\n    [0, 1, 2, 3, 71, 72, 73, 74],\n    [0, 1],\n    [0, 1]\n)]\nfn parallel_drainable_vec(n: usize, nt: usize, chunk: usize) {\n    let vec_and_range = VecAndRange::new(n);\n    let VecAndRange(mut vec, range) = vec_and_range;\n\n    let mut vec2 = vec.clone();\n    let drained: Vec<_> = vec2.drain(range.clone()).collect();\n    let expected = (vec2, drained);\n\n    let drained: Vec<_> = vec\n        .par_drain(range)\n        .num_threads(nt)\n        .chunk_size(chunk)\n        .collect();\n    let result = (vec, drained);\n\n    assert_eq!(result, expected);\n}\n"
  },
  {
    "path": "tests/parallelizable.rs",
    "content": "use orx_iterable::IntoCloningIterable;\nuse orx_parallel::Parallelizable;\n\nfn take_parallelizable<T>(a: impl Parallelizable<Item = T>) {\n    let _ = a.par();\n    let _ = a.par();\n}\n\n#[test]\nfn vec_parallelizable() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n    take_parallelizable::<&String>(&vec);\n}\n\n#[test]\nfn slice_parallelizable() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n    let slice = vec.as_slice();\n    take_parallelizable::<&String>(slice);\n}\n\n#[test]\nfn range_parallelizable() {\n    let range = 0..10;\n    take_parallelizable::<usize>(range);\n}\n\n#[test]\nfn cloning_iter_parallelizable() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n    let iter = vec.iter().filter(|x| x.as_str() != \"x\");\n    let cloning = iter.into_iterable();\n    take_parallelizable(cloning);\n}\n"
  },
  {
    "path": "tests/parallelizable_collection.rs",
    "content": "use orx_parallel::ParallelizableCollection;\n\nfn take_parallelizable_collection<T>(a: impl ParallelizableCollection<Item = T>) {\n    let _ = a.par();\n    let _ = a.par();\n}\n\n#[test]\nfn vec_parallelizable_collection() {\n    let vec: Vec<_> = (0..10).map(|x| x.to_string()).collect();\n    take_parallelizable_collection::<String>(vec);\n}\n"
  },
  {
    "path": "tests/test_groups.rs",
    "content": "mod map_while_ok_collect;\nmod map_while_ok_collect_arbitrary;\nmod map_while_ok_reduce;\nmod using;\nmod whilst;\n\npub fn fibonacci(n: u64) -> u64 {\n    let mut a = 0;\n    let mut b = 1;\n    for _ in 0..n {\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    a\n}\n"
  },
  {
    "path": "tests/trait_bounds.rs",
    "content": "use orx_fixed_vec::FixedVec;\nuse orx_split_vec::SplitVec;\nuse std::collections::VecDeque;\n\n#[test]\nfn trait_bounds_parallelizable() {\n    use orx_parallel::Parallelizable;\n    fn fun(source: impl Parallelizable) {\n        let _iter = source.par();\n    }\n\n    fun(vec![1, 2, 3].as_slice());\n    fun(&vec![1, 2, 3]);\n    fun(&VecDeque::<String>::new());\n    fun(0..9);\n    fun(&FixedVec::<usize>::new(3));\n    fun(&SplitVec::<usize>::new());\n}\n\n#[test]\nfn trait_bounds_parallelizable_collection() {\n    use orx_parallel::ParallelizableCollection;\n    fn fun(source: impl ParallelizableCollection) {\n        let _iter = source.par();\n    }\n\n    fun(vec![1, 2, 3]);\n    fun(VecDeque::<String>::new());\n    fun(FixedVec::<usize>::new(3));\n    fun(SplitVec::<usize>::new());\n}\n\n#[test]\nfn trait_bounds_into_par_iter() {\n    use orx_parallel::IntoParIter;\n    fn fun(source: impl IntoParIter) {\n        let _iter = source.into_par();\n    }\n\n    // owned\n    fun(vec![1, 2, 3]);\n    fun(VecDeque::<String>::new());\n    fun(FixedVec::<usize>::new(3));\n    fun(SplitVec::<usize>::new());\n\n    // ref\n    #[allow(clippy::needless_borrows_for_generic_args)]\n    {\n        fun(vec![1, 2, 3].as_slice());\n        fun(&vec![1, 2, 3]);\n        fun(&VecDeque::<String>::new());\n        fun(0..9);\n        fun(&FixedVec::<usize>::new(3));\n        fun(&SplitVec::<usize>::new());\n    }\n}\n"
  },
  {
    "path": "tests/using/mod.rs",
    "content": "mod rng;\n"
  },
  {
    "path": "tests/using/rng.rs",
    "content": "use orx_parallel::*;\nuse rand::{Rng, SeedableRng};\nuse rand_chacha::ChaCha20Rng;\n\nfn random_walk(rng: &mut impl Rng, position: i64, num_steps: usize) -> i64 {\n    (0..num_steps).fold(position, |p, _| random_step(rng, p))\n}\n\nfn random_step(rng: &mut impl Rng, position: i64) -> i64 {\n    match rng.random_bool(0.5) {\n        true => position + 1,  // to right\n        false => position - 1, // to left\n    }\n}\n\nfn input_positions() -> Vec<i64> {\n    (-50..=50).collect()\n}\n\n#[test]\nfn using_rng_map() {\n    let positions = input_positions();\n    let _ = positions.iter().sum::<i64>();\n\n    let final_positions: Vec<_> = positions\n        .par()\n        .copied()\n        .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64))\n        .map(|rng, position| random_walk(rng, position, 100))\n        .collect();\n    let _ = final_positions.iter().sum::<i64>();\n}\n\n#[test]\nfn using_rng_xap() {\n    let positions = input_positions();\n    let _ = positions.iter().sum::<i64>();\n\n    let final_positions: Vec<_> = positions\n        .par()\n        .copied()\n        .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64))\n        .filter(|rng, _| rng.random_bool(0.7))\n        .map(|rng, position| random_walk(rng, position, 100))\n        .collect();\n    let _ = final_positions.iter().sum::<i64>();\n}\n\n#[cfg(not(miri))]\n#[test]\nfn using_rng_xap_long() {\n    let positions = input_positions();\n    let _ = positions.iter().sum::<i64>();\n\n    let final_positions: Vec<_> = positions\n        .par()\n        .copied()\n        .using(|t_idx| ChaCha20Rng::seed_from_u64(42 * t_idx as u64))\n        .filter(|rng, _| rng.random_bool(0.7))\n        .filter_map(|rng, position| rng.random_bool(0.9).then_some(position))\n        .filter(|rng, _| rng.random_bool(0.7))\n        .flat_map(|_, position| [position, position])\n        .map(|rng, position| random_walk(rng, position, 100))\n        .collect();\n    let _ = final_positions.iter().sum::<i64>();\n}\n"
  },
  {
    "path": "tests/whilst/collect.rs",
    "content": "use crate::fibonacci;\nuse orx_parallel::*;\nuse std::hint::black_box;\nuse test_case::test_case;\n\n#[test_case(0, 0, 0, 0, \"0\")]\n#[test_case(512, 4, 0, 3, \"22\")]\n#[test_case(1024, 3, 0, 3, \"84\")]\n#[test_case(1024, 4, 1, 3, \"84\")]\n#[test_case(1024, 2, 0, 2, \"5\")]\nfn par(n: usize, nt: usize, c: usize, until_num_digits: usize, until_digits: &str) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            x.len() != until_num_digits || !x.starts_with(until_digits)\n        })\n        .collect();\n    let expected: Vec<_> = (0..n)\n        .map(|x| x.to_string())\n        .take_while(|x| x.len() != until_num_digits || !x.starts_with(until_digits))\n        .collect();\n\n    assert_eq!(output, expected);\n}\n\n#[test_case(0, 0, 0, 0, \"0\")]\n#[test_case(512, 4, 0, 3, \"82\")]\n#[test_case(1024, 3, 0, 3, \"84\")]\n#[test_case(1024, 4, 1, 3, \"84\")]\n#[test_case(1024, 2, 0, 2, \"8\")]\nfn map(n: usize, nt: usize, c: usize, until_num_digits: usize, until_digits: &str) {\n    let input = 0..n;\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .map(|x| x.to_string())\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            x.len() != until_num_digits || !x.starts_with(until_digits)\n        })\n        .collect();\n    let expected: Vec<_> = (0..n)\n        .map(|x| x.to_string())\n        .take_while(|x| x.len() != until_num_digits || !x.starts_with(until_digits))\n        .collect();\n\n    assert_eq!(output, expected);\n}\n\n#[test_case(512, 0, 0, &[\"55\"], &[\"55\"])]\n#[test_case(512, 4, 1, &[\"55\", \"222\"], &[\"55\"])]\n#[test_case(512, 3, 0, &[\"55\", \"222\"], &[\"55\"])]\n#[test_case(512, 5, 0, &[\"333\"], &[\"444\"])]\nfn xap_filter(n: usize, nt: usize, c: usize, stop_at: &[&str], filter_out: &[&str]) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .filter(|x| !filter_out.contains(&x.as_str()))\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            !stop_at.contains(&x.as_str())\n        })\n        .collect();\n    let expected: Vec<_> = (0..n)\n        .map(|x| x.to_string())\n        .filter(|x| !filter_out.contains(&x.as_str()))\n        .take_while(|x| !stop_at.contains(&x.as_str()))\n        .collect();\n\n    assert_eq!(output, expected);\n}\n\n#[test_case(512, 0, 0, &[\"55\"], &[\"55\"])]\n#[test_case(512, 4, 1, &[\"55\", \"222\"], &[\"55\"])]\n#[test_case(512, 3, 0, &[\"55\", \"222\"], &[\"55\"])]\n#[test_case(512, 5, 0, &[\"333\"], &[\"444\"])]\nfn xap_filter_map(n: usize, nt: usize, c: usize, stop_at: &[&str], filter_out: &[&str]) {\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .filter_map(|x| (!filter_out.contains(&x.as_str())).then_some(x))\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            !stop_at.contains(&x.as_str())\n        })\n        .collect();\n    let expected: Vec<_> = (0..n)\n        .map(|x| x.to_string())\n        .filter_map(|x| (!filter_out.contains(&x.as_str())).then_some(x))\n        .take_while(|x| !stop_at.contains(&x.as_str()))\n        .collect();\n\n    assert_eq!(output, expected);\n}\n\n#[test_case(1024, 0, 0, &[555], None)]\n#[test_case(1024, 4, 0, &[555], Some(\"!\"))]\n#[test_case(1024, 3, 0, &[555], Some(\"?\"))]\n#[test_case(1024, 3, 0, &[554,555,556,557,558,559], Some(\"?\"))]\nfn xap_flat_map(n: usize, nt: usize, c: usize, stop_at: &[usize], stop_at_char: Option<&str>) {\n    let input = 0..n;\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .flat_map(|i| [i.to_string(), format!(\"{i}!\"), format!(\"{i}?\")])\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            let s = match x.ends_with(\"!\") || x.ends_with(\"?\") {\n                true => &x[0..(x.len() - 1)],\n                false => x.as_str(),\n            };\n            let num: usize = s.parse().unwrap();\n            !stop_at.contains(&num)\n                || stop_at_char\n                    .map(|stop_at_char| !x.ends_with(stop_at_char))\n                    .unwrap_or(false)\n        })\n        .collect();\n    let expected: Vec<_> = (0..n)\n        .flat_map(|i| [i.to_string(), format!(\"{i}!\"), format!(\"{i}?\")])\n        .take_while(|x| {\n            let s = match x.ends_with(\"!\") || x.ends_with(\"?\") {\n                true => &x[0..(x.len() - 1)],\n                false => x.as_str(),\n            };\n            let num: usize = s.parse().unwrap();\n            !stop_at.contains(&num)\n                || stop_at_char\n                    .map(|stop_at_char| !x.ends_with(stop_at_char))\n                    .unwrap_or(false)\n        })\n        .collect();\n\n    assert_eq!(output, expected);\n}\n"
  },
  {
    "path": "tests/whilst/collect_arbitrary.rs",
    "content": "use crate::fibonacci;\nuse orx_parallel::*;\nuse std::hint::black_box;\nuse test_case::test_case;\n\n#[test_case(512, 4, 0, 3, \"22\", 220)]\n#[test_case(1024, 3, 0, 3, \"84\", 840)]\n#[test_case(1024, 4, 1, 3, \"84\", 840)]\n#[test_case(1024, 2, 0, 2, \"5\", 50)]\nfn par(n: usize, nt: usize, c: usize, until_num_digits: usize, until_digits: &str, min_len: usize) {\n    let whilst = |x: &String| x.len() != until_num_digits || !x.starts_with(until_digits);\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .iteration_order(IterationOrder::Arbitrary)\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            whilst(x)\n        })\n        .collect();\n\n    assert!(output.len() >= min_len);\n\n    assert!(output.iter().all(whilst));\n}\n\n#[test_case(512, 4, 0, 3, \"32\", 320)]\n#[test_case(1024, 3, 0, 3, \"84\", 840)]\n#[test_case(1024, 4, 1, 3, \"84\", 840)]\n#[test_case(1024, 2, 0, 2, \"8\", 80)]\nfn map(n: usize, nt: usize, c: usize, until_num_digits: usize, until_digits: &str, min_len: usize) {\n    let whilst = |x: &String| x.len() != until_num_digits || !x.starts_with(until_digits);\n\n    let input = 0..n;\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .iteration_order(IterationOrder::Arbitrary)\n        .map(|x| x.to_string())\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            whilst(x)\n        })\n        .collect();\n\n    assert!(output.len() >= min_len);\n\n    assert!(output.iter().all(whilst));\n}\n\n#[test_case(512, 0, 0, &[\"55\"], &[\"55\"], 511)]\n#[test_case(512, 4, 1, &[\"55\", \"222\"], &[\"55\"], 221)]\n#[test_case(512, 3, 0, &[\"55\", \"222\"], &[\"55\"], 221)]\n#[test_case(512, 5, 0, &[\"333\"], &[\"444\"], 333)]\nfn xap_filter(\n    n: usize,\n    nt: usize,\n    c: usize,\n    stop_at: &[&str],\n    filter_out: &[&str],\n    min_len: usize,\n) {\n    let whilst = |x: &String| !stop_at.contains(&x.as_str());\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter(|x| !filter_out.contains(&x.as_str()))\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            whilst(x)\n        })\n        .collect();\n\n    assert!(output.len() >= min_len);\n\n    assert!(output.iter().all(whilst));\n}\n\n#[test_case(512, 0, 0, &[\"55\"], &[\"55\"], 511)]\n#[test_case(512, 4, 1, &[\"55\", \"222\"], &[\"55\"], 221)]\n#[test_case(512, 3, 0, &[\"55\", \"222\"], &[\"55\"], 221)]\n#[test_case(512, 5, 0, &[\"333\"], &[\"444\"], 333)]\nfn xap_filter_map(\n    n: usize,\n    nt: usize,\n    c: usize,\n    stop_at: &[&str],\n    filter_out: &[&str],\n    min_len: usize,\n) {\n    let whilst = |x: &String| !stop_at.contains(&x.as_str());\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .iteration_order(IterationOrder::Arbitrary)\n        .filter_map(|x| (!filter_out.contains(&x.as_str())).then_some(x))\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            whilst(x)\n        })\n        .collect();\n\n    assert!(output.len() >= min_len);\n\n    assert!(output.iter().all(whilst));\n}\n\n#[test_case(1024, 0, 0, &[555], None, 555*3)]\n#[test_case(1024, 4, 0, &[555], Some(\"!\"), 555*3+1)]\n#[test_case(1024, 3, 0, &[555], Some(\"?\"), 555*3+2)]\n#[test_case(1024, 3, 0, &[554,555,556,557,558,559], Some(\"?\"), 554*3)]\nfn xap_flat_map(\n    n: usize,\n    nt: usize,\n    c: usize,\n    stop_at: &[usize],\n    stop_at_char: Option<&str>,\n    min_len: usize,\n) {\n    let whilst = |x: &String| {\n        let s = match x.ends_with(\"!\") || x.ends_with(\"?\") {\n            true => &x[0..(x.len() - 1)],\n            false => x.as_str(),\n        };\n        let num: usize = s.parse().unwrap();\n        !stop_at.contains(&num)\n            || stop_at_char\n                .map(|stop_at_char| !x.ends_with(stop_at_char))\n                .unwrap_or(false)\n    };\n\n    let input = 0..n;\n    let output: Vec<_> = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .iteration_order(IterationOrder::Arbitrary)\n        .flat_map(|i| [i.to_string(), format!(\"{i}!\"), format!(\"{i}?\")])\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            whilst(x)\n        })\n        .collect();\n\n    assert!(output.len() >= min_len);\n\n    assert!(output.iter().all(whilst));\n}\n"
  },
  {
    "path": "tests/whilst/find.rs",
    "content": "use crate::fibonacci;\nuse orx_parallel::*;\nuse std::hint::black_box;\nuse test_case::test_case;\n\n#[test_case(511, 0, 0, &[333], &[333], None)]\n#[test_case(511, 0, 0, &[333], &[332], Some(332))]\n#[test_case(511, 0, 0, &[222, 333], &[223, 224, 225, 332], None)]\n#[test_case(511, 0, 0, &[171], &[172], None)]\nfn par(n: usize, nt: usize, c: usize, stop_at: &[usize], find: &[usize], expected: Option<usize>) {\n    let filter = |x: &String| find.contains(&x.parse().unwrap());\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            let num: usize = x.parse().unwrap();\n            !stop_at.contains(&num)\n        })\n        .find(filter)\n        .map(|x| x.parse().unwrap());\n\n    assert_eq!(output, expected);\n}\n\n#[test_case(511, 0, 0, &[333], &[334], Some(334))]\n#[test_case(511, 0, 0, &[334], &[332], Some(332))]\n#[test_case(511, 0, 0, &[222, 333], &[223, 224, 225, 332], None)]\n#[test_case(511, 0, 0, &[170], &[172], None)]\nfn filter(\n    n: usize,\n    nt: usize,\n    c: usize,\n    stop_at: &[usize],\n    find: &[usize],\n    expected: Option<usize>,\n) {\n    let filter = |x: &String| find.contains(&x.parse().unwrap());\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .filter(|x| x.parse::<usize>().unwrap() % 2 == 0) // only evens remain\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            let num: usize = x.parse().unwrap();\n            !stop_at.contains(&num)\n        })\n        .find(filter)\n        .map(|x| x.parse().unwrap());\n\n    assert_eq!(output, expected);\n}\n\n#[test_case(511, 0, 0, &[\"333!\"], &[333], Some(\"333\".to_string()))]\n#[test_case(511, 0, 0, &[\"334?\"], &[332], Some(\"332\".to_string()))]\n#[test_case(511, 0, 0, &[\"222!\",\"333\"], &[223, 224, 225, 332], None)]\n#[test_case(511, 0, 0, &[\"170!\"], &[170], Some(\"170\".to_string()))]\nfn flat_map(\n    n: usize,\n    nt: usize,\n    c: usize,\n    stop_at: &[&str],\n    find: &[usize],\n    expected: Option<String>,\n) {\n    let filter = |x: &String| {\n        let s = match x.ends_with(\"!\") || x.ends_with(\"?\") {\n            true => &x[0..(x.len() - 1)],\n            false => x.as_str(),\n        };\n        let num: usize = s.parse().unwrap();\n        find.contains(&num)\n    };\n\n    let input: Vec<_> = (0..n).map(|x| x.to_string()).collect();\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .flat_map(|i| [i.to_string(), format!(\"{i}!\"), format!(\"{i}?\")])\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            !stop_at.contains(&x.as_str())\n        })\n        .find(filter)\n        .map(|x| x.parse().unwrap());\n\n    assert_eq!(output, expected);\n}\n"
  },
  {
    "path": "tests/whilst/mod.rs",
    "content": "mod collect;\nmod collect_arbitrary;\nmod find;\nmod reduce;\n"
  },
  {
    "path": "tests/whilst/reduce.rs",
    "content": "use crate::fibonacci;\nuse orx_parallel::*;\nuse std::hint::black_box;\nuse test_case::test_case;\n\n#[test_case(511, 0, 0, 333, 332*331/2)]\n#[test_case(511, 0, 0, 1000, 510*509/2)]\n#[test_case(511, 0, 0, 222, 221*220/2)]\n#[test_case(511, 0, 0, 171, 170*169/2)]\nfn par(n: usize, nt: usize, c: usize, stop_at: usize, expected_min: usize) {\n    let input = 0..n;\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            *x != stop_at\n        })\n        .reduce(|x, y| x + y);\n\n    assert!(output.unwrap() >= expected_min);\n}\n\n#[test_case(511, 0, 0, 333, 332*331/2)]\n#[test_case(511, 0, 0, 1000, 510*509/2)]\n#[test_case(511, 0, 0, 222, 221*220/2)]\n#[test_case(511, 0, 0, 171, 170*169/2)]\nfn www_map(n: usize, nt: usize, c: usize, stop_at: usize, expected_min: usize) {\n    let input = 0..n;\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .map(|x| x.to_string())\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            let x: usize = x.parse().unwrap();\n            x != stop_at\n        })\n        .map(|x| x.parse::<usize>().unwrap())\n        .reduce(|x, y| x + y);\n\n    assert!(output.unwrap() >= expected_min);\n}\n\n#[test_case(511, 0, 0, 333, 332*331/2)]\n#[test_case(511, 0, 0, 1000, 510*509/2)]\n#[test_case(511, 0, 0, 222, 221*220/2)]\n#[test_case(511, 0, 0, 171, 170*169/2)]\nfn filter(n: usize, nt: usize, c: usize, stop_at: usize, expected_min: usize) {\n    let input = 0..n;\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .filter(|x| x != &42)\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            *x != stop_at\n        })\n        .reduce(|x, y| x + y);\n\n    assert!(output.unwrap() >= expected_min - 42);\n}\n\n#[test_case(511, 0, 0, 333, 332*331/2)]\n#[test_case(511, 0, 0, 1000, 510*509/2)]\n#[test_case(511, 0, 0, 222, 221*220/2)]\n#[test_case(511, 0, 0, 171, 170*169/2)]\nfn flatmap(n: usize, nt: usize, c: usize, stop_at: usize, expected_min: usize) {\n    let input = 0..n;\n    let output = input\n        .into_par()\n        .num_threads(nt)\n        .chunk_size(c)\n        .flat_map(|x| [x, x, x])\n        .take_while(|x| {\n            let _fib = black_box(fibonacci(42));\n            *x != stop_at\n        })\n        .reduce(|x, y| x + y);\n\n    assert!(output.unwrap() >= expected_min * 3);\n}\n"
  }
]