diff --git a/Cargo.lock b/Cargo.lock index 1f7db66af420..604c5535f3b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -584,7 +584,7 @@ dependencies = [ "bitflags 2.10.0", "cexpr", "clang-sys", - "itertools 0.14.0", + "itertools 0.14.999", "proc-macro2", "quote", "regex", @@ -3976,14 +3976,21 @@ dependencies = [ name = "itertools" version = "0.13.0" dependencies = [ - "itertools 0.14.0", + "itertools 0.14.999", ] [[package]] name = "itertools" -version = "0.14.0" +version = "0.14.999" +dependencies = [ + "itertools 0.15.0", +] + +[[package]] +name = "itertools" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" dependencies = [ "either", ] @@ -4928,7 +4935,7 @@ dependencies = [ "futures", "getrandom 0.2.999", "hex", - "itertools 0.14.0", + "itertools 0.14.999", "maybe-async", "mls-rs-codec", "mls-rs-core", @@ -4950,7 +4957,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bd834f164dc06c1fed805540ae307a460b7ed7c2769a35a376f1de577a0dc1" dependencies = [ - "itertools 0.14.0", + "itertools 0.14.999", "mls-rs-codec-derive", "thiserror 2.0.12", "wasm-bindgen", @@ -5228,7 +5235,7 @@ dependencies = [ "icu_properties", "idna", "indexmap", - "itertools 0.14.0", + "itertools 0.15.0", "libc", "log", "memchr", @@ -5590,7 +5597,7 @@ dependencies = [ "glob", "heck", "icu_segmenter", - "itertools 0.14.0", + "itertools 0.14.999", "lazy_static", "mozilla-central-workspace-hack", "regex", @@ -6548,7 +6555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.14.999", "proc-macro2", "quote", "syn", @@ -7727,7 +7734,7 @@ dependencies = [ "gecko-profiler", "icu_segmenter", "indexmap", - "itertools 0.14.0", + "itertools 0.14.999", "itoa", "log", "malloc_size_of", @@ -7823,7 +7830,7 @@ dependencies = [ "icu_normalizer", "icu_properties", "interrupt-support", - "itertools 0.14.0", + "itertools 0.14.999", "once_cell", "parking_lot", "rc_crypto", diff --git a/Cargo.toml b/Cargo.toml index 14efb7c37859..2efb78636dca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -266,8 +266,11 @@ base64_21 = { package = "base64", path = "build/rust/base64" } # Patch wasi 0.11 to 0.14 wasi_0_11 = { package = "wasi", path = "build/rust/wasi" } -# Patch itertools 0.13 to 0.14 -itertools = { path = "build/rust/itertools" } +# Patch itertools 0.13 to 0.15 +itertools_0_13 = { package = "itertools", path = "build/rust/itertools-0.13" } + +# Patch itertools 0.14 to 0.15 +itertools_0_14 = { package = "itertools", path = "build/rust/itertools" } # tokio 0.29.0 includes an experimental "tracing" feature which requires # backtrace ^0.3.58 and the `tokio_unstable` flag. We don't use it, and nothing diff --git a/build/rust/itertools-0.13/Cargo.toml b/build/rust/itertools-0.13/Cargo.toml new file mode 100644 index 000000000000..660683f427c6 --- /dev/null +++ b/build/rust/itertools-0.13/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "itertools" +version = "0.13.0" +edition = "2018" +license = "MPL2.0" + +[lib] +path = "lib.rs" + +[dependencies.itertools] +version = "0.14" diff --git a/build/rust/itertools-0.13/lib.rs b/build/rust/itertools-0.13/lib.rs new file mode 100644 index 000000000000..dcd8116971b0 --- /dev/null +++ b/build/rust/itertools-0.13/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use itertools::*; diff --git a/build/rust/itertools/Cargo.toml b/build/rust/itertools/Cargo.toml index 660683f427c6..cb391d5b7250 100644 --- a/build/rust/itertools/Cargo.toml +++ b/build/rust/itertools/Cargo.toml @@ -1,11 +1,17 @@ [package] name = "itertools" -version = "0.13.0" +version = "0.14.999" edition = "2018" license = "MPL2.0" [lib] path = "lib.rs" +[features] +default = ["itertools/default"] +use_alloc = ["itertools/use_alloc"] +use_std = ["itertools/use_std"] + [dependencies.itertools] -version = "0.14" +version = "0.15" +default-features = false diff --git a/build/workspace-hack/Cargo.toml b/build/workspace-hack/Cargo.toml index 2d9e3ba7ac23..3bc8d6f5e38b 100644 --- a/build/workspace-hack/Cargo.toml +++ b/build/workspace-hack/Cargo.toml @@ -87,7 +87,7 @@ scopeguard = { version = "1", optional = true } [build-dependencies] bindgen = { version = "0.69", default-features = false, features = ["runtime"], optional = true } cc = { version = "1.0", features = ["parallel"], optional = true } -itertools = { version = "0.14", default-features = false, features = ["use_alloc"], optional = true } +itertools = { version = "0.15", default-features = false, features = ["use_alloc"], optional = true } libc = "0.2" log = { version = "0.4", features = ["std"], optional = true } memchr = { version = "2", optional = true } diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index a719af603ce7..9e11b88cd169 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -4105,6 +4105,11 @@ who = "Mike Hommey " criteria = "safe-to-deploy" delta = "0.10.3 -> 0.10.5" +[[audits.itertools]] +who = "Erich Gubler " +criteria = "safe-to-deploy" +delta = "0.14.0 -> 0.15.0" + [[audits.itoa]] who = "Mike Hommey " criteria = "safe-to-deploy" diff --git a/third_party/rust/itertools/.cargo-checksum.json b/third_party/rust/itertools/.cargo-checksum.json index e065c77cc467..860e3b32b197 100644 --- a/third_party/rust/itertools/.cargo-checksum.json +++ b/third_party/rust/itertools/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".cargo_vcs_info.json":"c44891b3a83326c2d0434099194ceee3d75eb1f850a58f611b1c85a788938512",".codecov.yml":"27b445dc39fefbcb3c232623d6ce77ec15133d3fad6bde481b8d140614993b2a",".github/dependabot.yml":"7ae793ed2cfbb3d571f46e4c6ed9cfd374af472c44d38d7e9be82e91fccafcd4",".github/workflows/ci.yml":"c38c00e4e8b428fce92cfad22c26f9ff8dc99cb9045380071ba8bc759a7ec16e",".github/workflows/coverage.yml":"6dfc476a71ffa247ff4a79dfb2e51afc927ea644f5c781afaf5c3cd03b552537","CHANGELOG.md":"60ec9a1801e015e49f7fbb299b608ac730d5b1a3fb298e6cf7935c0695ddf7fe","CONTRIBUTING.md":"d5787d0fd4df15481e2e09a37234ac5dec22c007c890826991f633d890efa29e","Cargo.lock":"4422e732d4ce6f650afb53a1dcffb1e53c86dd066c3dcd66bc9620acd898b99e","Cargo.toml":"77735549383196a4156a2246dd1cd6742029b223679b3004531456d33562b0ce","Cargo.toml.orig":"1fb9c3c002924032d84c3a39dddfeb171724c413c1d5215d7a720598eb922a58","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"7dba3f55ea54eff2606f8b9f005e369cf9885dd972cb481432fce00234ee7750","benches/bench1.rs":"d632c8b839d7b318d1cb7b81b9c62570c77dcdf0696b8ce3d52067c79c930f78","benches/combinations.rs":"5b3bd243336d6b6bdc111d66218f3f0a4ecdb10fb72e90db79959e3d8bb2cf6f","benches/combinations_with_replacement.rs":"11f29160652a2d90ce7ca4b1c339c4457888ab6867e2456ce1c62e3adf9be737","benches/fold_specialization.rs":"66ab13fd8576a662afb59ef72c5565f5c3d27f7f30a976450ee5a14958654fa2","benches/k_smallest.rs":"c1bb2aa597def7f7c282d1196f9d70be6d10e1acbae03279c05bc8065544bb8e","benches/powerset.rs":"dc1fd729584147e5d8e4d19c6ca6f8706087d41c3c5beb7293d9ea43b4beab14","benches/specializations.rs":"daa989877d83ccd58e8de529184d50905b3d6fa60a9eeae917f38bd570d72fa4","benches/tree_reduce.rs":"fa4f22f042b76df89094ddf6e925ba42c4c3992f8195e719ed035f2e7cfa05bd","benches/tuple_combinations.rs":"16366158743307a0289fc1df423a3cec45009807d410a9fe9922d5b6f8b7d002","benches/tuples.rs":"5ab542aca40df4390de0ebf3819665df402d924a7dd6f4280e6ffc942bbd25c4","examples/iris.data":"596ffd580471ca4d4880f8e439c7281f3b50d8249a5960353cb200b1490f63a0","examples/iris.rs":"42c1b2fc148df52a050b013a57b577ad19911f1fe85b9525863df501979b5cd1","src/adaptors/coalesce.rs":"b57157c205ae077dd398740b61c7f49023aa80868abd8a071a6fe89ae6ecc9ad","src/adaptors/map.rs":"4952ee770cb54e98b2f649efd9c98f18951689358eb9b6bee10f139d056353ae","src/adaptors/mod.rs":"1e0cf7409c7291a923cf87f1c6d27cc57bd9f71ca52f7dd08a429aa994daa6ce","src/adaptors/multi_product.rs":"ad501e8ae4e5089b9d2f2be1f9a4713da6a2103b14daa759e09918409f88e321","src/combinations.rs":"9c4490bc4c7488fe9a8dba656a30493d90abb33006f7abbe3e266c237ffc986b","src/combinations_with_replacement.rs":"c7d6b7a122057e9aab075b2de41440ccd2973a6985fba75c2e93af13de55ef90","src/concat_impl.rs":"d61c00d43eca1193f135e25d3b6afd840c02ef1c573c29b264c47ee3429a45e8","src/cons_tuples_impl.rs":"7f46da33168107860b2b15d05d8edfe618e41bbc66ff0e16baf82d7373c4356d","src/diff.rs":"6e5ba3705a3a076d4fc360594014c90f1dfc597e61e8a629f96efa050e2433f5","src/duplicates_impl.rs":"1be37249b4566edc8da611ed9766ec851a526e7513bd13d80fe97482dcfcf7f3","src/either_or_both.rs":"cac278666b5d3c1fd103d97d15ce4c40960ea459441aeae83c6502087fd2ad8d","src/exactly_one_err.rs":"90b6204551161d27394af72107765dbfe3b51a77f4770c2e506fa4938985a184","src/extrema_set.rs":"11de200d853941716e9aa9a9b520b006704827c3c43a0c5f067906b0941e51d1","src/flatten_ok.rs":"62c18e5221a27949a00de49414306d6dfd601515817c1c8ae6189e3275756dd3","src/format.rs":"3ae6414043e0040f7358028c560437ea49afdbb2416df138a2410169e2619589","src/free.rs":"00ec21acee2ae2b30bf99e62472f9684c0a1719fbafc8dd2e4195ea8377c5b5d","src/group_map.rs":"c9da201137c6bb479b9308bfc38398b76950e39905f4ce8bc435c5318371522c","src/groupbylazy.rs":"5862629719258703aad47977ba1060f20fff15e962e18e6142758ebf6cd4a61c","src/grouping_map.rs":"3896c46ba4bd8ea886e5344a245658235626a104758d5ccecf223544a9ba471b","src/impl_macros.rs":"97fc5f39574805e0c220aa462cf1ae7dcac5c1082d6ee5500e7d71c120db5f88","src/intersperse.rs":"55031819e985c3184275e254c9600ecbe01e9fb49f198039c5da82a87ea5b90e","src/iter_index.rs":"1b0ff8376a4ad855d44db8c662450c777db84e0f4997b53ca575c65b107bb83b","src/k_smallest.rs":"a6840980e4c1aedd6987f93c904d362aa09a101537e447121fff58bb2473638d","src/kmerge_impl.rs":"3f999d55d7def904f71f2ca88b36707461f7f23b32966e0ccaf31d808886d843","src/lazy_buffer.rs":"baa01490fceb5a8dd7bd9c2634e19ce8a785bd1df352a9dd77d1344e3e0f8892","src/lib.rs":"e7f144351cca5018dc12270b4c33f0562afddb92452acfa85153cb276aebd6e9","src/merge_join.rs":"f2f257e63c84ed772b235229cc787ebe9ae009d7c80ed2087002a6b62c5e2133","src/minmax.rs":"0ec34b172ca8efc4aacb96f3e5771bdc5e8ac882876ee0f59d698c3924717c48","src/multipeek_impl.rs":"79eef0be49ad66f15d41808e72c03976c4f7cff5838b69d17975d3ece266f3f8","src/next_array.rs":"295924058891c08f9fe6313a1d9dd0042dcf60f0a514c6a6e009a1396d804fc9","src/pad_tail.rs":"e6bb5b086478600b0dbb8726cae8364bf83ab36d989ef467e1264eea43933b50","src/peek_nth.rs":"093f1a157b1c917f041af5244a5a46311affa2922126e36dc0ee2c501c79b58c","src/peeking_take_while.rs":"075ce13475c84e2cfdfaf1a7a0d0695332102c82a61914ed4c00a7d2634b1d34","src/permutations.rs":"b316084ee14e9e138d22f177367b3bfa24cb3e5e90ab20b9b00a9a23d653496f","src/powerset.rs":"7ab24fefc914b339dd92a6c8e639d0cad34479e09293b3346078856d6bc02d34","src/process_results_impl.rs":"6b5d82447eef4e87fef7b2a8e56b906ac7b000886a468ce421252f34ec86e371","src/put_back_n_impl.rs":"5a58d7a31c03029f0726e4d42de3be869580cf76b73c6d1ef70dd40c240b03a0","src/rciter_impl.rs":"081fd206ba4a601bd65e2f3b8d7c95e3e4a3564beb7c98944bd2e7986959c230","src/repeatn.rs":"dd9a5bf5a63ef9cc6ec5c8a6137c7ffba80f13568b6d001e189daaa29ffbaf39","src/size_hint.rs":"6022c2327ddc6df7e7b939eb60a93ee66ea9aa4d3aab49b9952e663ff4bff10b","src/sources.rs":"ef942af209ca1effcd28a95abedad8c45b659ae2a15b66c2158cb604f6e325f8","src/take_while_inclusive.rs":"1973a9f5322b3dae3b5ccded5912a08a8e2e975b9a5eac666192b118b230d305","src/tee.rs":"dad50ca162627cf0a67786f0993ef27d06cdefc14d412463e58c07824ef409d8","src/tuple_impl.rs":"0213261109e7c65746ccc22425d19141907bf7ea1e3dd4c40e9f278e6148e272","src/unique_impl.rs":"1efc280226f13ddd7dd5f7eedeec0093b704596652c942f3a0b2f8c90fa2e2f7","src/unziptuple.rs":"f3f6a2ee2658fa07db7592f2c344c2e3b1263a21fc75e1325f2be32c9dc1e750","src/with_position.rs":"9ca1eb195d04690b0c3a62a6c0eea349b8042e11c4ca4b80744f54103e1c7355","src/zip_eq_impl.rs":"3282b177e7dece5d3fbdc9b03563f209589a399ea45e70abf23ccca3b5512ac7","src/zip_longest.rs":"5572699564dd5717cc074b7733333ed238c2e9f3e6819d45e33e3a2dbda74478","src/ziptuple.rs":"d3a12221d39c8a5514574adb3ad2ccd1803d514b1cb09fbcd9253e3ddd628310","tests/adaptors_no_collect.rs":"7e6240878b1fc13b6384fdde0317d5d7ccca3e417b10a201ba61eb5255400fda","tests/flatten_ok.rs":"b7894874132918b8229c7150b2637511d8e3e14197d8eeb9382d46b2a514efa2","tests/laziness.rs":"89e6caec10da3d7aeadf9e30d5caf03cda36d07cee8415ff134b5b8e2a2cf144","tests/macros_hygiene.rs":"c2d517badf593c0ba9b70e987a6f8482ed8997547b2e88bbec70babd9b677aa2","tests/merge_join.rs":"5fb506b989f4a331d46cdec5775ea594656985134196099eaf8d3905bdddcdd5","tests/peeking_take_while.rs":"f834361c5520dda15eb9e9ebe87507c905462201412b21859d9f83dab91d0e0b","tests/quick.rs":"d463bf8712b32742c93bc2cf3993031aeaba1f5b0505ca0ecd347313c3da0582","tests/specializations.rs":"fefbdac83bb774186882e3d31be619c9ce1dbfc4191a99ed2ac90aa764737a8f","tests/test_core.rs":"9bbc6772e97a60d93d4021c184b9e4de1c0440a1c48b991a92edc189699fd20d","tests/test_std.rs":"b0e56deefe309b9c11804bd069c744b5caea7960cd4b68244531f6edf38b9741","tests/tuples.rs":"014e4da776174bfe923270e2a359cd9c95b372fce4b952b8138909d6e2c52762","tests/zip.rs":"457e34761d9bf2943a43abd9020d2b1a4492ebff9e4d94efe4c730652fbf62af"},"package":"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"} \ No newline at end of file +{"files":{".cargo_vcs_info.json":"4392e2c0996dbbdfdc3aaf5a8f7173a58c1e72a118ed89e31c4585c8df5da1de",".codecov.yml":"27b445dc39fefbcb3c232623d6ce77ec15133d3fad6bde481b8d140614993b2a",".github/dependabot.yml":"7ae793ed2cfbb3d571f46e4c6ed9cfd374af472c44d38d7e9be82e91fccafcd4",".github/workflows/ci.yml":"c38c00e4e8b428fce92cfad22c26f9ff8dc99cb9045380071ba8bc759a7ec16e",".github/workflows/coverage.yml":"6dfc476a71ffa247ff4a79dfb2e51afc927ea644f5c781afaf5c3cd03b552537","CHANGELOG.md":"26b83b8f6206e5fa67139ac1b8e8b803f34ead29cdd8ff9c449f38b166ad1bf2","CONTRIBUTING.md":"d5787d0fd4df15481e2e09a37234ac5dec22c007c890826991f633d890efa29e","Cargo.lock":"1c5a169dc68a4c74a5126754e1b18f31e5097a17f993856730cadef2e2a7a9c5","Cargo.toml":"62dea4c41dff0c454c3198715885ca13ae6cdf1a5d3b5a5ec68ef42750ccbaf2","Cargo.toml.orig":"974a5d0983829082ef3219c52db21e8e12374e9d64996561736bf0f5bafc9bd2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"b05ce16c04a2e8ad346540e4c3b2ffa5c6b6795797ebc27adfeca8c0f5a1f969","benches/bench1.rs":"d632c8b839d7b318d1cb7b81b9c62570c77dcdf0696b8ce3d52067c79c930f78","benches/combinations.rs":"5b3bd243336d6b6bdc111d66218f3f0a4ecdb10fb72e90db79959e3d8bb2cf6f","benches/combinations_with_replacement.rs":"0a83451abefad1b14c02effceaf2b13c4b56cc763816bff29c8cd481c40b0a56","benches/fold_specialization.rs":"66ab13fd8576a662afb59ef72c5565f5c3d27f7f30a976450ee5a14958654fa2","benches/k_smallest.rs":"c1bb2aa597def7f7c282d1196f9d70be6d10e1acbae03279c05bc8065544bb8e","benches/powerset.rs":"20cd76d5fc4817f1d3a14068aca82315cfd2c02aeeaf0e6288ef72ab12b033cd","benches/specializations.rs":"f35d04a56ed51a36bbad2674a7b296061cf77d9e22e698e5fc985a89e3af65c9","benches/tree_reduce.rs":"b7e56a6def9b7fa93c90dbfa2938d2df6c85fb837d32c6bb4d657cd659482ace","benches/tuple_combinations.rs":"9e255700b0a8afc38131026e43c7367db843363f29463ede3e0b3671aa87bdf7","benches/tuples.rs":"5ab542aca40df4390de0ebf3819665df402d924a7dd6f4280e6ffc942bbd25c4","examples/iris.data":"596ffd580471ca4d4880f8e439c7281f3b50d8249a5960353cb200b1490f63a0","examples/iris.rs":"a9e1c771e5d75defa285c7e7dc32f4fed74d81c104ba054427bc59ef38d99dc8","src/adaptors/coalesce.rs":"b9ddc210df82073e70dd41436eb84b207c1ef1c82cdefffb14be73299b3f6b17","src/adaptors/map.rs":"4952ee770cb54e98b2f649efd9c98f18951689358eb9b6bee10f139d056353ae","src/adaptors/mod.rs":"1a031acb216c34489475e841622181c6c54521a76a3f9280312cceac897dbbf0","src/adaptors/multi_product.rs":"ad501e8ae4e5089b9d2f2be1f9a4713da6a2103b14daa759e09918409f88e321","src/all_equal_value_err.rs":"0cc6f2215012087e15b07edc390b7939daaaaa06fe26e84614e6ebe3beb1274c","src/array_impl.rs":"4eb99b5385e3f3b68f134c5d6073485b8d6558544ab2067a19b2789de3939d3c","src/combinations.rs":"9b2d1d92b0b049ae655d6b2b271d4edcb7af05c1fb44fecdd71ff0be2c0120dd","src/combinations_with_replacement.rs":"bfe41c0fcd1512ab581a3e7521e3b417b311d29b037dc63aed41d3262af60fcb","src/concat_impl.rs":"d61c00d43eca1193f135e25d3b6afd840c02ef1c573c29b264c47ee3429a45e8","src/cons_tuples_impl.rs":"7f46da33168107860b2b15d05d8edfe618e41bbc66ff0e16baf82d7373c4356d","src/diff.rs":"6e5ba3705a3a076d4fc360594014c90f1dfc597e61e8a629f96efa050e2433f5","src/duplicates_impl.rs":"a8ee2930e0d5825e4efd2a200e825a330925d177b79232b5d14eb0519ded6d9c","src/either_or_both.rs":"8b3c54326d748106ec91a6a882da2750e3049ab759646914475ffa44ed4e9301","src/exactly_one_err.rs":"2ade8409f31c47d583894f69fc0556c13a1b3b0f4dc01fcd74a4c3de11476daf","src/extrema_set.rs":"11de200d853941716e9aa9a9b520b006704827c3c43a0c5f067906b0941e51d1","src/flatten_ok.rs":"62c18e5221a27949a00de49414306d6dfd601515817c1c8ae6189e3275756dd3","src/format.rs":"3ae6414043e0040f7358028c560437ea49afdbb2416df138a2410169e2619589","src/free.rs":"1c7f7b08681b71694c2f82c66bb0d388795628f90b618c57e29d63ef7a70f0af","src/group_map.rs":"a34116bc64f73ebff084077843157a11c23b8245f6efac73ff93ff9376156dd8","src/groupbylazy.rs":"d68308d1ecc642cb42c021a4052265cbb4a961cc7c5241424bfe76e9853e144e","src/grouping_map.rs":"1c943a4d61a034ab8a6eeea0b8714383258705bbb8ebd72e5273db724e259728","src/impl_macros.rs":"97fc5f39574805e0c220aa462cf1ae7dcac5c1082d6ee5500e7d71c120db5f88","src/intersperse.rs":"55031819e985c3184275e254c9600ecbe01e9fb49f198039c5da82a87ea5b90e","src/iter_index.rs":"1b0ff8376a4ad855d44db8c662450c777db84e0f4997b53ca575c65b107bb83b","src/k_smallest.rs":"a6840980e4c1aedd6987f93c904d362aa09a101537e447121fff58bb2473638d","src/kmerge_impl.rs":"40bda0a09a178ba95a397f294d5ed4896776d1abedf793c44475d4ee41afabb9","src/lazy_buffer.rs":"baa01490fceb5a8dd7bd9c2634e19ce8a785bd1df352a9dd77d1344e3e0f8892","src/lib.rs":"cac2e34f5b83156078fbbb0137e173c1b4aa63528259f82100e16d7501692ee8","src/merge_join.rs":"f2f257e63c84ed772b235229cc787ebe9ae009d7c80ed2087002a6b62c5e2133","src/minmax.rs":"57a8b9463f0c059f9d2b95229373fe9b9791193458c07955977ea9868b2c1bb0","src/multipeek_impl.rs":"79eef0be49ad66f15d41808e72c03976c4f7cff5838b69d17975d3ece266f3f8","src/next_array.rs":"295924058891c08f9fe6313a1d9dd0042dcf60f0a514c6a6e009a1396d804fc9","src/pad_tail.rs":"ff1e0fd1355367df079b3dabb0fc7b6df4db3c515bcb42225697f527ba1762f9","src/peek_nth.rs":"093f1a157b1c917f041af5244a5a46311affa2922126e36dc0ee2c501c79b58c","src/peeking_take_while.rs":"9c2db32f04c2b25db3a1d5f1977f6a10531bcadc0a8a974d3a25ee83e087d824","src/permutations.rs":"b316084ee14e9e138d22f177367b3bfa24cb3e5e90ab20b9b00a9a23d653496f","src/powerset.rs":"2bcca88409a7db66bfa1f2ed81cc1e98c979ac739594578927ca84e722aa44e1","src/process_results_impl.rs":"6b5d82447eef4e87fef7b2a8e56b906ac7b000886a468ce421252f34ec86e371","src/put_back_n_impl.rs":"5a58d7a31c03029f0726e4d42de3be869580cf76b73c6d1ef70dd40c240b03a0","src/rciter_impl.rs":"081fd206ba4a601bd65e2f3b8d7c95e3e4a3564beb7c98944bd2e7986959c230","src/repeatn.rs":"dd9a5bf5a63ef9cc6ec5c8a6137c7ffba80f13568b6d001e189daaa29ffbaf39","src/size_hint.rs":"bfc6da72b88d62138649b0b1377d59f6c66d4d78b1c321be37219fa13821a33b","src/sources.rs":"ef942af209ca1effcd28a95abedad8c45b659ae2a15b66c2158cb604f6e325f8","src/take_while_inclusive.rs":"1973a9f5322b3dae3b5ccded5912a08a8e2e975b9a5eac666192b118b230d305","src/tee.rs":"dad50ca162627cf0a67786f0993ef27d06cdefc14d412463e58c07824ef409d8","src/tuple_impl.rs":"310e24bbbefe21492ab0de9e1a38b587c1b07977bd78c12ef8871f607723f343","src/unique_impl.rs":"25f233599cdfe092f826e1cf4ec7cd5c9d17cd3659a31205ff3e0a9ff2b49744","src/unziptuple.rs":"f3f6a2ee2658fa07db7592f2c344c2e3b1263a21fc75e1325f2be32c9dc1e750","src/with_position.rs":"8af0bfe147ebda1eedaf2afcef4ba5d80e845853031dad36844ffc683fdb3629","src/zip_eq_impl.rs":"3282b177e7dece5d3fbdc9b03563f209589a399ea45e70abf23ccca3b5512ac7","src/zip_longest.rs":"5572699564dd5717cc074b7733333ed238c2e9f3e6819d45e33e3a2dbda74478","src/ziptuple.rs":"94cedabf2fe48e0c90615338240029749faa3c9f48c02cf3bac9d0ebc4bf6f5b","tests/adaptors_no_collect.rs":"0b0512425f9b3d864398cf8c487e1d2bd76a06e5188e4a0f37922a5bf1e4f595","tests/arrays.rs":"bfafdfb27adc6239361be55120f660ae9991f1a5500acd2a37b6f71ef97c6629","tests/flatten_ok.rs":"b7894874132918b8229c7150b2637511d8e3e14197d8eeb9382d46b2a514efa2","tests/laziness.rs":"b2644ce9d78438bd2be4e833bf245b20281a900700e65cb7e761fc0ba6a7ea19","tests/macros_hygiene.rs":"c2d517badf593c0ba9b70e987a6f8482ed8997547b2e88bbec70babd9b677aa2","tests/merge_join.rs":"5fb506b989f4a331d46cdec5775ea594656985134196099eaf8d3905bdddcdd5","tests/peeking_take_while.rs":"f834361c5520dda15eb9e9ebe87507c905462201412b21859d9f83dab91d0e0b","tests/quick.rs":"dc822c7461b560ccaa42b1aab2f2ed9b10efbbe7243b15c4f1bcddf1b7b7e61a","tests/specializations.rs":"39817f342e9f9da24653f600897a73a46a6f29ceb792083e0575ffbc7de8899f","tests/test_core.rs":"94e786ea94f2862b167d4c13785ca57bf8d27055fc4117257fc70ee764ce6247","tests/test_std.rs":"58654b9dbaaa8ea213c913e9e44eb8d7939689fca9f92096b7d0a90901bfa4fd","tests/tuples.rs":"014e4da776174bfe923270e2a359cd9c95b372fce4b952b8138909d6e2c52762","tests/zip.rs":"1ac8ff7b1a60298957748764e0231c1d740d06e5ccfacf727bafa3f9eee4a860"},"package":"8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc"} \ No newline at end of file diff --git a/third_party/rust/itertools/.cargo_vcs_info.json b/third_party/rust/itertools/.cargo_vcs_info.json index a6fc921c2a93..e3c6c36f2b61 100644 --- a/third_party/rust/itertools/.cargo_vcs_info.json +++ b/third_party/rust/itertools/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "a015a6831525ee1637df747d3f530a627d9741bf" + "sha1": "37bd72aa6d58e594711d127b52418ca5e58b6091" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/third_party/rust/itertools/CHANGELOG.md b/third_party/rust/itertools/CHANGELOG.md index 6b08f68309ab..41f62bdcce20 100644 --- a/third_party/rust/itertools/CHANGELOG.md +++ b/third_party/rust/itertools/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 0.15.0 + +### Breaking +- Restructure `Position` as struct instead of enum (#1042, #1043) +- Canonicalize `all_equal_value`'s error type (#1032) + +### Added +- Add `*_with_hasher` adaptors (#1007) +- Add strip_prefix and strip_prefix_by methods (#1104) + +### Changed +- Remove `Clone` bounds from `tuple_combinations` and `array_combinations`(#1011) +- `must_use` for `collect_vec` (#1009) +- Make `izip!` temporary friendly (#1021) +- Add `array_combinations_with_replacement` (#1033) +- Implement `Debug` for remaining public types (#1038) +- Specialize `ExactlyOneError::count` (#1046) +- Implement `PeekingNext` for more types, in particular `vec::IntoIter` (#1059, #1073) +- Fix `PadUsing::next_back` (#1082) +- Introduce `[circular_]array_windows`, deprecate `tuple_windows` (#1086) +- Deprecate `tuple_combinations` (replaced by `array_combinations`) (#1085) + +### Notable Internal Changes +- Make `into_group_map` code more idiomatic (#1027) +- Fix clippy lints (#1017, #1029, #1076, #1099) + ## 0.14.0 ### Breaking diff --git a/third_party/rust/itertools/Cargo.lock b/third_party/rust/itertools/Cargo.lock index fbf369b2fab4..a7062bc996ce 100644 --- a/third_party/rust/itertools/Cargo.lock +++ b/third_party/rust/itertools/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bitflags" @@ -42,9 +42,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "cast" @@ -54,9 +54,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "ciborium" @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -163,21 +163,45 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "either" -version = "1.11.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] [[package]] name = "getrandom" @@ -192,12 +216,13 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -236,7 +261,7 @@ dependencies = [ [[package]] name = "itertools" -version = "0.14.0" +version = "0.15.0" dependencies = [ "criterion", "either", @@ -248,42 +273,38 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" dependencies = [ + "cfg-if", + "futures-util", "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "memchr" -version = "2.7.2" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "num-traits" @@ -296,15 +317,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "os_str_bytes" @@ -325,10 +346,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" [[package]] -name = "plotters" -version = "0.3.5" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -339,30 +366,33 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -379,9 +409,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -429,9 +459,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -439,9 +469,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -449,9 +479,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -461,9 +491,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -472,15 +502,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] -name = "ryu" -version = "1.0.18" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "same-file" @@ -493,18 +523,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -513,20 +553,28 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] -name = "syn" -version = "2.0.63" +name = "slab" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -535,9 +583,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" [[package]] name = "tinytemplate" @@ -551,9 +599,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "walkdir" @@ -573,34 +621,22 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" dependencies = [ "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", "once_cell", - "proc-macro2", - "quote", - "syn", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -608,28 +644,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" dependencies = [ "js-sys", "wasm-bindgen", @@ -653,9 +692,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] @@ -666,75 +705,43 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets", + "windows-link", ] [[package]] -name = "windows-targets" -version = "0.52.5" +name = "zerocopy" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "zerocopy-derive", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" +name = "zerocopy-derive" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" +name = "zmij" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/third_party/rust/itertools/Cargo.toml b/third_party/rust/itertools/Cargo.toml index 96f9597712b7..f8dfa3323978 100644 --- a/third_party/rust/itertools/Cargo.toml +++ b/third_party/rust/itertools/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" rust-version = "1.63.0" name = "itertools" -version = "0.14.0" +version = "0.15.0" authors = ["bluss"] build = false autolib = false @@ -61,6 +61,10 @@ path = "examples/iris.rs" name = "adaptors_no_collect" path = "tests/adaptors_no_collect.rs" +[[test]] +name = "arrays" +path = "tests/arrays.rs" + [[test]] name = "flatten_ok" path = "tests/flatten_ok.rs" diff --git a/third_party/rust/itertools/Cargo.toml.orig b/third_party/rust/itertools/Cargo.toml.orig index 1d8a68f83623..ea2f1fe1ea7e 100644 --- a/third_party/rust/itertools/Cargo.toml.orig +++ b/third_party/rust/itertools/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "itertools" -version = "0.14.0" +version = "0.15.0" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-itertools/itertools" diff --git a/third_party/rust/itertools/README.md b/third_party/rust/itertools/README.md index 46acc3fcae09..6628ed7b0929 100644 --- a/third_party/rust/itertools/README.md +++ b/third_party/rust/itertools/README.md @@ -8,7 +8,7 @@ How to use with Cargo: ```toml [dependencies] -itertools = "0.14.0" +itertools = "0.15.0" ``` How to use in your crate: diff --git a/third_party/rust/itertools/benches/combinations_with_replacement.rs b/third_party/rust/itertools/benches/combinations_with_replacement.rs index 8e4fa3dc3b1b..203532714ec8 100644 --- a/third_party/rust/itertools/benches/combinations_with_replacement.rs +++ b/third_party/rust/itertools/benches/combinations_with_replacement.rs @@ -30,11 +30,42 @@ fn comb_replacement_n10_k10(c: &mut Criterion) { }) }); } +fn array_comb_replacement_n10_k5(c: &mut Criterion) { + c.bench_function("array comb replacement n10k5", move |b| { + b.iter(|| { + for i in (0..10).array_combinations_with_replacement::<5>() { + black_box(i); + } + }) + }); +} +fn array_comb_replacement_n5_k10(c: &mut Criterion) { + c.bench_function("array comb replacement n5 k10", move |b| { + b.iter(|| { + for i in (0..5).array_combinations_with_replacement::<10>() { + black_box(i); + } + }) + }); +} + +fn array_comb_replacement_n10_k10(c: &mut Criterion) { + c.bench_function("array comb replacement n10 k10", move |b| { + b.iter(|| { + for i in (0..10).array_combinations_with_replacement::<10>() { + black_box(i); + } + }) + }); +} criterion_group!( benches, comb_replacement_n10_k5, comb_replacement_n5_k10, comb_replacement_n10_k10, + array_comb_replacement_n10_k5, + array_comb_replacement_n5_k10, + array_comb_replacement_n10_k10, ); criterion_main!(benches); diff --git a/third_party/rust/itertools/benches/powerset.rs b/third_party/rust/itertools/benches/powerset.rs index 018333d316c1..7d7fc17fe94c 100644 --- a/third_party/rust/itertools/benches/powerset.rs +++ b/third_party/rust/itertools/benches/powerset.rs @@ -8,7 +8,7 @@ const fn calc_iters(n: usize) -> usize { } fn powerset_n(c: &mut Criterion, n: usize) { - let id = format!("powerset {}", n); + let id = format!("powerset {n}"); c.bench_function(id.as_str(), move |b| { b.iter(|| { for _ in 0..calc_iters(n) { @@ -21,7 +21,7 @@ fn powerset_n(c: &mut Criterion, n: usize) { } fn powerset_n_fold(c: &mut Criterion, n: usize) { - let id = format!("powerset {} fold", n); + let id = format!("powerset {n} fold"); c.bench_function(id.as_str(), move |b| { b.iter(|| { for _ in 0..calc_iters(n) { diff --git a/third_party/rust/itertools/benches/specializations.rs b/third_party/rust/itertools/benches/specializations.rs index e70323f8e6c2..247b61481faa 100644 --- a/third_party/rust/itertools/benches/specializations.rs +++ b/third_party/rust/itertools/benches/specializations.rs @@ -355,29 +355,29 @@ bench_specializations! { } v.iter().copied().update(|x| *x *= 7) } - tuple_combinations1 { + array_combinations1 { { let v = black_box(vec![0; 1024]); } - v.iter().tuple_combinations::<(_,)>() + v.iter().array_combinations::<1>() } - tuple_combinations2 { + array_combinations2 { { let v = black_box(vec![0; 64]); } - v.iter().tuple_combinations::<(_, _)>() + v.iter().array_combinations::<2>() } - tuple_combinations3 { + array_combinations3 { { let v = black_box(vec![0; 64]); } - v.iter().tuple_combinations::<(_, _, _)>() + v.iter().array_combinations::<3>() } - tuple_combinations4 { + array_combinations4 { { let v = black_box(vec![0; 64]); } - v.iter().tuple_combinations::<(_, _, _, _)>() + v.iter().array_combinations::<4>() } intersperse { { @@ -441,6 +441,30 @@ bench_specializations! { } v.iter().combinations_with_replacement(4) } + array_combinations_with_replacement1 { + { + let v = black_box(vec![0; 4096]); + } + v.iter().array_combinations_with_replacement::<1>() + } + array_combinations_with_replacement2 { + { + let v = black_box(vec![0; 90]); + } + v.iter().array_combinations_with_replacement::<2>() + } + array_combinations_with_replacement3 { + { + let v = black_box(vec![0; 28]); + } + v.iter().array_combinations_with_replacement::<3>() + } + array_combinations_with_replacement4 { + { + let v = black_box(vec![0; 16]); + } + v.iter().array_combinations_with_replacement::<4>() + } permutations1 { { let v = black_box(vec![0; 1024]); diff --git a/third_party/rust/itertools/benches/tree_reduce.rs b/third_party/rust/itertools/benches/tree_reduce.rs index 051b14883481..4580fa61a07f 100644 --- a/third_party/rust/itertools/benches/tree_reduce.rs +++ b/third_party/rust/itertools/benches/tree_reduce.rs @@ -12,8 +12,8 @@ trait IterEx: Iterator { Self: Sized, { let hint = self.size_hint().0; - let cap = std::mem::size_of::() * 8 - hint.leading_zeros() as usize; - let mut stack = Vec::with_capacity(cap); + let capacity = usize::BITS - hint.leading_zeros(); + let mut stack = Vec::with_capacity(capacity as usize); self.enumerate().for_each(|(mut i, mut x)| { while (i & 1) != 0 { x = f(stack.pop().unwrap(), x); diff --git a/third_party/rust/itertools/benches/tuple_combinations.rs b/third_party/rust/itertools/benches/tuple_combinations.rs index 4e26b282e853..407a97856357 100644 --- a/third_party/rust/itertools/benches/tuple_combinations.rs +++ b/third_party/rust/itertools/benches/tuple_combinations.rs @@ -7,8 +7,8 @@ const N2: usize = 448; const N3: usize = 86; const N4: usize = 41; -fn tuple_comb_for1(c: &mut Criterion) { - c.bench_function("tuple comb for1", move |b| { +fn array_comb_for1(c: &mut Criterion) { + c.bench_function("array comb for1", move |b| { b.iter(|| { for i in 0..N1 { black_box(i); @@ -17,8 +17,8 @@ fn tuple_comb_for1(c: &mut Criterion) { }); } -fn tuple_comb_for2(c: &mut Criterion) { - c.bench_function("tuple comb for2", move |b| { +fn array_comb_for2(c: &mut Criterion) { + c.bench_function("array comb for2", move |b| { b.iter(|| { for i in 0..N2 { for j in (i + 1)..N2 { @@ -29,8 +29,8 @@ fn tuple_comb_for2(c: &mut Criterion) { }); } -fn tuple_comb_for3(c: &mut Criterion) { - c.bench_function("tuple comb for3", move |b| { +fn array_comb_for3(c: &mut Criterion) { + c.bench_function("array comb for3", move |b| { b.iter(|| { for i in 0..N3 { for j in (i + 1)..N3 { @@ -43,8 +43,8 @@ fn tuple_comb_for3(c: &mut Criterion) { }); } -fn tuple_comb_for4(c: &mut Criterion) { - c.bench_function("tuple comb for4", move |b| { +fn array_comb_for4(c: &mut Criterion) { + c.bench_function("array comb for4", move |b| { b.iter(|| { for i in 0..N4 { for j in (i + 1)..N4 { @@ -59,40 +59,40 @@ fn tuple_comb_for4(c: &mut Criterion) { }); } -fn tuple_comb_c1(c: &mut Criterion) { - c.bench_function("tuple comb c1", move |b| { +fn array_comb_c1(c: &mut Criterion) { + c.bench_function("array comb c1", move |b| { b.iter(|| { - for (i,) in (0..N1).tuple_combinations() { + for [i] in (0..N1).array_combinations() { black_box(i); } }) }); } -fn tuple_comb_c2(c: &mut Criterion) { - c.bench_function("tuple comb c2", move |b| { +fn array_comb_c2(c: &mut Criterion) { + c.bench_function("array comb c2", move |b| { b.iter(|| { - for (i, j) in (0..N2).tuple_combinations() { + for [i, j] in (0..N2).array_combinations() { black_box(i + j); } }) }); } -fn tuple_comb_c3(c: &mut Criterion) { - c.bench_function("tuple comb c3", move |b| { +fn array_comb_c3(c: &mut Criterion) { + c.bench_function("array comb c3", move |b| { b.iter(|| { - for (i, j, k) in (0..N3).tuple_combinations() { + for [i, j, k] in (0..N3).array_combinations() { black_box(i + j + k); } }) }); } -fn tuple_comb_c4(c: &mut Criterion) { - c.bench_function("tuple comb c4", move |b| { +fn array_comb_c4(c: &mut Criterion) { + c.bench_function("array comb c4", move |b| { b.iter(|| { - for (i, j, k, l) in (0..N4).tuple_combinations() { + for [i, j, k, l] in (0..N4).array_combinations() { black_box(i + j + k + l); } }) @@ -101,13 +101,13 @@ fn tuple_comb_c4(c: &mut Criterion) { criterion_group!( benches, - tuple_comb_for1, - tuple_comb_for2, - tuple_comb_for3, - tuple_comb_for4, - tuple_comb_c1, - tuple_comb_c2, - tuple_comb_c3, - tuple_comb_c4, + array_comb_for1, + array_comb_for2, + array_comb_for3, + array_comb_for4, + array_comb_c1, + array_comb_c2, + array_comb_c3, + array_comb_c4, ); criterion_main!(benches); diff --git a/third_party/rust/itertools/examples/iris.rs b/third_party/rust/itertools/examples/iris.rs index 63f9c4832604..f89f2e3ae4aa 100644 --- a/third_party/rust/itertools/examples/iris.rs +++ b/third_party/rust/itertools/examples/iris.rs @@ -65,7 +65,7 @@ fn main() { }); let mut irises = match irises { Err(e) => { - println!("Error parsing: {:?}", e); + println!("Error parsing: {e:?}"); std::process::exit(1); } Ok(data) => data, @@ -99,9 +99,9 @@ fn main() { let n = 30; // plot size let mut plot = vec![' '; n * n]; - // using Itertools::tuple_combinations - for (a, b) in (0..4).tuple_combinations() { - println!("Column {} vs {}:", a, b); + // using Itertools::array_combinations + for [a, b] in (0..4).array_combinations() { + println!("Column {a} vs {b}:"); // Clear plot // diff --git a/third_party/rust/itertools/src/adaptors/coalesce.rs b/third_party/rust/itertools/src/adaptors/coalesce.rs index ab1ab5255dd6..1e3fa6054c0f 100644 --- a/third_party/rust/itertools/src/adaptors/coalesce.rs +++ b/third_party/rust/itertools/src/adaptors/coalesce.rs @@ -74,9 +74,9 @@ where fn size_hint(&self) -> (usize, Option) { let (low, hi) = size_hint::add_scalar( self.iter.size_hint(), - matches!(self.last, Some(Some(_))) as usize, + usize::from(matches!(self.last, Some(Some(_)))), ); - ((low > 0) as usize, hi) + (usize::from(low > 0), hi) } fn fold(self, acc: Acc, mut fn_acc: FnAcc) -> Acc @@ -110,8 +110,10 @@ where { } +#[derive(Debug)] pub struct NoCount; +#[derive(Debug)] pub struct WithCount; pub trait CountItem { diff --git a/third_party/rust/itertools/src/adaptors/mod.rs b/third_party/rust/itertools/src/adaptors/mod.rs index 77192f26eb70..b5c0d42b1a32 100644 --- a/third_party/rust/itertools/src/adaptors/mod.rs +++ b/third_party/rust/itertools/src/adaptors/mod.rs @@ -300,11 +300,11 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { // Not ExactSizeIterator because size may be larger than usize - size_hint::add_scalar(self.iter.size_hint(), self.top.is_some() as usize) + size_hint::add_scalar(self.iter.size_hint(), usize::from(self.top.is_some())) } fn count(self) -> usize { - self.iter.count() + (self.top.is_some() as usize) + self.iter.count() + usize::from(self.top.is_some()) } fn last(self) -> Option { @@ -522,8 +522,8 @@ where debug_fmt_fields!(TakeWhileRef, iter); } -/// Create a new `TakeWhileRef` from a reference to clonable iterator. -pub fn take_while_ref(iter: &mut I, f: F) -> TakeWhileRef +/// Create a new `TakeWhileRef` from a reference to cloneable iterator. +pub fn take_while_ref(iter: &mut I, f: F) -> TakeWhileRef<'_, I, F> where I: Iterator + Clone, { @@ -626,10 +626,10 @@ pub trait HasCombination: Sized { type Combination: From + Iterator; } -/// Create a new `TupleCombinations` from a clonable iterator. +/// Create a new `TupleCombinations` from a cloneable iterator. pub fn tuple_combinations(iter: I) -> TupleCombinations where - I: Iterator + Clone, + I: Iterator, I::Item: Clone, T: HasCombination, { @@ -992,7 +992,7 @@ fn transpose_result(result: Result, E>) -> Option> } } -/// Create a new `FilterOk` iterator. +/// Create a new `FilterMapOk` iterator. pub fn filter_map_ok(iter: I, f: F) -> FilterMapOk where I: Iterator>, diff --git a/third_party/rust/itertools/src/all_equal_value_err.rs b/third_party/rust/itertools/src/all_equal_value_err.rs new file mode 100644 index 000000000000..f3a1d3a4ebda --- /dev/null +++ b/third_party/rust/itertools/src/all_equal_value_err.rs @@ -0,0 +1,31 @@ +#[cfg(doc)] +use crate::Itertools; +#[cfg(feature = "use_std")] +use std::error::Error; +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; + +/// Value returned for the error case of [`Itertools::all_equal_value`]. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct AllEqualValueError(pub Option<[Item; 2]>); + +impl Display for AllEqualValueError { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + match self.0 { + None => { + write!( + f, + "got zero elements when all elements were expected to be equal" + ) + } + Some([_, _]) => { + write!( + f, + "got different elements when all elements were expected to be equal" + ) + } + } + } +} + +#[cfg(feature = "use_std")] +impl Error for AllEqualValueError where Item: Debug {} diff --git a/third_party/rust/itertools/src/array_impl.rs b/third_party/rust/itertools/src/array_impl.rs new file mode 100644 index 000000000000..f227392133ab --- /dev/null +++ b/third_party/rust/itertools/src/array_impl.rs @@ -0,0 +1,226 @@ +use crate::Itertools; +use std::iter::Fuse; + +/// An iterator over all contiguous windows of the input iterator, +/// producing arrays of a specific size. +/// +/// See [`.array_windows()`](crate::Itertools::array_windows) for more +/// information. +#[derive(Debug, Clone)] +pub struct ArrayWindows +where + I: Iterator + Sized, + I::Item: Clone, +{ + iter: Fuse, + inner: Option>, +} + +#[derive(Debug, Clone)] +struct ArrayWindowsInner { + // `window` stores the `N` items delivered in the most + // recent output window. It is stored in the form of a ring + // buffer, with `window_start` identifying the element + // that logically comes first. + window: [T; N], + window_start: usize, +} + +impl ArrayWindowsInner { + /// Replace the least recent item in `window` with a new + /// item. + fn add_to_buffer(&mut self, item: T) { + if N > 0 { + self.window[self.window_start] = item; + self.window_start = (self.window_start + 1) % N; + } + } + + /// Construct an array window to return. + fn make_window(&self) -> [T; N] { + std::array::from_fn(|i| self.window[(i + self.window_start) % N].clone()) + } +} + +impl Iterator for ArrayWindows +where + I: Iterator + Sized, + I::Item: Clone, +{ + type Item = [I::Item; N]; + + fn next(&mut self) -> Option<[I::Item; N]> { + match &mut self.inner { + // Initialisation code, when next() is called for the first time + None => match self.iter.next_array() { + None => { + // The input iterator was completely empty + None + } + Some(buf) => { + let inner = ArrayWindowsInner { + window: buf, + window_start: 0, + }; + let window = inner.make_window(); + self.inner = Some(inner); + Some(window) + } + }, + Some(inner) => match self.iter.next() { + Some(item) => { + inner.add_to_buffer(item); + Some(inner.make_window()) + } + None => None, + }, + } + } +} + +pub fn array_windows(iter: I) -> ArrayWindows +where + I: Iterator + Sized, + I::Item: Clone, +{ + ArrayWindows { + iter: iter.fuse(), + inner: None, + } +} + +/// An iterator over all windows, wrapping back to the first elements when the +/// window would otherwise exceed the length of the iterator, producing arrays +/// of a specific size. +/// +/// See [`.circular_array_windows()`](crate::Itertools::circular_array_windows) +/// for more information. +#[derive(Debug, Clone)] +pub struct CircularArrayWindows +where + I: Iterator + Sized, + I::Item: Clone, +{ + iter: Fuse, + inner: Option>, +} + +#[derive(Debug, Clone)] +struct CircularArrayWindowsInner { + // `prefix` stores the first `N` items output from this iterator. + // If the input contained fewer than `N` items, then it is filled + // with clones of the previous items in a cycle. + // + // `prefix_pos` tracks the number of items that have been _used_ + // from `prefix`. It begins counting up from 0 once the input runs + // out. (So in the case where the input iterator is shorter than + // `N`, it will begin counting up before `prefix` has even been + // populated during setup.) + prefix: [T; N], + prefix_pos: usize, + + // For delivering the output arrays, we reuse `ArrayWindowsInner` + // unchanged. + arraywin: ArrayWindowsInner, +} + +impl Iterator for CircularArrayWindows +where + I: Iterator + Sized, + I::Item: Clone, +{ + type Item = [I::Item; N]; + + fn next(&mut self) -> Option<[I::Item; N]> { + match &mut self.inner { + // Initialisation code, when next() is called for the first time + None => match self.iter.next() { + None => { + // The input iterator was completely empty + None + } + Some(first) => { + // We have at least one item, so we can definitely + // populate `prefix` (even if we have to make N + // copies of this element). + + // Construct [Option; N] and convert to [T; N] + // once it's full. TODO: can this be improved? + let mut items = std::array::from_fn(|_| None); + let mut prefix_pos = 0; + if N > 0 { + // The first item stored is the one passed to + // us from our caller. + items[0] = Some(first); + } + for i in 1..N { + // Populate the remaining slots in `items` + // from the input iterator. + items[i] = self.iter.next(); + if items[i].is_none() { + // If the input iterator runs out early, + // populate the rest of `items` by + // recycling from the beginning, and set + // `prefix_pos` to indicate that we have + // already consumed those items. + for j in i..N { + items[j] = items[j - i].clone(); + } + prefix_pos = N - i; + break; + } + } + let items = items.map(Option::unwrap); + + let inner = CircularArrayWindowsInner { + prefix: items.clone(), + prefix_pos, + arraywin: ArrayWindowsInner { + window: items, + window_start: 0, + }, + }; + + let window = inner.arraywin.make_window(); + self.inner = Some(inner); + Some(window) + } + }, + Some(inner) => { + // Normal case. Read the next item in the logical + // input sequence (consisting of the contents of the + // input iterator followed by N-1 items recycling from + // the beginning), and add it to the ring buffer. + let item = if let Some(item) = self.iter.next() { + // Read from the input iterator. + item + } else { + assert!(N == 0 || inner.prefix_pos < N); + if N == 0 || inner.prefix_pos + 1 == N { + // The input iterator has run out, and we've + // emitted as many windows as we read items, + // so we've finished. + return None; + } + let item = inner.prefix[inner.prefix_pos].clone(); + inner.prefix_pos += 1; + item + }; + + inner.arraywin.add_to_buffer(item); + Some(inner.arraywin.make_window()) + } + } + } +} + +pub fn circular_array_windows(iter: I) -> CircularArrayWindows +where + I: Iterator + Sized, + I::Item: Clone, +{ + CircularArrayWindows { + iter: iter.fuse(), + inner: None, + } +} diff --git a/third_party/rust/itertools/src/combinations.rs b/third_party/rust/itertools/src/combinations.rs index 54a027551607..838007578866 100644 --- a/third_party/rust/itertools/src/combinations.rs +++ b/third_party/rust/itertools/src/combinations.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use core::array; use core::borrow::BorrowMut; use std::fmt; @@ -13,7 +14,7 @@ pub type Combinations = CombinationsGeneric>; /// Iterator for const generic combinations returned by [`.array_combinations()`](crate::Itertools::array_combinations) pub type ArrayCombinations = CombinationsGeneric; -/// Create a new `Combinations` from a clonable iterator. +/// Create a new `Combinations` from a cloneable iterator. pub fn combinations(iter: I, k: usize) -> Combinations where I::Item: Clone, @@ -21,7 +22,7 @@ where Combinations::new(iter, (0..k).collect()) } -/// Create a new `ArrayCombinations` from a clonable iterator. +/// Create a new `ArrayCombinations` from a cloneable iterator. pub fn array_combinations(iter: I) -> ArrayCombinations where I::Item: Clone, @@ -52,7 +53,16 @@ pub trait PoolIndex: BorrowMut<[usize]> { self.borrow().len() } } +impl PoolIndex for Box<[usize]> { + type Item = Vec; + fn extract_item>(&self, pool: &LazyBuffer) -> Vec + where + T: Clone, + { + pool.get_at(self) + } +} impl PoolIndex for Vec { type Item = Vec; diff --git a/third_party/rust/itertools/src/combinations_with_replacement.rs b/third_party/rust/itertools/src/combinations_with_replacement.rs index c17e752508f8..315df685e586 100644 --- a/third_party/rust/itertools/src/combinations_with_replacement.rs +++ b/third_party/rust/itertools/src/combinations_with_replacement.rs @@ -1,52 +1,62 @@ use alloc::boxed::Box; -use alloc::vec::Vec; use std::fmt; use std::iter::FusedIterator; use super::lazy_buffer::LazyBuffer; use crate::adaptors::checked_binomial; - +use crate::combinations::PoolIndex; /// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement. /// /// See [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement) /// for more information. #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct CombinationsWithReplacement +pub struct CombinationsWithReplacementGeneric where I: Iterator, I::Item: Clone, { - indices: Box<[usize]>, + indices: Idx, pool: LazyBuffer, first: bool, } -impl fmt::Debug for CombinationsWithReplacement +/// Iterator for `Box<[I]>` valued combinations_with_replacement returned by [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement) +pub type CombinationsWithReplacement = CombinationsWithReplacementGeneric>; +/// Iterator for const generic combinations_with_replacement returned by [`.array_combinations_with_replacement()`](crate::Itertools::array_combinations_with_replacement) +pub type ArrayCombinationsWithReplacement = + CombinationsWithReplacementGeneric; + +impl fmt::Debug for CombinationsWithReplacementGeneric where I: Iterator + fmt::Debug, I::Item: fmt::Debug + Clone, + Idx: fmt::Debug, { - debug_fmt_fields!(CombinationsWithReplacement, indices, pool, first); + debug_fmt_fields!(CombinationsWithReplacementGeneric, indices, pool, first); } -/// Create a new `CombinationsWithReplacement` from a clonable iterator. +/// Create a new `ArrayCombinationsWithReplacement`` from a cloneable iterator. +pub fn array_combinations_with_replacement( + iter: I, +) -> ArrayCombinationsWithReplacement +where + I::Item: Clone, +{ + ArrayCombinationsWithReplacement::new(iter, [0; K]) +} +/// Create a new `CombinationsWithReplacement` from a cloneable iterator. pub fn combinations_with_replacement(iter: I, k: usize) -> CombinationsWithReplacement where I: Iterator, I::Item: Clone, { let indices = alloc::vec![0; k].into_boxed_slice(); - let pool: LazyBuffer = LazyBuffer::new(iter); - CombinationsWithReplacement { - indices, - pool, - first: true, - } + CombinationsWithReplacementGeneric::new(iter, indices) } -impl CombinationsWithReplacement +impl> CombinationsWithReplacementGeneric where I: Iterator, I::Item: Clone, @@ -62,7 +72,8 @@ where // Work out where we need to update our indices let mut increment = None; - for (i, indices_int) in self.indices.iter().enumerate().rev() { + let indices: &mut [usize] = self.indices.borrow_mut(); + for (i, indices_int) in indices.iter().enumerate().rev() { if *indices_int < self.pool.len() - 1 { increment = Some((i, indices_int + 1)); break; @@ -73,39 +84,48 @@ where Some((increment_from, increment_value)) => { // We need to update the rightmost non-max value // and all those to the right - self.indices[increment_from..].fill(increment_value); + indices[increment_from..].fill(increment_value); false } // Otherwise, we're done None => true, } } + /// Constructor with arguments the inner iterator and the initial state for the indices. + fn new(iter: I, indices: Idx) -> Self { + Self { + indices, + pool: LazyBuffer::new(iter), + first: true, + } + } } -impl Iterator for CombinationsWithReplacement +impl Iterator for CombinationsWithReplacementGeneric where I: Iterator, I::Item: Clone, + Idx: PoolIndex, { - type Item = Vec; + type Item = Idx::Item; fn next(&mut self) -> Option { if self.first { // In empty edge cases, stop iterating immediately - if !(self.indices.is_empty() || self.pool.get_next()) { + if !(self.indices.borrow().is_empty() || self.pool.get_next()) { return None; } self.first = false; } else if self.increment_indices() { return None; } - Some(self.pool.get_at(&self.indices)) + Some(self.indices.extract_item(&self.pool)) } fn nth(&mut self, n: usize) -> Option { if self.first { // In empty edge cases, stop iterating immediately - if !(self.indices.is_empty() || self.pool.get_next()) { + if !(self.indices.borrow().is_empty() || self.pool.get_next()) { return None; } self.first = false; @@ -117,13 +137,13 @@ where return None; } } - Some(self.pool.get_at(&self.indices)) + Some(self.indices.extract_item(&self.pool)) } fn size_hint(&self) -> (usize, Option) { let (mut low, mut upp) = self.pool.size_hint(); - low = remaining_for(low, self.first, &self.indices).unwrap_or(usize::MAX); - upp = upp.and_then(|upp| remaining_for(upp, self.first, &self.indices)); + low = remaining_for(low, self.first, self.indices.borrow()).unwrap_or(usize::MAX); + upp = upp.and_then(|upp| remaining_for(upp, self.first, self.indices.borrow())); (low, upp) } @@ -134,14 +154,15 @@ where first, } = self; let n = pool.count(); - remaining_for(n, first, &indices).unwrap() + remaining_for(n, first, indices.borrow()).unwrap() } } -impl FusedIterator for CombinationsWithReplacement +impl FusedIterator for CombinationsWithReplacementGeneric where I: Iterator, I::Item: Clone, + Idx: PoolIndex, { } diff --git a/third_party/rust/itertools/src/duplicates_impl.rs b/third_party/rust/itertools/src/duplicates_impl.rs index a0db15432d85..853f97490591 100644 --- a/third_party/rust/itertools/src/duplicates_impl.rs +++ b/third_party/rust/itertools/src/duplicates_impl.rs @@ -1,31 +1,39 @@ +use core::hash::BuildHasher; +use std::collections::hash_map::RandomState; use std::hash::Hash; mod private { + use core::hash::BuildHasher; + use std::collections::hash_map::RandomState; use std::collections::HashMap; use std::fmt; use std::hash::Hash; #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] - pub struct DuplicatesBy { + pub struct DuplicatesBy + where + S: BuildHasher, + { pub(crate) iter: I, - pub(crate) meta: Meta, + pub(crate) meta: Meta, } - impl fmt::Debug for DuplicatesBy + impl fmt::Debug for DuplicatesBy where I: Iterator + fmt::Debug, V: fmt::Debug + Hash + Eq, + S: BuildHasher, { debug_fmt_fields!(DuplicatesBy, iter, meta.used); } - impl DuplicatesBy { - pub(crate) fn new(iter: I, key_method: F) -> Self { + impl DuplicatesBy { + pub(crate) fn new(iter: I, key_method: F, hash_builder: S) -> Self { Self { iter, meta: Meta { - used: HashMap::new(), + used: HashMap::with_hasher(hash_builder), pending: 0, key_method, }, @@ -34,15 +42,16 @@ mod private { } #[derive(Clone)] - pub struct Meta { - used: HashMap, + pub struct Meta { + used: HashMap, pending: usize, key_method: F, } - impl Meta + impl Meta where Key: Eq + Hash, + S: BuildHasher, { /// Takes an item and returns it back to the caller if it's the second time we see it. /// Otherwise the item is consumed and None is returned @@ -68,11 +77,12 @@ mod private { } } - impl Iterator for DuplicatesBy + impl Iterator for DuplicatesBy where I: Iterator, Key: Eq + Hash, F: KeyMethod, + S: BuildHasher, { type Item = I::Item; @@ -102,11 +112,12 @@ mod private { } } - impl DoubleEndedIterator for DuplicatesBy + impl DoubleEndedIterator for DuplicatesBy where I: DoubleEndedIterator, Key: Eq + Hash, F: KeyMethod, + S: BuildHasher, { fn next_back(&mut self) -> Option { let Self { iter, meta } = self; @@ -189,28 +200,35 @@ mod private { /// An iterator adapter to filter for duplicate elements. /// /// See [`.duplicates_by()`](crate::Itertools::duplicates_by) for more information. -pub type DuplicatesBy = private::DuplicatesBy>; +pub type DuplicatesBy = private::DuplicatesBy, S>; -/// Create a new `DuplicatesBy` iterator. -pub fn duplicates_by(iter: I, f: F) -> DuplicatesBy +/// Create a new `DuplicatesBy` iterator with a specified hash builder. +pub fn duplicates_by_with_hasher( + iter: I, + f: F, + hash_builder: S, +) -> DuplicatesBy where Key: Eq + Hash, F: FnMut(&I::Item) -> Key, I: Iterator, + S: BuildHasher, { - DuplicatesBy::new(iter, private::ByFn(f)) + DuplicatesBy::new(iter, private::ByFn(f), hash_builder) } /// An iterator adapter to filter out duplicate elements. /// /// See [`.duplicates()`](crate::Itertools::duplicates) for more information. -pub type Duplicates = private::DuplicatesBy::Item, private::ById>; +pub type Duplicates = + private::DuplicatesBy::Item, private::ById, S>; -/// Create a new `Duplicates` iterator. -pub fn duplicates(iter: I) -> Duplicates +/// Create a new `Duplicates` iterator with a specified hash builder. +pub fn duplicates_with_hasher(iter: I, hash_builder: S) -> Duplicates where I: Iterator, I::Item: Eq + Hash, + S: BuildHasher, { - Duplicates::new(iter, private::ById) + Duplicates::new(iter, private::ById, hash_builder) } diff --git a/third_party/rust/itertools/src/either_or_both.rs b/third_party/rust/itertools/src/either_or_both.rs index b7a7fc14115b..b39e4626546a 100644 --- a/third_party/rust/itertools/src/either_or_both.rs +++ b/third_party/rust/itertools/src/either_or_both.rs @@ -421,7 +421,7 @@ impl EitherOrBoth { /// // Inserting a second value. /// let mut either = Left("what's"); /// assert_eq!(*either.insert_right(9 + 10), 21 - 2); - /// assert_eq!(either, Both("what's", 9+10)); + /// assert_eq!(either, Both("what's", 9 + 10)); /// ``` pub fn insert_right(&mut self, val: B) -> &mut B { match self { @@ -467,7 +467,7 @@ impl EitherOrBoth { /// Return either value of left, right, or apply a function `f` to both values if both are present. /// The input function has to return the same type as both Right and Left carry. /// - /// This function can be used to preferrably extract the left resp. right value, + /// This function can be used to preferably extract the left resp. right value, /// but fall back to the other (i.e. right resp. left) if the preferred one is not present. /// /// # Examples diff --git a/third_party/rust/itertools/src/exactly_one_err.rs b/third_party/rust/itertools/src/exactly_one_err.rs index 19b9e19189a5..6e79f99fdd83 100644 --- a/third_party/rust/itertools/src/exactly_one_err.rs +++ b/third_party/rust/itertools/src/exactly_one_err.rs @@ -8,7 +8,9 @@ use either::Either; use crate::size_hint; -/// Iterator returned for the error case of `Itertools::exactly_one()` +/// Iterator returned for the error case of `Itertools` +/// [`exactly_one()`](crate::Itertools::exactly_one) and +/// [`at_most_one()`](crate::Itertools::at_most_one). /// This iterator yields exactly the same elements as the input iterator. /// /// During the execution of `exactly_one` the iterator must be mutated. This wrapper @@ -64,6 +66,13 @@ where size_hint::add_scalar(self.inner.size_hint(), self.additional_len()) } + fn count(self) -> usize + where + Self: Sized, + { + self.additional_len() + self.inner.count() + } + fn fold(self, mut init: B, mut f: F) -> B where F: FnMut(B, Self::Item) -> B, diff --git a/third_party/rust/itertools/src/free.rs b/third_party/rust/itertools/src/free.rs index 4c6820543caf..2051be8b6b2f 100644 --- a/third_party/rust/itertools/src/free.rs +++ b/third_party/rust/itertools/src/free.rs @@ -119,7 +119,7 @@ where /// for (a, b) in zip(&[1, 2, 3, 4, 5], &['a', 'b', 'c']) { /// result.push((*a, *b)); /// } -/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]); +/// assert_eq!(result, vec![(1, 'a'), (2, 'b'), (3, 'c')]); /// ``` #[deprecated( note = "Use [std::iter::zip](https://doc.rust-lang.org/std/iter/fn.zip.html) instead", @@ -141,7 +141,7 @@ where /// ``` /// use itertools::chain; /// -/// let mut result:Vec = Vec::new(); +/// let mut result: Vec = Vec::new(); /// /// for element in chain(&[1, 2, 3], &[4]) { /// result.push(*element); @@ -284,8 +284,8 @@ where /// [`IntoIterator`] enabled version of [`Itertools::sorted`]. /// /// ``` -/// use itertools::sorted; /// use itertools::assert_equal; +/// use itertools::sorted; /// /// assert_equal(sorted("rust".chars()), "rstu".chars()); /// ``` @@ -304,8 +304,8 @@ where /// [`IntoIterator`] enabled version of [`Itertools::sorted_unstable`]. /// /// ``` -/// use itertools::sorted_unstable; /// use itertools::assert_equal; +/// use itertools::sorted_unstable; /// /// assert_equal(sorted_unstable("rust".chars()), "rstu".chars()); /// ``` diff --git a/third_party/rust/itertools/src/group_map.rs b/third_party/rust/itertools/src/group_map.rs index 3dcee83afd00..c93afeb8a33c 100644 --- a/third_party/rust/itertools/src/group_map.rs +++ b/third_party/rust/itertools/src/group_map.rs @@ -1,5 +1,6 @@ #![cfg(feature = "use_std")] +use core::hash::BuildHasher; use std::collections::HashMap; use std::hash::Hash; use std::iter::Iterator; @@ -8,25 +9,31 @@ use std::iter::Iterator; /// /// See [`.into_group_map()`](crate::Itertools::into_group_map) /// for more information. -pub fn into_group_map(iter: I) -> HashMap> +pub fn into_group_map_with_hasher(iter: I, hash_builder: S) -> HashMap, S> where I: Iterator, K: Hash + Eq, + S: BuildHasher, { - let mut lookup = HashMap::new(); + let mut lookup = HashMap::, S>::with_hasher(hash_builder); iter.for_each(|(key, val)| { - lookup.entry(key).or_insert_with(Vec::new).push(val); + lookup.entry(key).or_default().push(val); }); lookup } -pub fn into_group_map_by(iter: I, mut f: F) -> HashMap> +pub fn into_group_map_by_with_hasher( + iter: I, + mut f: F, + hash_builder: S, +) -> HashMap, S> where I: Iterator, K: Hash + Eq, F: FnMut(&V) -> K, + S: BuildHasher, { - into_group_map(iter.map(|v| (f(&v), v))) + into_group_map_with_hasher(iter.map(|v| (f(&v), v)), hash_builder) } diff --git a/third_party/rust/itertools/src/groupbylazy.rs b/third_party/rust/itertools/src/groupbylazy.rs index 5847c8f7d1f7..99778a87c397 100644 --- a/third_party/rust/itertools/src/groupbylazy.rs +++ b/third_party/rust/itertools/src/groupbylazy.rs @@ -1,5 +1,6 @@ use alloc::vec::{self, Vec}; use std::cell::{Cell, RefCell}; +use std::fmt::Debug; /// A trait to unify `FnMut` for `ChunkBy` with the chunk key in `IntoChunks` trait KeyFunction { @@ -76,6 +77,27 @@ where dropped_group: usize, } +impl Debug for GroupInner +where + K: Debug, + I: Iterator + Debug, + I::Item: Debug, +{ + debug_fmt_fields!( + GroupInner, + // key, omitted because functions are almost never Debug + iter, + current_key, + current_elt, + done, + top_group, + oldest_buffered_group, + bottom_group, + buffer, + dropped_group + ); +} + impl GroupInner where I: Iterator, @@ -175,14 +197,11 @@ where while let Some(elt) = self.next_element() { let key = self.key.call_mut(&elt); - match self.current_key.take() { - None => {} - Some(old_key) => { - if old_key != key { - self.current_key = Some(key); - first_elt = Some(elt); - break; - } + if let Some(old_key) = self.current_key.take() { + if old_key != key { + self.current_key = Some(key); + first_elt = Some(elt); + break; } } self.current_key = Some(key); @@ -226,15 +245,12 @@ where None => None, Some(elt) => { let key = self.key.call_mut(&elt); - match self.current_key.take() { - None => {} - Some(old_key) => { - if old_key != key { - self.current_key = Some(key); - self.current_elt = Some(elt); - self.top_group += 1; - return None; - } + if let Some(old_key) = self.current_key.take() { + if old_key != key { + self.current_key = Some(key); + self.current_elt = Some(elt); + self.top_group += 1; + return None; } } self.current_key = Some(key); @@ -311,6 +327,15 @@ where index: Cell, } +impl Debug for ChunkBy +where + K: Debug, + I: Iterator + Debug, + I::Item: Debug, +{ + debug_fmt_fields!(ChunkBy, inner, index); +} + /// Create a new pub fn new(iter: J, f: F) -> ChunkBy where @@ -385,6 +410,15 @@ where parent: &'a ChunkBy, } +impl<'a, K, I, F> Debug for Groups<'a, K, I, F> +where + K: Debug, + I: Iterator + Debug, + I::Item: Debug, +{ + debug_fmt_fields!(Groups, parent); +} + impl<'a, K, I, F> Iterator for Groups<'a, K, I, F> where I: Iterator, @@ -438,6 +472,15 @@ where } } +impl<'a, K, I, F> Debug for Group<'a, K, I, F> +where + K: Debug, + I: Iterator + Debug, + I::Item: Debug, +{ + debug_fmt_fields!(Group, parent, index, first); +} + impl<'a, K, I, F> Iterator for Group<'a, K, I, F> where I: Iterator, @@ -479,7 +522,7 @@ where } } -/// `ChunkLazy` is the storage for a lazy chunking operation. +/// `IntoChunks` is the storage for a lazy chunking operation. /// /// `IntoChunks` behaves just like `ChunkBy`: it is iterable, and /// it only buffers if several chunk iterators are alive at the same time. @@ -503,6 +546,14 @@ where index: Cell, } +impl Debug for IntoChunks +where + I: Iterator + Debug, + I::Item: Debug, +{ + debug_fmt_fields!(IntoChunks, inner, index); +} + impl Clone for IntoChunks where I: Clone + Iterator, @@ -554,6 +605,14 @@ where parent: &'a IntoChunks, } +impl<'a, I> Debug for Chunks<'a, I> +where + I: Iterator + Debug, + I::Item: Debug, +{ + debug_fmt_fields!(Chunks, parent); +} + impl<'a, I> Iterator for Chunks<'a, I> where I: Iterator, @@ -577,6 +636,7 @@ where /// An iterator for the elements in a single chunk. /// /// Iterator element type is `I::Item`. +#[derive(Debug)] pub struct Chunk<'a, I> where I: Iterator + 'a, diff --git a/third_party/rust/itertools/src/grouping_map.rs b/third_party/rust/itertools/src/grouping_map.rs index 86cb55dc0077..11188a5fe225 100644 --- a/third_party/rust/itertools/src/grouping_map.rs +++ b/third_party/rust/itertools/src/grouping_map.rs @@ -2,11 +2,12 @@ use crate::{ adaptors::map::{MapSpecialCase, MapSpecialCaseFn}, MinMaxResult, }; -use std::cmp::Ordering; +use core::hash::BuildHasher; use std::collections::HashMap; use std::hash::Hash; use std::iter::Iterator; use std::ops::{Add, Mul}; +use std::{cmp::Ordering, collections::hash_map::RandomState}; /// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by) pub type MapForGrouping = MapSpecialCase>; @@ -36,18 +37,19 @@ pub(crate) fn new_map_for_grouping K>( } /// Creates a new `GroupingMap` from `iter` -pub fn new(iter: I) -> GroupingMap +pub fn new(iter: I, hash_builder: S) -> GroupingMap where I: Iterator, K: Hash + Eq, + S: BuildHasher, { - GroupingMap { iter } + GroupingMap { iter, hash_builder } } /// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations. /// -/// See [`GroupingMap`] for more informations. -pub type GroupingMapBy = GroupingMap>; +/// See [`GroupingMap`] for more information. +pub type GroupingMapBy = GroupingMap, S>; /// `GroupingMap` is an intermediate struct for efficient group-and-fold operations. /// It groups elements by their key and at the same time fold each group @@ -56,14 +58,19 @@ pub type GroupingMapBy = GroupingMap>; /// No method on this struct performs temporary allocations. #[derive(Clone, Debug)] #[must_use = "GroupingMap is lazy and do nothing unless consumed"] -pub struct GroupingMap { +pub struct GroupingMap +where + S: BuildHasher, +{ iter: I, + hash_builder: S, } -impl GroupingMap +impl GroupingMap where I: Iterator, K: Hash + Eq, + S: BuildHasher, { /// This is the generic way to perform any operation on a `GroupingMap`. /// It's suggested to use this method only to implement custom operations @@ -105,11 +112,11 @@ where /// assert_eq!(lookup[&3], 7); /// assert_eq!(lookup.len(), 3); // The final keys are only 0, 1 and 2 /// ``` - pub fn aggregate(self, mut operation: FO) -> HashMap + pub fn aggregate(self, mut operation: FO) -> HashMap where FO: FnMut(Option, &K, V) -> Option, { - let mut destination_map = HashMap::new(); + let mut destination_map = HashMap::with_hasher(self.hash_builder); self.iter.for_each(|(key, val)| { let acc = destination_map.remove(&key); @@ -139,7 +146,7 @@ where /// /// #[derive(Debug, Default)] /// struct Accumulator { - /// acc: usize, + /// acc: usize, /// } /// /// let lookup = (1..=7) @@ -154,7 +161,7 @@ where /// assert_eq!(lookup[&2].acc, 2 + 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn fold_with(self, mut init: FI, mut operation: FO) -> HashMap + pub fn fold_with(self, mut init: FI, mut operation: FO) -> HashMap where FI: FnMut(&K, &V) -> R, FO: FnMut(R, &K, V) -> R, @@ -190,7 +197,7 @@ where /// assert_eq!(lookup[&2], 2 + 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn fold(self, init: R, operation: FO) -> HashMap + pub fn fold(self, init: R, operation: FO) -> HashMap where R: Clone, FO: FnMut(R, &K, V) -> R, @@ -225,7 +232,7 @@ where /// assert_eq!(lookup[&2], 2 + 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn reduce(self, mut operation: FO) -> HashMap + pub fn reduce(self, mut operation: FO) -> HashMap where FO: FnMut(V, &K, V) -> V, { @@ -239,7 +246,7 @@ where /// See [`.reduce()`](GroupingMap::reduce). #[deprecated(note = "Use .reduce() instead", since = "0.13.0")] - pub fn fold_first(self, operation: FO) -> HashMap + pub fn fold_first(self, operation: FO) -> HashMap where FO: FnMut(V, &K, V) -> V, { @@ -264,11 +271,11 @@ where /// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::>()); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn collect(self) -> HashMap + pub fn collect(self) -> HashMap where C: Default + Extend, { - let mut destination_map = HashMap::new(); + let mut destination_map = HashMap::with_hasher(self.hash_builder); self.iter.for_each(|(key, val)| { destination_map @@ -298,7 +305,7 @@ where /// assert_eq!(lookup[&2], 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn max(self) -> HashMap + pub fn max(self) -> HashMap where V: Ord, { @@ -324,7 +331,7 @@ where /// assert_eq!(lookup[&2], 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn max_by(self, mut compare: F) -> HashMap + pub fn max_by(self, mut compare: F) -> HashMap where F: FnMut(&K, &V, &V) -> Ordering, { @@ -353,7 +360,7 @@ where /// assert_eq!(lookup[&2], 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn max_by_key(self, mut f: F) -> HashMap + pub fn max_by_key(self, mut f: F) -> HashMap where F: FnMut(&K, &V) -> CK, CK: Ord, @@ -379,7 +386,7 @@ where /// assert_eq!(lookup[&2], 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn min(self) -> HashMap + pub fn min(self) -> HashMap where V: Ord, { @@ -405,7 +412,7 @@ where /// assert_eq!(lookup[&2], 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn min_by(self, mut compare: F) -> HashMap + pub fn min_by(self, mut compare: F) -> HashMap where F: FnMut(&K, &V, &V) -> Ordering, { @@ -434,7 +441,7 @@ where /// assert_eq!(lookup[&2], 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn min_by_key(self, mut f: F) -> HashMap + pub fn min_by_key(self, mut f: F) -> HashMap where F: FnMut(&K, &V) -> CK, CK: Ord, @@ -458,7 +465,7 @@ where /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, OneElement}; /// /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter() /// .into_grouping_map_by(|&n| n % 3) @@ -469,7 +476,7 @@ where /// assert_eq!(lookup[&2], OneElement(5)); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn minmax(self) -> HashMap> + pub fn minmax(self) -> HashMap, S> where V: Ord, { @@ -488,7 +495,7 @@ where /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, OneElement}; /// /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter() /// .into_grouping_map_by(|&n| n % 3) @@ -499,7 +506,7 @@ where /// assert_eq!(lookup[&2], OneElement(5)); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn minmax_by(self, mut compare: F) -> HashMap> + pub fn minmax_by(self, mut compare: F) -> HashMap, S> where F: FnMut(&K, &V, &V) -> Ordering, { @@ -539,7 +546,7 @@ where /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, OneElement}; /// /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter() /// .into_grouping_map_by(|&n| n % 3) @@ -550,7 +557,7 @@ where /// assert_eq!(lookup[&2], OneElement(5)); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn minmax_by_key(self, mut f: F) -> HashMap> + pub fn minmax_by_key(self, mut f: F) -> HashMap, S> where F: FnMut(&K, &V) -> CK, CK: Ord, @@ -577,7 +584,7 @@ where /// assert_eq!(lookup[&2], 5 + 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn sum(self) -> HashMap + pub fn sum(self) -> HashMap where V: Add, { @@ -603,7 +610,7 @@ where /// assert_eq!(lookup[&2], 5 * 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn product(self) -> HashMap + pub fn product(self) -> HashMap where V: Mul, { diff --git a/third_party/rust/itertools/src/kmerge_impl.rs b/third_party/rust/itertools/src/kmerge_impl.rs index 9ea73f9e8b10..e40f8077e55a 100644 --- a/third_party/rust/itertools/src/kmerge_impl.rs +++ b/third_party/rust/itertools/src/kmerge_impl.rs @@ -80,7 +80,7 @@ where while child + 1 < heap.len() { // pick the smaller of the two children // use arithmetic to avoid an unpredictable branch - child += less_than(&heap[child + 1], &heap[child]) as usize; + child += usize::from(less_than(&heap[child + 1], &heap[child])); // sift down is done if we are already in order if !less_than(&heap[child], &heap[pos]) { @@ -97,7 +97,7 @@ where } } -/// An iterator adaptor that merges an abitrary number of base iterators in ascending order. +/// An iterator adaptor that merges an arbitrary number of base iterators in ascending order. /// If all base iterators are sorted (ascending), the result is sorted. /// /// Iterator element type is `I::Item`. @@ -146,7 +146,7 @@ where kmerge_by(iterable, KMergeByLt) } -/// An iterator adaptor that merges an abitrary number of base iterators +/// An iterator adaptor that merges an arbitrary number of base iterators /// according to an ordering function. /// /// Iterator element type is `I::Item`. diff --git a/third_party/rust/itertools/src/lib.rs b/third_party/rust/itertools/src/lib.rs index 20226d88a00a..804c7c45006b 100644 --- a/third_party/rust/itertools/src/lib.rs +++ b/third_party/rust/itertools/src/lib.rs @@ -1,4 +1,5 @@ #![warn(missing_docs, clippy::default_numeric_fallback)] +#![warn(missing_debug_implementations)] #![crate_name = "itertools"] #![cfg_attr(not(feature = "use_std"), no_std)] #![doc(test(attr(deny(warnings), allow(deprecated, unstable_name_collisions))))] @@ -63,11 +64,13 @@ use alloc::{collections::VecDeque, string::String, vec::Vec}; pub use either::Either; use core::borrow::Borrow; +#[cfg(feature = "use_std")] +use core::hash::BuildHasher; use std::cmp::Ordering; #[cfg(feature = "use_std")] -use std::collections::HashMap; -#[cfg(feature = "use_std")] use std::collections::HashSet; +#[cfg(feature = "use_std")] +use std::collections::{hash_map::RandomState, HashMap}; use std::fmt; #[cfg(feature = "use_alloc")] use std::fmt::Write; @@ -96,6 +99,8 @@ pub mod structs { FilterOk, Interleave, InterleaveShortest, MapInto, MapOk, Positions, Product, PutBack, TakeWhileRef, TupleCombinations, Update, WhileSome, }; + pub use crate::all_equal_value_err::AllEqualValueError; + pub use crate::array_impl::{ArrayWindows, CircularArrayWindows}; #[cfg(feature = "use_alloc")] pub use crate::combinations::{ArrayCombinations, Combinations}; #[cfg(feature = "use_alloc")] @@ -153,6 +158,8 @@ pub mod traits { pub use crate::tuple_impl::HomogeneousTuple; } +#[cfg(feature = "use_alloc")] +use crate::combinations_with_replacement::ArrayCombinationsWithReplacement; pub use crate::concat_impl::concat; pub use crate::cons_tuples_impl::cons_tuples; pub use crate::diff::diff_with; @@ -171,12 +178,14 @@ pub use crate::unziptuple::{multiunzip, MultiUnzip}; pub use crate::with_position::Position; pub use crate::ziptuple::multizip; mod adaptors; +mod array_impl; mod either_or_both; pub use crate::either_or_both::EitherOrBoth; #[doc(hidden)] pub mod free; #[doc(inline)] pub use crate::free::*; +mod all_equal_value_err; #[cfg(feature = "use_alloc")] mod combinations; #[cfg(feature = "use_alloc")] @@ -321,14 +330,27 @@ macro_rules! iproduct { macro_rules! izip { // @closure creates a tuple-flattening closure for .map() call. usage: // @closure partial_pattern => partial_tuple , rest , of , iterators - // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee ) + // eg. izip!( @closure (a, (b, c)) => (a, b, c) , dd , ee ) ( @closure $p:pat => $tup:expr ) => { |$p| $tup }; // The "b" identifier is a different identifier on each recursion level thanks to hygiene. ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => { - $crate::izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*) + $crate::izip!(@closure (b, $p) => ( b, $($tup)* ) $( , $tail )*) + }; + + // Inner recursion of the macro without final map adapter, base case + ( @ no_map @ $first:expr $(,)?) => { + $crate::__std_iter::IntoIterator::into_iter($first) + }; + + // Inner recursion of the macro without final map adapter, recursive case + ( @ no_map @ $first:expr, $($rest:expr),+ $(,)?) => { + $crate::__std_iter::Iterator::zip( + $crate::__std_iter::IntoIterator::into_iter($first), + $crate::izip!(@ no_map @ $($rest),+) + ) }; // unary @@ -346,16 +368,13 @@ macro_rules! izip { // n-ary where n > 2 ( $first:expr $( , $rest:expr )* $(,)* ) => { - { - let iter = $crate::__std_iter::IntoIterator::into_iter($first); - $( - let iter = $crate::__std_iter::Iterator::zip(iter, $rest); - )* - $crate::__std_iter::Iterator::map( - iter, - $crate::izip!(@closure a => (a) $( , $rest )*) - ) - } + $crate::__std_iter::Iterator::map( + $crate::__std_iter::Iterator::zip( + $crate::__std_iter::IntoIterator::into_iter($first), + $crate::izip!(@ no_map @ $($rest),+) + ), + $crate::izip!(@closure a => (a) $( , $rest )*) + ) }; } @@ -371,8 +390,8 @@ macro_rules! izip { /// /// Empty invocations of `chain!` expand to an invocation of [`std::iter::empty`]: /// ``` -/// use std::iter; /// use itertools::chain; +/// use std::iter; /// /// let _: iter::Empty<()> = chain!(); /// let _: iter::Empty = chain!(); @@ -380,8 +399,8 @@ macro_rules! izip { /// /// Invocations of `chain!` with one argument expand to [`arg.into_iter()`](IntoIterator): /// ``` -/// use std::ops::Range; /// use itertools::chain; +/// use std::ops::Range; /// let _: as IntoIterator>::IntoIter = chain!(2..6,); // trailing comma optional! /// let _: <&[_] as IntoIterator>::IntoIter = chain!(&[2, 3, 4]); /// ``` @@ -389,11 +408,11 @@ macro_rules! izip { /// Invocations of `chain!` with multiple arguments [`.into_iter()`](IntoIterator) each /// argument, and then [`chain`] them together: /// ``` -/// use std::{iter::*, slice}; /// use itertools::{assert_equal, chain}; +/// use std::{iter::*, slice}; /// /// // e.g., this: -/// let with_macro: Chain, Take>>, slice::Iter<_>> = +/// let with_macro: Chain, Take>>, slice::Iter<_>> = /// chain![once(&0), repeat(&1).take(2), &[2, 3, 5],]; /// /// // ...is equivalent to this: @@ -609,6 +628,28 @@ pub trait Itertools: Iterator { /// /// **Panics** if the iterators reach an end and they are not of equal /// lengths. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a = vec![1, 2]; + /// let b = vec![3, 4]; + /// + /// let zipped: Vec<_> = a.into_iter().zip_eq(b.into_iter()).collect(); + /// + /// itertools::assert_equal(zipped, vec![(1, 3), (2, 4)]); + /// ``` + /// + /// ```should_panic + /// use itertools::Itertools; + /// + /// let a = [1, 2]; + /// let b = [3, 4, 5]; + /// // This example panics because the iterators are not of equal length. + /// let _zipped: Vec<_> = a.iter().zip_eq(b.iter()).collect(); + /// ``` #[inline] fn zip_eq(self, other: J) -> ZipEq where @@ -640,7 +681,6 @@ pub trait Itertools: Iterator { /// /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]); /// ``` - /// fn batching(self, f: F) -> Batching where F: FnMut(&mut Self) -> Option, @@ -719,6 +759,8 @@ pub trait Itertools: Iterator { /// /// **Panics** if `size` is 0. /// + /// # Examples + /// /// ``` /// use itertools::Itertools; /// @@ -732,6 +774,13 @@ pub trait Itertools: Iterator { /// assert_eq!(4, chunk.sum()); /// } /// ``` + /// + /// ```should_panic + /// use itertools::Itertools; + /// let data = vec![1, 2, 3]; + /// // Panics because chunk size is 0. + /// let _chunks = data.into_iter().chunks(0); + /// ``` #[cfg(feature = "use_alloc")] fn chunks(self, size: usize) -> IntoChunks where @@ -857,10 +906,130 @@ pub trait Itertools: Iterator { tuple_impl::tuples(self) } + /// Return an iterator over all contiguous windows, producing + /// arrays of size `N`. + /// + /// `array_windows` clones the iterator elements so that they can be + /// part of successive windows. This makes it most suited for iterators + /// of references and other values that are cheap to copy. + /// + /// If the input iterator contains fewer than `N` items, no + /// windows are returned. Otherwise, if the input iterator + /// contains `k` items, exactly `k+N-1` windows are returned. + /// + /// (This formula still applies when `N==0`, and means that `k+1` + /// zero-length windows are returned for `k` input items.) + /// + /// ``` + /// use itertools::Itertools; + /// + /// // Three-element windows from the items [1, 2, 3, 4, 5]. + /// itertools::assert_equal( + /// (1..6).array_windows::<3>(), + /// vec![[1, 2, 3], [2, 3, 4], [3, 4, 5]] + /// ); + /// + /// // When the input list is shorter than the window size, no windows + /// // are returned at all. + /// let mut windows = (1..6).array_windows::<10>(); + /// assert_eq!(None, windows.next()); + /// + /// // When the window size is zero, one more window is returned + /// // than there are items. + /// itertools::assert_equal((1..6).array_windows::<0>(), vec![[]; 6]); + /// + /// // In some cases you don't have to specify the window size + /// // explicitly with a type hint, because Rust can infer it + /// for [a, b, c] in (1..6).array_windows() { + /// println!("{a} {b} {c}"); + /// } + /// ``` + fn array_windows(self) -> ArrayWindows + where + Self: Sized, + Self::Item: Clone, + { + array_impl::array_windows(self) + } + + /// Return an iterator over all windows, wrapping back to the first + /// elements when the window would otherwise exceed the length of the + /// iterator, producing arrays of size `N`. + /// + /// `circular_array_windows` clones the iterator elements so that + /// they can be part of successive windows, this makes it most + /// suited for iterators of references and other values that are + /// cheap to copy. + /// + /// One window is returned per element of the input iterator. This + /// is true even if the input contains fewer elements than the + /// window size. In that situation, input elements are repeated + /// within each window. The results are as if the input had been + /// treated as a cyclic list, and a window of `N` items had been + /// returned for every starting point in the cycle. + /// + /// (If the window size is zero, the function _still_ returns one + /// empty window per element of the input iterator.) + /// + /// ``` + /// use itertools::Itertools; + /// + /// // Three-element windows from [1, 2, 3, 4, 5], with two of + /// // them wrapping round from 5 to 1. + /// itertools::assert_equal( + /// (1..6).circular_array_windows::<3>(), + /// vec![[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 1], [5, 1, 2]] + /// ); + /// + /// // If the input is shorter than the window size, input + /// // items are repeated even within the same window. + /// itertools::assert_equal( + /// (1..3).circular_array_windows::<5>(), + /// vec![[1, 2, 1, 2, 1], [2, 1, 2, 1, 2]] + /// ); + /// + /// // If the input contains only one item, the returned window + /// // repeats it N times. + /// let once = std::iter::once(1); + /// itertools::assert_equal( + /// once.circular_array_windows::<3>(), + /// vec![[1, 1, 1]] + /// ); + /// + /// // If the input is empty, no windows are returned at all. + /// let empty = std::iter::empty::(); + /// let mut windows = empty.circular_array_windows::<5>(); + /// assert_eq!(None, windows.next()); + /// + /// // If the input is empty, no windows are returned at all. + /// let empty = std::iter::empty::(); + /// let mut windows = empty.circular_array_windows::<5>(); + /// assert_eq!(None, windows.next()); + /// + /// // One window is returned per item, even if the windows are empty. + /// itertools::assert_equal( + /// (1..6).circular_array_windows::<0>(), + /// vec![[]; 5] + /// ); + /// + /// // In some cases you don't have to specify the window size + /// // explicitly with a type hint, because Rust can infer it. + /// for [a, b, c] in (1..10).circular_array_windows() { + /// println!("{a} {b} {c}"); + /// } + /// ``` + fn circular_array_windows(self) -> CircularArrayWindows + where + Self: Sized, + Self::Item: Clone, + { + array_impl::circular_array_windows(self) + } + /// Split into an iterator pair that both yield all elements from /// the original iterator. /// - /// **Note:** If the iterator is clonable, prefer using that instead + /// **Note:** If the iterator is cloneable, prefer using that instead /// of using this method. Cloning is likely to be more efficient. /// /// Iterator element type is `Self::Item`. @@ -888,7 +1057,10 @@ pub trait Itertools: Iterator { /// ```rust /// use itertools::Itertools; /// - /// (1i32..42i32).map_into::().collect_vec(); + /// assert_eq!( + /// (1i32..4i32).map_into::().collect_vec(), + /// vec![1f64, 2f64, 3f64] + /// ); /// ``` fn map_into(self) -> MapInto where @@ -988,7 +1160,7 @@ pub trait Itertools: Iterator { /// as long as the original iterator produces `Ok` values. /// /// If the original iterable produces an error at any point, the adapted - /// iterator ends and it will return the error iself. + /// iterator ends and it will return the error itself. /// /// Otherwise, the return value from the closure is returned wrapped /// inside `Ok`. @@ -1084,8 +1256,8 @@ pub trait Itertools: Iterator { /// and remove both `i` and `j` from their respective source iterators /// /// ``` + /// use itertools::EitherOrBoth::{Both, Left, Right}; /// use itertools::Itertools; - /// use itertools::EitherOrBoth::{Left, Right, Both}; /// /// let a = vec![0, 2, 4, 6, 1].into_iter(); /// let b = (0..10).step_by(3); @@ -1113,8 +1285,8 @@ pub trait Itertools: Iterator { /// "less" than the second argument. /// /// ``` - /// use itertools::Itertools; /// use itertools::Either::{Left, Right}; + /// use itertools::Itertools; /// /// let a = vec![0, 2, 4, 6, 1].into_iter(); /// let b = (0..10).step_by(3); @@ -1136,7 +1308,7 @@ pub trait Itertools: Iterator { } /// Return an iterator adaptor that flattens an iterator of iterators by - /// merging them in ascending order. + /// merging them in ascending order. Duplicates are preserved. /// /// If all base iterators are sorted (ascending), the result is sorted. /// @@ -1145,11 +1317,12 @@ pub trait Itertools: Iterator { /// ``` /// use itertools::Itertools; /// - /// let a = (0..6).step_by(3); - /// let b = (1..6).step_by(3); - /// let c = (2..6).step_by(3); + /// let a = (0..6).step_by(3); // [0, 3] + /// let b = (1..6).step_by(2); // [1, 3, 5 ] + /// let c = (2..6).step_by(3); // [2, 5] + /// /// let it = vec![a, b, c].into_iter().kmerge(); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5]); + /// itertools::assert_equal(it, vec![0, 1, 2, 3, 3, 5, 5]); /// ``` #[cfg(feature = "use_alloc")] fn kmerge(self) -> KMerge<::IntoIter> @@ -1406,7 +1579,33 @@ pub trait Itertools: Iterator { Self: Sized, Self::Item: Eq + Hash, { - duplicates_impl::duplicates(self) + duplicates_impl::duplicates_with_hasher(self, RandomState::new()) + } + + /// Return an iterator which yields the same elements as the one returned by + /// [.duplicates()](crate::Itertools::duplicates), but uses the specified hash builder to hash + /// the elements for comparison. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's + /// users to be resistant to attacks that cause many collisions and very poor performance. + /// Setting it manually using this function can expose a DoS attack vector. + /// + /// ``` + /// use std::hash::RandomState; + /// use itertools::Itertools; + /// + /// let data = vec![10, 20, 30, 20, 40, 10, 50]; + /// itertools::assert_equal(data.into_iter().duplicates_with_hasher(RandomState::new()), + /// vec![20,10]); + /// ``` + #[cfg(feature = "use_std")] + fn duplicates_with_hasher(self, hash_builder: S) -> Duplicates + where + Self: Sized, + Self::Item: Eq + Hash, + S: BuildHasher, + { + duplicates_impl::duplicates_with_hasher(self, hash_builder) } /// Return an iterator adaptor that produces elements that appear more than once during the @@ -1433,7 +1632,38 @@ pub trait Itertools: Iterator { V: Eq + Hash, F: FnMut(&Self::Item) -> V, { - duplicates_impl::duplicates_by(self, f) + duplicates_impl::duplicates_by_with_hasher(self, f, RandomState::new()) + } + + /// Return an iterator which yields the same elements as the one returned by + /// [.duplicates_by()](crate::Itertools::duplicates_by), but uses the specified hash builder to + /// hash the keys for comparison. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's + /// users to be resistant to attacks that cause many collisions and very poor performance. + /// Setting it manually using this function can expose a DoS attack vector. + /// + /// ``` + /// use std::hash::RandomState; + /// use itertools::Itertools; + /// + /// let data = vec!["a", "bb", "aa", "c", "ccc"]; + /// itertools::assert_equal(data.into_iter().duplicates_by_with_hasher(|s| s.len(),RandomState::new()), + /// vec!["aa", "c"]); + /// ``` + #[cfg(feature = "use_std")] + fn duplicates_by_with_hasher( + self, + f: F, + hash_builder: S, + ) -> DuplicatesBy + where + Self: Sized, + V: Eq + Hash, + F: FnMut(&Self::Item) -> V, + S: BuildHasher, + { + duplicates_impl::duplicates_by_with_hasher(self, f, hash_builder) } /// Return an iterator adaptor that filters out elements that have @@ -1460,7 +1690,33 @@ pub trait Itertools: Iterator { Self: Sized, Self::Item: Clone + Eq + Hash, { - unique_impl::unique(self) + unique_impl::unique_with_hasher(self, RandomState::new()) + } + + /// Return an iterator which yields the same elements as the one returned by + /// [.unique()](crate::Itertools::unique), but uses the specified hash builder to hash the + /// elements for comparison. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's + /// users to be resistant to attacks that cause many collisions and very poor performance. + /// Setting it manually using this function can expose a DoS attack vector. + /// + /// ``` + /// use std::hash::RandomState; + /// use itertools::Itertools; + /// + /// let data = vec![10, 20, 30, 20, 40, 10, 50]; + /// itertools::assert_equal(data.into_iter().unique_with_hasher(RandomState::new()), + /// vec![10, 20, 30, 40, 50]); + /// ``` + #[cfg(feature = "use_std")] + fn unique_with_hasher(self, hash_builder: S) -> Unique + where + Self: Sized, + Self::Item: Clone + Eq + Hash, + S: BuildHasher, + { + unique_impl::unique_with_hasher(self, hash_builder) } /// Return an iterator adaptor that filters out elements that have @@ -1488,7 +1744,34 @@ pub trait Itertools: Iterator { V: Eq + Hash, F: FnMut(&Self::Item) -> V, { - unique_impl::unique_by(self, f) + unique_impl::unique_by_with_hasher(self, f, RandomState::new()) + } + + /// Return an iterator which yields the same elements as the one returned by + /// [.unique_by()](crate::Itertools::unique_by), but uses the specified hash builder to hash + /// the elements for comparison. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's + /// users to be resistant to attacks that cause many collisions and very poor performance. + /// Setting it manually using this function can expose a DoS attack vector. + /// + /// ``` + /// use std::hash::RandomState; + /// use itertools::Itertools; + /// + /// let data = vec!["a", "bb", "aa", "c", "ccc"]; + /// itertools::assert_equal(data.into_iter().unique_by_with_hasher(|s| s.len(), RandomState::new()), + /// vec!["a", "bb", "ccc"]); + /// ``` + #[cfg(feature = "use_std")] + fn unique_by_with_hasher(self, f: F, hash_builder: S) -> UniqueBy + where + Self: Sized, + V: Eq + Hash, + F: FnMut(&Self::Item) -> V, + S: BuildHasher, + { + unique_impl::unique_by_with_hasher(self, f, hash_builder) } /// Return an iterator adaptor that borrows from this iterator and @@ -1503,7 +1786,7 @@ pub trait Itertools: Iterator { /// /// See also [`.take_while_ref()`](Itertools::take_while_ref) /// which is a similar adaptor. - fn peeking_take_while(&mut self, accept: F) -> PeekingTakeWhile + fn peeking_take_while(&mut self, accept: F) -> PeekingTakeWhile<'_, Self, F> where Self: Sized + PeekingNext, F: FnMut(&Self::Item) -> bool, @@ -1527,9 +1810,8 @@ pub trait Itertools: Iterator { /// .collect::(); /// assert_eq!(decimals, "0123456789"); /// assert_eq!(hexadecimals.next(), Some('a')); - /// /// ``` - fn take_while_ref(&mut self, accept: F) -> TakeWhileRef + fn take_while_ref(&mut self, accept: F) -> TakeWhileRef<'_, Self, F> where Self: Clone, F: FnMut(&Self::Item) -> bool, @@ -1587,11 +1869,11 @@ pub trait Itertools: Iterator { /// #[derive(Debug, PartialEq)] /// struct NoCloneImpl(i32); /// - /// let non_clonable_items: Vec<_> = vec![1, 2, 3, 4, 5] + /// let non_cloneable_items: Vec<_> = vec![1, 2, 3, 4, 5] /// .into_iter() /// .map(NoCloneImpl) /// .collect(); - /// let filtered: Vec<_> = non_clonable_items + /// let filtered: Vec<_> = non_cloneable_items /// .into_iter() /// .take_while_inclusive(|n| n.0 % 3 != 0) /// .collect(); @@ -1617,8 +1899,8 @@ pub trait Itertools: Iterator { /// // List all hexadecimal digits /// itertools::assert_equal( /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), - /// "0123456789abcdef".chars()); - /// + /// "0123456789abcdef".chars(), + /// ); /// ``` fn while_some(self) -> WhileSome where @@ -1665,9 +1947,10 @@ pub trait Itertools: Iterator { /// let it: TupleCombinations, (u32, u32, u32)> = (1..5).tuple_combinations(); /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); /// ``` + #[deprecated(note = "Use .array_combinations() instead", since = "0.15.0")] fn tuple_combinations(self) -> TupleCombinations where - Self: Sized + Clone, + Self: Sized, Self::Item: Clone, T: adaptors::HasCombination, { @@ -1715,7 +1998,7 @@ pub trait Itertools: Iterator { #[cfg(feature = "use_alloc")] fn array_combinations(self) -> ArrayCombinations where - Self: Sized + Clone, + Self: Sized, Self::Item: Clone, { combinations::array_combinations(self) @@ -1791,7 +2074,35 @@ pub trait Itertools: Iterator { { combinations_with_replacement::combinations_with_replacement(self, k) } - + /// Return an iterator that iterates over the `k`-length combinations of + /// the elements from an iterator, with replacement. + /// + /// Iterator element type is [Self::Item; K]. The iterator produces a new + /// array per iteration, and clones the iterator elements. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (1..4).array_combinations_with_replacement::<2>(); + /// itertools::assert_equal(it, vec![ + /// [1, 1], + /// [1, 2], + /// [1, 3], + /// [2, 2], + /// [2, 3], + /// [3, 3], + /// ]); + /// ``` + #[cfg(feature = "use_alloc")] + fn array_combinations_with_replacement( + self, + ) -> ArrayCombinationsWithReplacement + where + Self: Sized, + Self::Item: Clone, + { + combinations_with_replacement::array_combinations_with_replacement(self) + } /// Return an iterator adaptor that iterates over all k-permutations of the /// elements from an iterator. /// @@ -1886,13 +2197,13 @@ pub trait Itertools: Iterator { /// ``` /// use itertools::Itertools; /// - /// let it = (0..5).pad_using(10, |i| 2*i); + /// let it = (0..5).pad_using(10, |i| 2 * i); /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 10, 12, 14, 16, 18]); /// - /// let it = (0..10).pad_using(5, |i| 2*i); + /// let it = (0..10).pad_using(5, |i| 2 * i); /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// - /// let it = (0..5).pad_using(10, |i| 2*i).rev(); + /// let it = (0..5).pad_using(10, |i| 2 * i).rev(); /// itertools::assert_equal(it, vec![18, 16, 14, 12, 10, 4, 3, 2, 1, 0]); /// ``` fn pad_using(self, min: usize, f: F) -> PadUsing @@ -1903,8 +2214,8 @@ pub trait Itertools: Iterator { pad_tail::pad_using(self, min, f) } - /// Return an iterator adaptor that combines each element with a `Position` to - /// ease special-case handling of the first or last elements. + /// Return an iterator adaptor that combines each element with a `Position` + /// to ease special-case handling of the first or last elements. /// /// Iterator element type is /// [`(Position, Self::Item)`](Position) @@ -1913,14 +2224,21 @@ pub trait Itertools: Iterator { /// use itertools::{Itertools, Position}; /// /// let it = (0..4).with_position(); - /// itertools::assert_equal(it, - /// vec![(Position::First, 0), - /// (Position::Middle, 1), - /// (Position::Middle, 2), - /// (Position::Last, 3)]); + /// itertools::assert_equal( + /// it, + /// vec![ + /// (Position { is_first: true, is_last: false }, 0), + /// (Position { is_first: false, is_last: false }, 1), + /// (Position { is_first: false, is_last: false }, 2), + /// (Position { is_first: false, is_last: true }, 3), + /// ], + /// ); /// /// let it = (0..1).with_position(); - /// itertools::assert_equal(it, vec![(Position::Only, 0)]); + /// itertools::assert_equal( + /// it, + /// vec![(Position { is_first: true, is_last: true }, 0)], + /// ); /// ``` fn with_position(self) -> WithPosition where @@ -2199,7 +2517,7 @@ pub trait Itertools: Iterator { /// assert!(data[3..5].iter().all_equal()); /// assert!(data[5..8].iter().all_equal()); /// - /// let data : Option = None; + /// let data: Option = None; /// assert!(data.into_iter().all_equal()); /// ``` fn all_equal(&mut self) -> bool @@ -2219,27 +2537,27 @@ pub trait Itertools: Iterator { /// two non-equal elements found. /// /// ``` - /// use itertools::Itertools; + /// use itertools::{Itertools, AllEqualValueError}; /// /// let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5]; - /// assert_eq!(data.iter().all_equal_value(), Err(Some((&1, &2)))); + /// assert_eq!(data.iter().all_equal_value(), Err(AllEqualValueError(Some([&1, &2])))); /// assert_eq!(data[0..3].iter().all_equal_value(), Ok(&1)); /// assert_eq!(data[3..5].iter().all_equal_value(), Ok(&2)); /// assert_eq!(data[5..8].iter().all_equal_value(), Ok(&3)); /// - /// let data : Option = None; - /// assert_eq!(data.into_iter().all_equal_value(), Err(None)); + /// let data: Option = None; + /// assert_eq!(data.into_iter().all_equal_value(), Err(AllEqualValueError(None))); /// ``` #[allow(clippy::type_complexity)] - fn all_equal_value(&mut self) -> Result> + fn all_equal_value(&mut self) -> Result> where Self: Sized, Self::Item: PartialEq, { - let first = self.next().ok_or(None)?; + let first = self.next().ok_or(AllEqualValueError(None))?; let other = self.find(|x| x != &first); if let Some(other) = other { - Err(Some((first, other))) + Err(AllEqualValueError(Some([first, other]))) } else { Ok(first) } @@ -2257,7 +2575,7 @@ pub trait Itertools: Iterator { /// assert!(data[0..4].iter().all_unique()); /// assert!(data[1..6].iter().all_unique()); /// - /// let data : Option = None; + /// let data: Option = None; /// assert!(data.into_iter().all_unique()); /// ``` #[cfg(feature = "use_std")] @@ -2266,7 +2584,32 @@ pub trait Itertools: Iterator { Self: Sized, Self::Item: Eq + Hash, { - let mut used = HashSet::new(); + self.all_unique_with_hasher(RandomState::new()) + } + + /// Check whether all elements are unique (non equal). The specified hash builder is used for + /// hashing the elements. See [.all_unique](crate::Itertools::all_unique). + /// + /// ``` + /// use std::hash::RandomState; + /// use itertools::Itertools; + /// + /// let data = vec![1, 2, 3, 4, 1, 5]; + /// assert!(!data.iter().all_unique_with_hasher(RandomState::new())); + /// assert!(data[0..4].iter().all_unique_with_hasher(RandomState::new())); + /// assert!(data[1..6].iter().all_unique_with_hasher(RandomState::new())); + /// + /// let data : Option = None; + /// assert!(data.into_iter().all_unique_with_hasher(RandomState::new())); + /// ``` + #[cfg(feature = "use_std")] + fn all_unique_with_hasher(&mut self, hash_builder: S) -> bool + where + Self: Sized, + Self::Item: Eq + Hash, + S: BuildHasher, + { + let mut used = HashSet::with_hasher(hash_builder); self.all(move |elt| used.insert(elt)) } @@ -2344,6 +2687,7 @@ pub trait Itertools: Iterator { /// `.collect_vec()` is simply a type specialization of [`Iterator::collect`], /// for convenience. + #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] #[cfg(feature = "use_alloc")] fn collect_vec(self) -> Vec where @@ -2358,8 +2702,8 @@ pub trait Itertools: Iterator { /// # Example /// /// ``` - /// use std::{fs, io}; /// use itertools::Itertools; + /// use std::{fs, io}; /// /// fn process_dir_entries(entries: &[fs::DirEntry]) { /// // ... @@ -2431,10 +2775,10 @@ pub trait Itertools: Iterator { // estimate lower bound of capacity needed let (lower, _) = self.size_hint(); let mut result = String::with_capacity(sep.len() * lower); - write!(&mut result, "{}", first_elt).unwrap(); + write!(&mut result, "{first_elt}").unwrap(); self.for_each(|elt| { result.push_str(sep); - write!(&mut result, "{}", elt).unwrap(); + write!(&mut result, "{elt}").unwrap(); }); result } @@ -2456,7 +2800,7 @@ pub trait Itertools: Iterator { /// format!("{:.2}", data.iter().format(", ")), /// "1.10, 2.72, -3.00"); /// ``` - fn format(self, sep: &str) -> Format + fn format(self, sep: &str) -> Format<'_, Self> where Self: Sized, { @@ -2495,7 +2839,7 @@ pub trait Itertools: Iterator { /// /// /// ``` - fn format_with(self, sep: &str, format: F) -> FormatWith + fn format_with(self, sep: &str, format: F) -> FormatWith<'_, Self, F> where Self: Sized, F: FnMut(Self::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result, @@ -2531,8 +2875,8 @@ pub trait Itertools: Iterator { /// this effectively results in *((0 + 1) + 2) + 3* /// /// ``` - /// use std::ops::Add; /// use itertools::Itertools; + /// use std::ops::Add; /// /// let values = [1, 2, -2, -1, 2, 1]; /// assert_eq!( @@ -2571,8 +2915,8 @@ pub trait Itertools: Iterator { /// This is the `Option` equivalent to [`fold_ok`](Itertools::fold_ok). /// /// ``` - /// use std::ops::Add; /// use itertools::Itertools; + /// use std::ops::Add; /// /// let mut values = vec![Some(1), Some(2), Some(-2)].into_iter(); /// assert_eq!(values.fold_options(5, Add::add), Some(5 + 1 + 2 - 2)); @@ -2787,8 +3131,8 @@ pub trait Itertools: Iterator { /// early exit via short-circuiting. /// /// ``` - /// use itertools::Itertools; /// use itertools::FoldWhile::{Continue, Done}; + /// use itertools::Itertools; /// /// let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; /// @@ -2825,7 +3169,7 @@ pub trait Itertools: Iterator { Self: Sized, F: FnMut(B, Self::Item) -> FoldWhile, { - use Result::{Err as Break, Ok as Continue}; + use core::ops::ControlFlow::{Break, Continue}; let result = self.try_fold( init, @@ -3617,7 +3961,7 @@ pub trait Itertools: Iterator { /// have a distinct type. /// /// ``` - /// use itertools::{Itertools, Either}; + /// use itertools::{Either, Itertools}; /// /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)]; /// @@ -3700,7 +4044,36 @@ pub trait Itertools: Iterator { Self: Iterator + Sized, K: Hash + Eq, { - group_map::into_group_map(self) + group_map::into_group_map_with_hasher(self, RandomState::new()) + } + + /// Return a `HashMap` of keys mapped to `Vec`s of values, using the hash builder for hashing. + /// See [.into_group_map()](crate::Itertools::into_group_map) for more information. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's + /// users to be resistant to attacks that cause many collisions and very poor performance. + /// Setting it manually using this function can expose a DoS attack vector. + /// + /// ``` + /// use std::hash::RandomState; + /// use itertools::Itertools; + /// + /// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)]; + /// let lookup = data.into_iter().into_group_map_with_hasher(RandomState::new()); + /// + /// assert_eq!(lookup[&0], vec![10, 20]); + /// assert_eq!(lookup.get(&1), None); + /// assert_eq!(lookup[&2], vec![12, 42]); + /// assert_eq!(lookup[&3], vec![13, 33]); + /// ``` + #[cfg(feature = "use_std")] + fn into_group_map_with_hasher(self, hash_builder: S) -> HashMap, S> + where + Self: Iterator + Sized, + K: Hash + Eq, + S: BuildHasher, + { + group_map::into_group_map_with_hasher(self, hash_builder) } /// Return a `HashMap` of keys mapped to `Vec`s of values. The key is specified @@ -3716,17 +4089,17 @@ pub trait Itertools: Iterator { /// let lookup: HashMap> = /// data.clone().into_iter().into_group_map_by(|a| a.0); /// - /// assert_eq!(lookup[&0], vec![(0,10), (0,20)]); + /// assert_eq!(lookup[&0], vec![(0, 10), (0, 20)]); /// assert_eq!(lookup.get(&1), None); - /// assert_eq!(lookup[&2], vec![(2,12), (2,42)]); - /// assert_eq!(lookup[&3], vec![(3,13), (3,33)]); + /// assert_eq!(lookup[&2], vec![(2, 12), (2, 42)]); + /// assert_eq!(lookup[&3], vec![(3, 13), (3, 33)]); /// /// assert_eq!( /// data.into_iter() /// .into_group_map_by(|x| x.0) /// .into_iter() - /// .map(|(key, values)| (key, values.into_iter().fold(0,|acc, (_,v)| acc + v ))) - /// .collect::>()[&0], + /// .map(|(key, values)| (key, values.into_iter().fold(0, |acc, (_, v)| acc + v))) + /// .collect::>()[&0], /// 30, /// ); /// ``` @@ -3737,7 +4110,52 @@ pub trait Itertools: Iterator { K: Hash + Eq, F: FnMut(&V) -> K, { - group_map::into_group_map_by(self, f) + group_map::into_group_map_by_with_hasher(self, f, RandomState::new()) + } + + /// Return a `HashMap` of keys mapped to `Vec`s of values, using the hash builder for hashing. + /// See [.into_group_map_by()](crate::Itertools::into_group_map_by) for more information. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's + /// users to be resistant to attacks that cause many collisions and very poor performance. + /// Setting it manually using this function can expose a DoS attack vector. + /// + /// ``` + /// use itertools::Itertools; + /// use std::collections::HashMap; + /// use std::hash::RandomState; + /// + /// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)]; + /// let lookup: HashMap, RandomState> = + /// data.clone().into_iter().into_group_map_by_with_hasher(|a| a.0, RandomState::new()); + /// + /// assert_eq!(lookup[&0], vec![(0,10), (0,20)]); + /// assert_eq!(lookup.get(&1), None); + /// assert_eq!(lookup[&2], vec![(2,12), (2,42)]); + /// assert_eq!(lookup[&3], vec![(3,13), (3,33)]); + /// + /// assert_eq!( + /// data.into_iter() + /// .into_group_map_by_with_hasher(|x| x.0, RandomState::new()) + /// .into_iter() + /// .map(|(key, values)| (key, values.into_iter().fold(0,|acc, (_,v)| acc + v ))) + /// .collect::>()[&0], + /// 30, + /// ); + /// ``` + #[cfg(feature = "use_std")] + fn into_group_map_by_with_hasher( + self, + f: F, + hash_builder: S, + ) -> HashMap, S> + where + Self: Iterator + Sized, + K: Hash + Eq, + F: FnMut(&V) -> K, + S: BuildHasher, + { + group_map::into_group_map_by_with_hasher(self, f, hash_builder) } /// Constructs a `GroupingMap` to be used later with one of the efficient @@ -3747,7 +4165,7 @@ pub trait Itertools: Iterator { /// value of type `K` will be used as key to identify the groups and the /// value of type `V` as value for the folding operation. /// - /// See [`GroupingMap`] for more informations + /// See [`GroupingMap`] for more information /// on what operations are available. #[cfg(feature = "use_std")] fn into_grouping_map(self) -> GroupingMap @@ -3755,7 +4173,21 @@ pub trait Itertools: Iterator { Self: Iterator + Sized, K: Hash + Eq, { - grouping_map::new(self) + grouping_map::new(self, RandomState::new()) + } + + /// Constructs a `GroupingMap` to be used later with one of the efficient + /// group-and-fold operations it allows to perform, using the specified hash builder for + /// hashing the elements. + /// See [.into_grouping_map()](crate::Itertools::into_grouping_map) for more information. + #[cfg(feature = "use_std")] + fn into_grouping_map_with_hasher(self, hash_builder: S) -> GroupingMap + where + Self: Iterator + Sized, + K: Hash + Eq, + S: BuildHasher, + { + grouping_map::new(self, hash_builder) } /// Constructs a `GroupingMap` to be used later with one of the efficient @@ -3764,7 +4196,7 @@ pub trait Itertools: Iterator { /// The values from this iterator will be used as values for the folding operation /// while the keys will be obtained from the values by calling `key_mapper`. /// - /// See [`GroupingMap`] for more informations + /// See [`GroupingMap`] for more information /// on what operations are available. #[cfg(feature = "use_std")] fn into_grouping_map_by(self, key_mapper: F) -> GroupingMapBy @@ -3773,7 +4205,32 @@ pub trait Itertools: Iterator { K: Hash + Eq, F: FnMut(&V) -> K, { - grouping_map::new(grouping_map::new_map_for_grouping(self, key_mapper)) + grouping_map::new( + grouping_map::new_map_for_grouping(self, key_mapper), + RandomState::new(), + ) + } + + /// Constructs a `GroupingMap` to be used later with one of the efficient + /// group-and-fold operations it allows to perform, using the specified hash builder for + /// hashing the keys. + /// See [.into_grouping_map_by()](crate::Itertools::into_grouping_map_by) for more information. + #[cfg(feature = "use_std")] + fn into_grouping_map_by_with_hasher( + self, + key_mapper: F, + hash_builder: S, + ) -> GroupingMapBy + where + Self: Iterator + Sized, + K: Hash + Eq, + F: FnMut(&V) -> K, + S: BuildHasher, + { + grouping_map::new( + grouping_map::new_map_for_grouping(self, key_mapper), + hash_builder, + ) } /// Return all minimum elements of an iterator. @@ -3977,8 +4434,8 @@ pub trait Itertools: Iterator { /// - `NoElements` if the iterator is empty. /// - `OneElement(x)` if the iterator has exactly one element. /// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two - /// values are equal if and only if there is more than one - /// element in the iterator and all elements are equal. + /// values are equal if and only if there is more than one + /// element in the iterator and all elements are equal. /// /// On an iterator of length `n`, `minmax` does `1.5 * n` comparisons, /// and so is faster than calling `min` and `max` separately which does @@ -3988,7 +4445,7 @@ pub trait Itertools: Iterator { /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; /// /// let a: [i32; 0] = []; /// assert_eq!(a.iter().minmax(), NoElements); @@ -4003,6 +4460,23 @@ pub trait Itertools: Iterator { /// assert_eq!(a.iter().minmax(), MinMax(&1, &1)); /// ``` /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; + /// + /// let a: [(i32, char); 0] = []; + /// assert_eq!(a.iter().minmax(), NoElements); + /// + /// let a = [(1, 'a')]; + /// assert_eq!(a.iter().minmax(), OneElement(&(1, 'a'))); + /// + /// let a = [(0, 'a'), (1, 'b')]; + /// assert_eq!(a.iter().minmax(), MinMax(&(0, 'a'), &(1, 'b'))); + /// + /// let a = [(1, 'a'), (1, 'b'), (1, 'c')]; + /// assert_eq!(a.iter().minmax(), MinMax(&(1, 'a'), &(1, 'c'))); + /// ``` + /// /// The elements can be floats but no particular result is guaranteed /// if an element is NaN. fn minmax(self) -> MinMaxResult @@ -4024,6 +4498,27 @@ pub trait Itertools: Iterator { /// /// The keys can be floats but no particular result is guaranteed /// if a key is NaN. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; + /// + /// let cmp_key = |x: &&(i32, char)| x.0; + /// + /// let a: [(i32, char); 0] = []; + /// assert_eq!(a.iter().minmax_by_key(cmp_key), NoElements); + /// + /// let a = [(1, 'a')]; + /// assert_eq!(a.iter().minmax_by_key(cmp_key), OneElement(&(1, 'a'))); + /// + /// let a = [(0, 'a'), (1, 'b')]; + /// assert_eq!(a.iter().minmax_by_key(cmp_key), MinMax(&(0, 'a'), &(1, 'b'))); + /// + /// let a = [(1, 'a'), (1, 'b'), (1, 'c')]; + /// assert_eq!(a.iter().minmax_by_key(cmp_key), MinMax(&(1, 'a'), &(1, 'c'))); + /// ``` fn minmax_by_key(self, key: F) -> MinMaxResult where Self: Sized, @@ -4041,6 +4536,27 @@ pub trait Itertools: Iterator { /// For the minimum, the first minimal element is returned. For the maximum, /// the last maximal element wins. This matches the behavior of the standard /// [`Iterator::min`] and [`Iterator::max`] methods. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; + /// + /// let first_item_cmp = |x: &&(i32, char), y: &&(i32, char)| x.0.cmp(&y.0); + /// + /// let a: [(i32, char); 0] = []; + /// assert_eq!(a.iter().minmax_by(first_item_cmp), NoElements); + /// + /// let a = [(1, 'a')]; + /// assert_eq!(a.iter().minmax_by(first_item_cmp), OneElement(&(1, 'a'))); + /// + /// let a = [(0, 'a'), (1, 'b')]; + /// assert_eq!(a.iter().minmax_by(first_item_cmp), MinMax(&(0, 'a'), &(1, 'b'))); + /// + /// let a = [(1, 'a'), (1, 'b'), (1, 'c')]; + /// assert_eq!(a.iter().minmax_by(first_item_cmp), MinMax(&(1, 'a'), &(1, 'c'))); + /// ``` fn minmax_by(self, mut compare: F) -> MinMaxResult where Self: Sized, @@ -4237,9 +4753,9 @@ pub trait Itertools: Iterator { /// - `NoElements` if the iterator is empty. /// - `OneElement(xpos)` if the iterator has exactly one element. /// - `MinMax(xpos, ypos)` is returned otherwise, where the - /// element at `xpos` ≤ the element at `ypos`. While the - /// referenced elements themselves may be equal, `xpos` cannot - /// be equal to `ypos`. + /// element at `xpos` ≤ the element at `ypos`. While the + /// referenced elements themselves may be equal, `xpos` cannot + /// be equal to `ypos`. /// /// On an iterator of length `n`, `position_minmax` does `1.5 * n` /// comparisons, and so is faster than calling `position_min` and @@ -4257,7 +4773,7 @@ pub trait Itertools: Iterator { /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; /// /// let a: [i32; 0] = []; /// assert_eq!(a.iter().position_minmax(), NoElements); @@ -4284,7 +4800,7 @@ pub trait Itertools: Iterator { } } - /// Return the postions of the minimum and maximum elements of an + /// Return the positions of the minimum and maximum elements of an /// iterator, as determined by the specified function. /// /// The return value is a variant of [`MinMaxResult`] like for @@ -4302,7 +4818,7 @@ pub trait Itertools: Iterator { /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; /// /// let a: [i32; 0] = []; /// assert_eq!(a.iter().position_minmax_by_key(|x| x.abs()), NoElements); @@ -4332,7 +4848,7 @@ pub trait Itertools: Iterator { } } - /// Return the postions of the minimum and maximum elements of an + /// Return the positions of the minimum and maximum elements of an /// iterator, as determined by the specified comparison function. /// /// The return value is a variant of [`MinMaxResult`] like for @@ -4347,7 +4863,7 @@ pub trait Itertools: Iterator { /// /// ``` /// use itertools::Itertools; - /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// use itertools::MinMaxResult::{MinMax, NoElements, OneElement}; /// /// let a: [i32; 0] = []; /// assert_eq!(a.iter().position_minmax_by(|x, y| x.cmp(y)), NoElements); @@ -4483,7 +4999,19 @@ pub trait Itertools: Iterator { Self: Sized, Self::Item: Eq + Hash, { - let mut counts = HashMap::new(); + self.counts_with_hasher(RandomState::new()) + } + + /// Collect the items in this iterator and return a `HashMap` the same way + /// [.counts()](crate::Itertools::counts) does, but use the specified hash builder for hashing. + #[cfg(feature = "use_std")] + fn counts_with_hasher(self, hash_builder: S) -> HashMap + where + Self: Sized, + Self::Item: Eq + Hash, + S: BuildHasher, + { + let mut counts = HashMap::with_hasher(hash_builder); self.for_each(|item| *counts.entry(item).or_default() += 1); counts } @@ -4496,9 +5024,9 @@ pub trait Itertools: Iterator { /// ``` /// # use itertools::Itertools; /// struct Character { - /// first_name: &'static str, + /// first_name: &'static str, /// # #[allow(dead_code)] - /// last_name: &'static str, + /// last_name: &'static str, /// } /// /// let characters = @@ -4528,7 +5056,20 @@ pub trait Itertools: Iterator { K: Eq + Hash, F: FnMut(Self::Item) -> K, { - self.map(f).counts() + self.counts_by_with_hasher(f, RandomState::new()) + } + + /// Collect the items in this iterator and return a `HashMap` the same way + /// [.counts_by()](crate::Itertools::counts_by) does, but use the specified hash builder for hashing. + #[cfg(feature = "use_std")] + fn counts_by_with_hasher(self, f: F, hash_builder: S) -> HashMap + where + Self: Sized, + K: Eq + Hash, + F: FnMut(Self::Item) -> K, + S: BuildHasher, + { + self.map(f).counts_with_hasher(hash_builder) } /// Converts an iterator of tuples into a tuple of containers. @@ -4581,6 +5122,95 @@ pub trait Itertools: Iterator { _ => Err(sh), } } + + /// Removes a prefix from the iterator, returning the rest. + /// + /// If `self` begins with all the items yielded by `prefix` (in order), this + /// returns `Ok` of the iterator advanced past that prefix. Otherwise it + /// returns `Err(StripPrefixError { .. })` exposing the partially-consumed + /// iterator, the remaining prefix, and the items that failed to match, so + /// callers can recover progress made before the mismatch. + /// + /// See [`strip_prefix_by`](Itertools::strip_prefix_by) for a variant + /// taking an explicit equality predicate. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let ok = (1..6).strip_prefix([1, 2]).map(Itertools::collect_vec).ok(); + /// assert_eq!(ok, Some(vec![3, 4, 5])); + /// assert!((1..6).strip_prefix([1, 9]).is_err()); + /// let empty = (1..6).strip_prefix(std::iter::empty::()).map(Itertools::collect_vec).ok(); + /// assert_eq!(empty, Some(vec![1, 2, 3, 4, 5])); + /// ``` + fn strip_prefix( + self, + prefix: Prefix, + ) -> Result> + where + Self: Sized, + Prefix: IntoIterator, + Self::Item: PartialEq, + { + self.strip_prefix_by(prefix, |a, b| a == b) + } + + /// Removes a prefix from the iterator using `eq` to compare items. + /// + /// If `self` begins with all the items yielded by `prefix` (in order, as + /// judged by `eq`), this returns `Ok` of the iterator advanced past that + /// prefix. Otherwise it returns `Err(StripPrefixError { .. })`, allowing + /// the prefix items to have a different type than `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let path = ["home", "user", "file"]; + /// let stripped = path.iter().strip_prefix_by(["home", "user"], |a, b| **a == *b); + /// assert_eq!(stripped.map(Itertools::collect_vec).ok(), Some(vec![&"file"])); + /// ``` + fn strip_prefix_by( + mut self, + prefix: Prefix, + mut eq: F, + ) -> Result> + where + Self: Sized, + Prefix: IntoIterator, + F: FnMut(&Self::Item, &Prefix::Item) -> bool, + { + let mut prefix = prefix.into_iter(); + match prefix.by_ref().try_for_each(|wanted| match self.next() { + Some(got) if eq(&got, &wanted) => Ok(()), + got => Err((got, wanted)), + }) { + Ok(()) => Ok(self), + Err(mismatch) => Err(StripPrefixError { + iterator: self, + prefix, + mismatch, + }), + } + } +} + +/// The error returned by [`Itertools::strip_prefix`] and +/// [`Itertools::strip_prefix_by`] when the iterator does not start with the +/// requested prefix. +/// +/// All fields are public so callers can recover the partially-consumed +/// iterators and the mismatched items. +#[derive(Debug, Clone)] +pub struct StripPrefixError { + /// The remainder of the original iterator, advanced past the matched + /// prefix items but stopped at the position of the mismatch. + pub iterator: I, + /// The remainder of the prefix iterator, starting just after the prefix + /// item that failed to match. + pub prefix: Prefix, + /// The pair of items that failed to compare equal. The first element is + /// `None` if `iterator` was exhausted before the prefix was fully matched. + pub mismatch: (Option, Prefix::Item), } impl Itertools for T where T: Iterator + ?Sized {} diff --git a/third_party/rust/itertools/src/minmax.rs b/third_party/rust/itertools/src/minmax.rs index 5c9674e01124..b68efffd4817 100644 --- a/third_party/rust/itertools/src/minmax.rs +++ b/third_party/rust/itertools/src/minmax.rs @@ -24,7 +24,7 @@ impl MinMaxResult { /// # Examples /// /// ``` - /// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax}; + /// use itertools::MinMaxResult::{self, MinMax, NoElements, OneElement}; /// /// let r: MinMaxResult = NoElements; /// assert_eq!(r.into_option(), None); diff --git a/third_party/rust/itertools/src/pad_tail.rs b/third_party/rust/itertools/src/pad_tail.rs index 5595b42bacf2..e6705d92c230 100644 --- a/third_party/rust/itertools/src/pad_tail.rs +++ b/third_party/rust/itertools/src/pad_tail.rs @@ -1,4 +1,3 @@ -use crate::size_hint; use std::iter::{Fuse, FusedIterator}; /// An iterator adaptor that pads a sequence to a minimum length by filling @@ -11,8 +10,9 @@ use std::iter::{Fuse, FusedIterator}; #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct PadUsing { iter: Fuse, - min: usize, - pos: usize, + elements_from_next: usize, + elements_from_next_back: usize, + elements_required: usize, filler: F, } @@ -20,19 +20,26 @@ impl std::fmt::Debug for PadUsing where I: std::fmt::Debug, { - debug_fmt_fields!(PadUsing, iter, min, pos); + debug_fmt_fields!( + PadUsing, + iter, + elements_from_next, + elements_from_next_back, + elements_required + ); } /// Create a new `PadUsing` iterator. -pub fn pad_using(iter: I, min: usize, filler: F) -> PadUsing +pub fn pad_using(iter: I, elements_required: usize, filler: F) -> PadUsing where I: Iterator, F: FnMut(usize) -> I::Item, { PadUsing { iter: iter.fuse(), - min, - pos: 0, + elements_from_next: 0, + elements_from_next_back: 0, + elements_required, filler, } } @@ -46,38 +53,34 @@ where #[inline] fn next(&mut self) -> Option { - match self.iter.next() { - None => { - if self.pos < self.min { - let e = Some((self.filler)(self.pos)); - self.pos += 1; - e - } else { - None - } - } - e => { - self.pos += 1; - e - } + let total_consumed = self.elements_from_next + self.elements_from_next_back; + + if total_consumed >= self.elements_required { + self.iter.next() + } else if let Some(e) = self.iter.next() { + self.elements_from_next += 1; + Some(e) + } else { + let e = (self.filler)(self.elements_from_next); + self.elements_from_next += 1; + Some(e) } } fn size_hint(&self) -> (usize, Option) { - let tail = self.min.saturating_sub(self.pos); - size_hint::max(self.iter.size_hint(), (tail, Some(tail))) - } + let total_consumed = self.elements_from_next + self.elements_from_next_back; - fn fold(self, mut init: B, mut f: G) -> B - where - G: FnMut(B, Self::Item) -> B, - { - let mut pos = self.pos; - init = self.iter.fold(init, |acc, item| { - pos += 1; - f(acc, item) - }); - (pos..self.min).map(self.filler).fold(init, f) + if total_consumed >= self.elements_required { + return self.iter.size_hint(); + } + + let elements_remaining = self.elements_required - total_consumed; + let (low, high) = self.iter.size_hint(); + + let lower_bound = low.max(elements_remaining); + let upper_bound = high.map(|h| h.max(elements_remaining)); + + (lower_bound, upper_bound) } } @@ -87,25 +90,24 @@ where F: FnMut(usize) -> I::Item, { fn next_back(&mut self) -> Option { - if self.min == 0 { - self.iter.next_back() - } else if self.iter.len() >= self.min { - self.min -= 1; - self.iter.next_back() - } else { - self.min -= 1; - Some((self.filler)(self.min)) - } - } + let total_consumed = self.elements_from_next + self.elements_from_next_back; - fn rfold(self, mut init: B, mut f: G) -> B - where - G: FnMut(B, Self::Item) -> B, - { - init = (self.iter.len()..self.min) - .map(self.filler) - .rfold(init, &mut f); - self.iter.rfold(init, f) + if total_consumed >= self.elements_required { + return self.iter.next_back(); + } + + let elements_remaining = self.elements_required - total_consumed; + self.elements_from_next_back += 1; + + if self.iter.len() < elements_remaining { + Some((self.filler)( + self.elements_required - self.elements_from_next_back, + )) + } else { + let item = self.iter.next_back(); + debug_assert!(item.is_some()); // If this triggers, we should not have incremented elements_from_next_back, and the input iterator mistakenly reported that it would be able to produce at least elements_remaining items. + item + } } } diff --git a/third_party/rust/itertools/src/peeking_take_while.rs b/third_party/rust/itertools/src/peeking_take_while.rs index f3259a919013..d61e641473d8 100644 --- a/third_party/rust/itertools/src/peeking_take_while.rs +++ b/third_party/rust/itertools/src/peeking_take_while.rs @@ -92,6 +92,57 @@ where } } +#[cfg(feature = "use_alloc")] +impl PeekingNext for ::alloc::vec::IntoIter { + fn peeking_next(&mut self, accept: F) -> Option + where + F: FnOnce(&Self::Item) -> bool, + { + match accept(self.as_slice().first()?) { + true => self.next(), + false => None, + } + } +} + +#[cfg(feature = "use_alloc")] +impl<'a, T> PeekingNext for ::alloc::vec::Drain<'a, T> { + fn peeking_next(&mut self, accept: F) -> Option + where + F: FnOnce(&Self::Item) -> bool, + { + match accept(self.as_slice().first()?) { + true => self.next(), + false => None, + } + } +} + +#[cfg(feature = "use_alloc")] +impl<'a> PeekingNext for ::alloc::string::Drain<'a> { + fn peeking_next(&mut self, accept: F) -> Option + where + F: FnOnce(&Self::Item) -> bool, + { + match accept(&self.as_str().chars().next()?) { + true => self.next(), + false => None, + } + } +} + +impl PeekingNext for ::core::array::IntoIter { + fn peeking_next(&mut self, accept: F) -> Option + where + F: FnOnce(&Self::Item) -> bool, + { + match accept(self.as_slice().first()?) { + true => self.next(), + false => None, + } + } +} + impl PeekingNext for RepeatN { fn peeking_next(&mut self, accept: F) -> Option where @@ -126,7 +177,7 @@ where } /// Create a `PeekingTakeWhile` -pub fn peeking_take_while(iter: &mut I, f: F) -> PeekingTakeWhile +pub fn peeking_take_while(iter: &mut I, f: F) -> PeekingTakeWhile<'_, I, F> where I: Iterator, { @@ -191,11 +242,33 @@ peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> } peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> } peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> } peeking_next_by_clone! { [T] ::std::iter::Empty } + #[cfg(feature = "use_alloc")] peeking_next_by_clone! { ['a, T] alloc::collections::linked_list::Iter<'a, T> } #[cfg(feature = "use_alloc")] peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> } +#[cfg(feature = "use_alloc")] +peeking_next_by_clone! { ['a, K, V] alloc::collections::btree_map::Iter<'a, K, V> } +#[cfg(feature = "use_alloc")] +peeking_next_by_clone! { ['a, K, V] alloc::collections::btree_map::Keys<'a, K, V> } +#[cfg(feature = "use_alloc")] +peeking_next_by_clone! { ['a, K, V] alloc::collections::btree_map::Values<'a, K, V> } + +#[cfg(feature = "use_alloc")] +peeking_next_by_clone! { ['a, T] alloc::collections::btree_set::Iter<'a, T> } +#[cfg(feature = "use_alloc")] +peeking_next_by_clone! { ['a, T] alloc::collections::binary_heap::Iter<'a, T> } + +#[cfg(feature = "use_std")] +peeking_next_by_clone! { ['a, K, V] std::collections::hash_map::Iter<'a, K, V> } +#[cfg(feature = "use_std")] +peeking_next_by_clone! { ['a, K, V] std::collections::hash_map::Keys<'a, K, V> } +#[cfg(feature = "use_std")] +peeking_next_by_clone! { ['a, K, V] std::collections::hash_map::Values<'a, K, V> } +#[cfg(feature = "use_std")] +peeking_next_by_clone! { ['a, T] std::collections::hash_set::Iter<'a, T> } + // cloning a Rev has no extra overhead; peekable and put backs are never DEI. peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator] ::std::iter::Rev } diff --git a/third_party/rust/itertools/src/powerset.rs b/third_party/rust/itertools/src/powerset.rs index 734eaf6149ac..f32cf8b78214 100644 --- a/third_party/rust/itertools/src/powerset.rs +++ b/third_party/rust/itertools/src/powerset.rs @@ -31,7 +31,7 @@ where debug_fmt_fields!(Powerset, combs); } -/// Create a new `Powerset` from a clonable iterator. +/// Create a new `Powerset` from a cloneable iterator. pub fn powerset(src: I) -> Powerset where I: Iterator, diff --git a/third_party/rust/itertools/src/size_hint.rs b/third_party/rust/itertools/src/size_hint.rs index 6cfead7f2b42..f46f8fb1487b 100644 --- a/third_party/rust/itertools/src/size_hint.rs +++ b/third_party/rust/itertools/src/size_hint.rs @@ -1,5 +1,4 @@ //! Arithmetic on `Iterator.size_hint()` values. -//! use std::cmp; @@ -86,6 +85,7 @@ pub fn min(a: SizeHint, b: SizeHint) -> SizeHint { (lower, upper) } +/// Test multiplication of size hints. #[test] fn mul_size_hints() { assert_eq!(mul((3, Some(4)), (3, Some(4))), (9, Some(16))); diff --git a/third_party/rust/itertools/src/tuple_impl.rs b/third_party/rust/itertools/src/tuple_impl.rs index c0d556fc95b1..1c3924ad4d87 100644 --- a/third_party/rust/itertools/src/tuple_impl.rs +++ b/third_party/rust/itertools/src/tuple_impl.rs @@ -385,6 +385,7 @@ macro_rules! impl_tuple_collect { count_ident!($($Y)*) } + /// Shift all elements one position to the left and push the new item to the end. fn left_shift_push(&mut self, mut item: A) { use std::mem::replace; diff --git a/third_party/rust/itertools/src/unique_impl.rs b/third_party/rust/itertools/src/unique_impl.rs index 0f6397e48fb9..49c0055b719c 100644 --- a/third_party/rust/itertools/src/unique_impl.rs +++ b/third_party/rust/itertools/src/unique_impl.rs @@ -1,4 +1,6 @@ +use core::hash::BuildHasher; use std::collections::hash_map::Entry; +use std::collections::hash_map::RandomState; use std::collections::HashMap; use std::fmt; use std::hash::Hash; @@ -9,42 +11,48 @@ use std::iter::FusedIterator; /// See [`.unique_by()`](crate::Itertools::unique) for more information. #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct UniqueBy { +pub struct UniqueBy +where + S: BuildHasher, +{ iter: I, // Use a Hashmap for the Entry API in order to prevent hashing twice. // This can maybe be replaced with a HashSet once `get_or_insert_with` // or a proper Entry API for Hashset is stable and meets this msrv - used: HashMap, + used: HashMap, f: F, } -impl fmt::Debug for UniqueBy +impl fmt::Debug for UniqueBy where I: Iterator + fmt::Debug, V: fmt::Debug + Hash + Eq, + S: BuildHasher, { debug_fmt_fields!(UniqueBy, iter, used); } /// Create a new `UniqueBy` iterator. -pub fn unique_by(iter: I, f: F) -> UniqueBy +pub fn unique_by_with_hasher(iter: I, f: F, hash_builder: S) -> UniqueBy where V: Eq + Hash, F: FnMut(&I::Item) -> V, I: Iterator, + S: BuildHasher, { UniqueBy { iter, - used: HashMap::new(), + used: HashMap::with_hasher(hash_builder), f, } } // count the number of new unique keys in iterable (`used` is the set already seen) -fn count_new_keys(mut used: HashMap, iterable: I) -> usize +fn count_new_keys(mut used: HashMap, iterable: I) -> usize where I: IntoIterator, K: Hash + Eq, + S: BuildHasher, { let iter = iterable.into_iter(); let current_used = used.len(); @@ -52,11 +60,12 @@ where used.len() - current_used } -impl Iterator for UniqueBy +impl Iterator for UniqueBy where I: Iterator, V: Eq + Hash, F: FnMut(&I::Item) -> V, + S: BuildHasher, { type Item = I::Item; @@ -68,7 +77,7 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { let (low, hi) = self.iter.size_hint(); - ((low > 0 && self.used.is_empty()) as usize, hi) + (usize::from(low > 0 && self.used.is_empty()), hi) } fn count(self) -> usize { @@ -77,11 +86,12 @@ where } } -impl DoubleEndedIterator for UniqueBy +impl DoubleEndedIterator for UniqueBy where I: DoubleEndedIterator, V: Eq + Hash, F: FnMut(&I::Item) -> V, + S: BuildHasher, { fn next_back(&mut self) -> Option { let Self { iter, used, f } = self; @@ -89,18 +99,20 @@ where } } -impl FusedIterator for UniqueBy +impl FusedIterator for UniqueBy where I: FusedIterator, V: Eq + Hash, F: FnMut(&I::Item) -> V, + S: BuildHasher, { } -impl Iterator for Unique +impl Iterator for Unique where I: Iterator, I::Item: Eq + Hash + Clone, + S: BuildHasher, { type Item = I::Item; @@ -119,7 +131,7 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { let (low, hi) = self.iter.iter.size_hint(); - ((low > 0 && self.iter.used.is_empty()) as usize, hi) + (usize::from(low > 0 && self.iter.used.is_empty()), hi) } fn count(self) -> usize { @@ -127,10 +139,11 @@ where } } -impl DoubleEndedIterator for Unique +impl DoubleEndedIterator for Unique where I: DoubleEndedIterator, I::Item: Eq + Hash + Clone, + S: BuildHasher, { fn next_back(&mut self) -> Option { let UniqueBy { iter, used, .. } = &mut self.iter; @@ -145,10 +158,11 @@ where } } -impl FusedIterator for Unique +impl FusedIterator for Unique where I: FusedIterator, I::Item: Eq + Hash + Clone, + S: BuildHasher, { } @@ -157,31 +171,34 @@ where /// See [`.unique()`](crate::Itertools::unique) for more information. #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Unique +pub struct Unique where I: Iterator, I::Item: Eq + Hash + Clone, + S: BuildHasher, { - iter: UniqueBy, + iter: UniqueBy, } -impl fmt::Debug for Unique +impl fmt::Debug for Unique where I: Iterator + fmt::Debug, I::Item: Hash + Eq + fmt::Debug + Clone, + S: BuildHasher, { debug_fmt_fields!(Unique, iter); } -pub fn unique(iter: I) -> Unique +pub fn unique_with_hasher(iter: I, hash_builder: S) -> Unique where I: Iterator, I::Item: Eq + Hash + Clone, + S: BuildHasher, { Unique { iter: UniqueBy { iter, - used: HashMap::new(), + used: HashMap::with_hasher(hash_builder), f: (), }, } diff --git a/third_party/rust/itertools/src/with_position.rs b/third_party/rust/itertools/src/with_position.rs index 2d56bb9b2247..ddb5a60d9da2 100644 --- a/third_party/rust/itertools/src/with_position.rs +++ b/third_party/rust/itertools/src/with_position.rs @@ -47,44 +47,46 @@ where /// /// See [`.with_position()`](crate::Itertools::with_position) for more information. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Position { - /// This is the first element. - First, - /// This is neither the first nor the last element. - Middle, - /// This is the last element. - Last, - /// This is the only element. - Only, +pub struct Position { + /// This is the initial element (also true if there's exactly one element) + pub is_first: bool, + /// This is the final element (also true if there's exactly one element) + pub is_last: bool, +} + +impl Position { + /// This is the first and the last element at the same time, and there are no more elements + pub fn is_exactly_one(self) -> bool { + self.is_first && self.is_last + } + + /// This is neither first nor last element, and there will be more elements + pub fn is_middle(self) -> bool { + !self.is_first && !self.is_last + } + + /// This is the initial element (also true if there's exactly one element) + pub fn is_first(self) -> bool { + self.is_first + } + + /// This is the final element (also true if there's exactly one element) + pub fn is_last(self) -> bool { + self.is_last + } } impl Iterator for WithPosition { type Item = (Position, I::Item); fn next(&mut self) -> Option { - match self.peekable.next() { - Some(item) => { - if !self.handled_first { - // Haven't seen the first item yet, and there is one to give. - self.handled_first = true; - // Peek to see if this is also the last item, - // in which case tag it as `Only`. - match self.peekable.peek() { - Some(_) => Some((Position::First, item)), - None => Some((Position::Only, item)), - } - } else { - // Have seen the first item, and there's something left. - // Peek to see if this is the last item. - match self.peekable.peek() { - Some(_) => Some((Position::Middle, item)), - None => Some((Position::Last, item)), - } - } - } - // Iterator is finished. - None => None, - } + let item = self.peekable.next()?; + + let is_last = self.peekable.peek().is_none(); + let is_first = !self.handled_first; + self.handled_first = true; + + Some((Position { is_first, is_last }, item)) } fn size_hint(&self) -> (usize, Option) { @@ -102,18 +104,36 @@ impl Iterator for WithPosition { match self.peekable.next() { Some(second) => { let first = std::mem::replace(&mut head, second); - init = f(init, (Position::First, first)); + let position = Position { + is_first: true, + is_last: false, + }; + init = f(init, (position, first)); + } + None => { + let position = Position { + is_first: true, + is_last: true, + }; + return f(init, (position, head)); } - None => return f(init, (Position::Only, head)), } } // Have seen the first item, and there's something left. init = self.peekable.fold(init, |acc, mut item| { std::mem::swap(&mut head, &mut item); - f(acc, (Position::Middle, item)) + let position = Position { + is_first: false, + is_last: false, + }; + f(acc, (position, item)) }); + let position = Position { + is_first: false, + is_last: true, + }; // The "head" is now the last item. - init = f(init, (Position::Last, head)); + init = f(init, (position, head)); } init } diff --git a/third_party/rust/itertools/src/ziptuple.rs b/third_party/rust/itertools/src/ziptuple.rs index 3ada0296caac..b1a8f3ef6d00 100644 --- a/third_party/rust/itertools/src/ziptuple.rs +++ b/third_party/rust/itertools/src/ziptuple.rs @@ -13,7 +13,7 @@ pub struct Zip { /// implement [`IntoIterator`]) and yields elements /// until any of the subiterators yields `None`. /// -/// The iterator element type is a tuple like like `(A, B, ..., E)` where `A` to `E` are the +/// The iterator element type is a tuple like `(A, B, ..., E)` where `A` to `E` are the /// element types of the subiterator. /// /// **Note:** The result of this function is a value of a named type (`Zip<(I, J, diff --git a/third_party/rust/itertools/tests/adaptors_no_collect.rs b/third_party/rust/itertools/tests/adaptors_no_collect.rs index 977224af29f7..28b20a4419bc 100644 --- a/third_party/rust/itertools/tests/adaptors_no_collect.rs +++ b/third_party/rust/itertools/tests/adaptors_no_collect.rs @@ -49,3 +49,7 @@ fn combinations_no_collect() { fn combinations_with_replacement_no_collect() { no_collect_test(|iter| iter.combinations_with_replacement(5)) } +#[test] +fn array_combinations_with_replacement_no_collect() { + no_collect_test(|iter| iter.array_combinations_with_replacement::<5>()) +} diff --git a/third_party/rust/itertools/tests/arrays.rs b/third_party/rust/itertools/tests/arrays.rs new file mode 100644 index 000000000000..45dd683b0e62 --- /dev/null +++ b/third_party/rust/itertools/tests/arrays.rs @@ -0,0 +1,483 @@ +use itertools::Itertools; + +#[test] +fn array_windows() { + let [vec0, vec1, vec2, vec4, vec10] = [ + vec![], + vec![1], + vec![1, 2], + vec![1, 2, 3, 4], + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + ]; + + assert_eq!( + vec10 + .iter() + .copied() + .array_windows::<2>() + .collect::>(), + vec![ + [1, 2], + [2, 3], + [3, 4], + [4, 5], + [5, 6], + [6, 7], + [7, 8], + [8, 9], + [9, 10], + ] + ); + + assert_eq!( + vec4.iter() + .copied() + .array_windows::<2>() + .collect::>(), + vec![[1, 2], [2, 3], [3, 4]] + ); + + assert_eq!( + vec2.iter() + .copied() + .array_windows::<2>() + .collect::>(), + vec![[1, 2]] + ); + + assert_eq!( + vec1.iter() + .copied() + .array_windows::<2>() + .collect::>(), + Vec::<[i32; 2]>::new() + ); + + assert_eq!( + vec0.iter() + .copied() + .array_windows::<2>() + .collect::>(), + Vec::<[i32; 2]>::new() + ); + + assert_eq!( + vec10 + .iter() + .copied() + .array_windows::<4>() + .collect::>(), + vec![ + [1, 2, 3, 4], + [2, 3, 4, 5], + [3, 4, 5, 6], + [4, 5, 6, 7], + [5, 6, 7, 8], + [6, 7, 8, 9], + [7, 8, 9, 10], + ] + ); + + // For zero-length output windows, the equation + // + // output length = input length + N - 1 + // + // implies that we return one _more_ zero-length window than there + // are input items, as if we were returning a zero-length window + // for each position between elements of the input list, including + // the positions at the start and end. + assert_eq!( + vec0.iter() + .copied() + .array_windows::<0>() + .collect::>(), + vec![[]] + ); + + assert_eq!( + vec1.iter() + .copied() + .array_windows::<0>() + .collect::>(), + vec![[], []] + ); + + assert_eq!( + vec2.iter() + .copied() + .array_windows::<0>() + .collect::>(), + vec![[], [], []] + ); + + assert_eq!( + vec0.iter() + .copied() + .array_windows::<1>() + .collect::>(), + Vec::<[i32; 1]>::new() + ); + + assert_eq!( + vec1.iter() + .copied() + .array_windows::<1>() + .collect::>(), + vec![[1]] + ); + + assert_eq!( + vec2.iter() + .copied() + .array_windows::<1>() + .collect::>(), + vec![[1], [2]] + ); + + assert_eq!( + vec1.iter() + .copied() + .array_windows::<7>() + .collect::>(), + Vec::<[i32; 7]>::new() + ); + + assert_eq!( + vec2.iter() + .copied() + .array_windows::<7>() + .collect::>(), + Vec::<[i32; 7]>::new() + ); + + assert_eq!( + vec4.iter() + .copied() + .array_windows::<7>() + .collect::>(), + Vec::<[i32; 7]>::new() + ); +} + +#[test] +fn array_windows_equal_tuple_windows() { + fn internal(slice: &[usize]) { + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_,)>() + .map(Into::<[_; 1]>::into), + slice.iter().array_windows::<1>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _)>() + .map(Into::<[_; 2]>::into), + slice.iter().array_windows::<2>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _)>() + .map(Into::<[_; 3]>::into), + slice.iter().array_windows::<3>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _)>() + .map(Into::<[_; 4]>::into), + slice.iter().array_windows::<4>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _, _)>() + .map(Into::<[_; 5]>::into), + slice.iter().array_windows::<5>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _, _, _)>() + .map(Into::<[_; 6]>::into), + slice.iter().array_windows::<6>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _, _, _, _)>() + .map(Into::<[_; 7]>::into), + slice.iter().array_windows::<7>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _, _, _, _, _)>() + .map(Into::<[_; 8]>::into), + slice.iter().array_windows::<8>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _, _, _, _, _, _)>() + .map(Into::<[_; 9]>::into), + slice.iter().array_windows::<9>(), + ); + itertools::assert_equal( + slice + .iter() + .tuple_windows::<(_, _, _, _, _, _, _, _, _, _)>() + .map(Into::<[_; 10]>::into), + slice.iter().array_windows::<10>(), + ); + } + for i in 0..100 { + internal(&(0..i).collect::>()); + } +} + +#[test] +fn circular_array_windows() { + let [vec0, vec1, vec2, vec4, vec10] = [ + vec![], + vec![1], + vec![1, 2], + vec![1, 2, 3, 4], + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + ]; + + assert_eq!( + vec10 + .iter() + .copied() + .circular_array_windows::<2>() + .collect::>(), + vec![ + [1, 2], + [2, 3], + [3, 4], + [4, 5], + [5, 6], + [6, 7], + [7, 8], + [8, 9], + [9, 10], + [10, 1] + ] + ); + + assert_eq!( + vec4.iter() + .copied() + .circular_array_windows::<2>() + .collect::>(), + vec![[1, 2], [2, 3], [3, 4], [4, 1]] + ); + + assert_eq!( + vec2.iter() + .copied() + .circular_array_windows::<2>() + .collect::>(), + vec![[1, 2], [2, 1]] + ); + + assert_eq!( + vec1.iter() + .copied() + .circular_array_windows::<2>() + .collect::>(), + vec![[1, 1]] + ); + + assert_eq!( + vec0.iter() + .copied() + .circular_array_windows::<2>() + .collect::>(), + Vec::<[i32; 2]>::new() + ); + + assert_eq!( + vec10 + .iter() + .copied() + .circular_array_windows::<4>() + .collect::>(), + vec![ + [1, 2, 3, 4], + [2, 3, 4, 5], + [3, 4, 5, 6], + [4, 5, 6, 7], + [5, 6, 7, 8], + [6, 7, 8, 9], + [7, 8, 9, 10], + [8, 9, 10, 1], + [9, 10, 1, 2], + [10, 1, 2, 3], + ] + ); + + // For zero-length output windows, we preserve the invariant that + // output length = input length, and return the same number of + // zero-length windows as there were input items, as if we were + // returning a zero-length window for every possible starting + // position in the cyclic input list. + assert_eq!( + vec0.iter() + .copied() + .circular_array_windows::<0>() + .collect::>(), + Vec::<[i32; 0]>::new() + ); + + assert_eq!( + vec1.iter() + .copied() + .circular_array_windows::<0>() + .collect::>(), + vec![[]] + ); + + assert_eq!( + vec2.iter() + .copied() + .circular_array_windows::<0>() + .collect::>(), + vec![[], []] + ); + + assert_eq!( + vec0.iter() + .copied() + .circular_array_windows::<1>() + .collect::>(), + Vec::<[i32; 1]>::new() + ); + + assert_eq!( + vec1.iter() + .copied() + .circular_array_windows::<1>() + .collect::>(), + vec![[1]] + ); + + assert_eq!( + vec2.iter() + .copied() + .circular_array_windows::<1>() + .collect::>(), + vec![[1], [2]] + ); + + assert_eq!( + vec1.iter() + .copied() + .circular_array_windows::<7>() + .collect::>(), + vec![[1, 1, 1, 1, 1, 1, 1]] + ); + + assert_eq!( + vec2.iter() + .copied() + .circular_array_windows::<7>() + .collect::>(), + vec![[1, 2, 1, 2, 1, 2, 1], [2, 1, 2, 1, 2, 1, 2]] + ); + + assert_eq!( + vec4.iter() + .copied() + .circular_array_windows::<7>() + .collect::>(), + vec![ + [1, 2, 3, 4, 1, 2, 3], + [2, 3, 4, 1, 2, 3, 4], + [3, 4, 1, 2, 3, 4, 1], + [4, 1, 2, 3, 4, 1, 2], + ] + ); +} + +#[test] +fn circular_array_windows_equal_circular_tuple_windows() { + fn internal(slice: &[usize]) { + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_,)>() + .map(Into::<[_; 1]>::into), + slice.iter().circular_array_windows::<1>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _)>() + .map(Into::<[_; 2]>::into), + slice.iter().circular_array_windows::<2>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _)>() + .map(Into::<[_; 3]>::into), + slice.iter().circular_array_windows::<3>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _)>() + .map(Into::<[_; 4]>::into), + slice.iter().circular_array_windows::<4>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _, _)>() + .map(Into::<[_; 5]>::into), + slice.iter().circular_array_windows::<5>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _, _, _)>() + .map(Into::<[_; 6]>::into), + slice.iter().circular_array_windows::<6>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _, _, _, _)>() + .map(Into::<[_; 7]>::into), + slice.iter().circular_array_windows::<7>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _, _, _, _, _)>() + .map(Into::<[_; 8]>::into), + slice.iter().circular_array_windows::<8>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _, _, _, _, _, _)>() + .map(Into::<[_; 9]>::into), + slice.iter().circular_array_windows::<9>(), + ); + itertools::assert_equal( + slice + .iter() + .circular_tuple_windows::<(_, _, _, _, _, _, _, _, _, _)>() + .map(Into::<[_; 10]>::into), + slice.iter().circular_array_windows::<10>(), + ); + } + for i in 0..100 { + internal(&(0..i).collect::>()); + } +} diff --git a/third_party/rust/itertools/tests/laziness.rs b/third_party/rust/itertools/tests/laziness.rs index c559d33adc5d..7fba430b0aa3 100644 --- a/third_party/rust/itertools/tests/laziness.rs +++ b/third_party/rust/itertools/tests/laziness.rs @@ -104,6 +104,18 @@ must_use_tests! { let _ = Panicking.circular_tuple_windows::<(_, _)>(); let _ = Panicking.circular_tuple_windows::<(_, _, _)>(); } + array_windows { + let _ = Panicking.array_windows::<0>(); + let _ = Panicking.array_windows::<1>(); + let _ = Panicking.array_windows::<2>(); + let _ = Panicking.array_windows::<3>(); + } + circular_array_windows { + let _ = Panicking.circular_array_windows::<0>(); + let _ = Panicking.circular_array_windows::<1>(); + let _ = Panicking.circular_array_windows::<2>(); + let _ = Panicking.circular_array_windows::<3>(); + } tuples { let _ = Panicking.tuples::<(_,)>(); let _ = Panicking.tuples::<(_, _)>(); @@ -196,17 +208,29 @@ must_use_tests! { while_some { let _ = Panicking.map(Some).while_some(); } + #[allow(deprecated)] tuple_combinations1 { let _ = Panicking.tuple_combinations::<(_,)>(); } + #[allow(deprecated)] #[should_panic] tuple_combinations2 { let _ = Panicking.tuple_combinations::<(_, _)>(); } + #[allow(deprecated)] #[should_panic] tuple_combinations3 { let _ = Panicking.tuple_combinations::<(_, _, _)>(); } + array_combinations1 { + let _ = Panicking.array_combinations::<1>(); + } + array_combinations2 { + let _ = Panicking.array_combinations::<2>(); + } + array_combinations3 { + let _ = Panicking.array_combinations::<3>(); + } combinations { let _ = Panicking.combinations(0); let _ = Panicking.combinations(1); @@ -217,6 +241,11 @@ must_use_tests! { let _ = Panicking.combinations_with_replacement(1); let _ = Panicking.combinations_with_replacement(2); } + array_combinations_with_replacement { + let _ = Panicking.array_combinations_with_replacement::<0>(); + let _ = Panicking.array_combinations_with_replacement::<1>(); + let _ = Panicking.array_combinations_with_replacement::<2>(); + } permutations { let _ = Panicking.permutations(0); let _ = Panicking.permutations(1); diff --git a/third_party/rust/itertools/tests/quick.rs b/third_party/rust/itertools/tests/quick.rs index 672901e7c70a..d33f425af4bc 100644 --- a/third_party/rust/itertools/tests/quick.rs +++ b/third_party/rust/itertools/tests/quick.rs @@ -275,8 +275,7 @@ where let actual_count = total_actual_count - i; if actual_count != returned_count { println!( - "Total iterations: {} True count: {} returned count: {}", - i, actual_count, returned_count + "Total iterations: {i} True count: {actual_count} returned count: {returned_count}" ); return false; @@ -450,7 +449,13 @@ quickcheck! { } assert_eq!(answer, actual); - assert_eq!(answer.into_iter().last(), a.multi_cartesian_product().last()); + assert_eq!( + { + #[allow(clippy::double_ended_iterator_last)] + answer.into_iter().last() + }, + a.multi_cartesian_product().last() + ); } fn correct_empty_multi_product() -> () { @@ -993,6 +998,45 @@ quickcheck! { } } +quickcheck! { + fn pad_using_next_next_back(v: Vec) -> () { + let only_oks = v.into_iter().map(Ok).collect::>(); + for elements_required in 0..128 { + let mut oks_then_errs_vector = only_oks.clone(); + while oks_then_errs_vector.len() < elements_required { + oks_then_errs_vector.push(Err(oks_then_errs_vector.len())); + } + let oks_then_errs_pad_using = only_oks.iter().copied().pad_using(elements_required, Err); + assert_eq!( + oks_then_errs_pad_using.clone().collect::>(), + oks_then_errs_vector + ); + // Check next, next_back (https://github.com/rust-itertools/itertools/issues/1065) + let mut iter_check = oks_then_errs_vector.into_iter(); + let mut iter_real = oks_then_errs_pad_using; + let mut rng = rand::thread_rng(); + loop { + let next_or_next_back = if rng.gen_bool(0.5) { + let element_next_check = iter_check.next(); + let element_next_real = iter_real.next(); + assert_eq!(element_next_check, element_next_real); + element_next_real + } else { + let element_next_back_check = iter_check.next_back(); + let element_next_back_real = iter_real.next_back(); + assert_eq!(element_next_back_check, element_next_back_real); + element_next_back_real + }; + if next_or_next_back.is_none() { + assert!(iter_real.next().is_none()); + assert!(iter_real.next_back().is_none()); + break; + } + } + } + } +} + quickcheck! { fn size_powerset(it: Iter) -> bool { // Powerset cardinality gets large very quickly, limit input to keep test fast. @@ -1059,7 +1103,7 @@ quickcheck! { let tup1 = |(_, b)| b; for &(ord, consume_now) in &order { - let iter = &mut [&mut chunks1, &mut chunks2][ord as usize]; + let iter = &mut [&mut chunks1, &mut chunks2][usize::from(ord)]; match iter.next() { Some((_, gr)) => if consume_now { for og in old_chunks.drain(..) { @@ -1256,6 +1300,79 @@ quickcheck! { } } +// array iterators +quickcheck! { + fn equal_array_windows_0(a: Vec) -> bool { + let x = (0..=a.len()).map(|_| [&0u8; 0] ); + let y = a.iter().array_windows::<0>(); + itertools::assert_equal(x,y); + true + } + + fn equal_array_windows_1(a: Vec) -> bool { + let x = a.iter().map(|e| [e] ); + let y = a.iter().array_windows::<1>(); + itertools::assert_equal(x,y); + true + } + + fn equal_array_windows_2(a: Vec) -> bool { + let x = (0..a.len().saturating_sub(1)).map(|start_idx| [ + &a[start_idx], + &a[start_idx + 1], + ]); + let y = a.iter().array_windows::<2>(); + itertools::assert_equal(x,y); + true + } + + fn equal_array_windows_3(a: Vec) -> bool { + let x = (0..a.len().saturating_sub(2)).map(|start_idx| [ + &a[start_idx], + &a[start_idx + 1], + &a[start_idx + 2], + ]); + let y = a.iter().array_windows::<3>(); + itertools::assert_equal(x,y); + true + } + + fn equal_circular_array_windows_0(a: Vec) -> bool { + let x = a.iter().map(|_| [&0u8; 0] ); + let y = a.iter().circular_array_windows::<0>(); + itertools::assert_equal(x,y); + true + } + + fn equal_circular_array_windows_1(a: Vec) -> bool { + let x = a.iter().map(|e| [e] ); + let y = a.iter().circular_array_windows::<1>(); + itertools::assert_equal(x,y); + true + } + + fn equal_circular_array_windows_2(a: Vec) -> bool { + let x = (0..a.len()).map(|start_idx| [ + &a[start_idx], + &a[(start_idx + 1) % a.len()], + ]); + let y = a.iter().circular_array_windows::<2>(); + itertools::assert_equal(x,y); + true + } + + fn equal_circular_array_windows_3(a: Vec) -> bool { + let x = (0..a.len()).map(|start_idx| [ + &a[start_idx], + &a[(start_idx + 1) % a.len()], + &a[(start_idx + 2) % a.len()], + ]); + let y = a.iter().circular_array_windows::<3>(); + itertools::assert_equal(x,y); + true + } +} + // with_position quickcheck! { fn with_position_exact_size_1(a: Vec) -> bool { @@ -1385,6 +1502,16 @@ quickcheck! { } } +quickcheck! { + fn exactly_one_count(a: Vec) -> TestResult { + let ret = a.iter().cloned().exactly_one(); + match a.len() { + 1 => TestResult::passed(), + len => TestResult::from_bool(len == ret.unwrap_err().count()), + } + } +} + quickcheck! { fn at_most_one_i32(a: Vec) -> TestResult { let ret = a.iter().cloned().at_most_one(); @@ -1407,9 +1534,9 @@ quickcheck! { } fn correct_grouping_map_by_aggregate_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = if modulo < 2 { 2 } else { modulo } as u64; // Avoid `% 0` + let modulo = u64::from(if modulo < 2 { 2 } else { modulo }); // Avoid `% 0` let lookup = a.iter() - .map(|&b| b as u64) // Avoid overflows + .map(|&b| u64::from(b)) // Avoid overflows .into_grouping_map_by(|i| i % modulo) .aggregate(|acc, &key, val| { assert!(val % modulo == key); @@ -1421,7 +1548,7 @@ quickcheck! { }); let group_map_lookup = a.iter() - .map(|&b| b as u64) + .map(|&b| u64::from(b)) .map(|i| (i % modulo, i)) .into_group_map() .into_iter() @@ -1441,7 +1568,7 @@ quickcheck! { assert_eq!( lookup.get(&m).copied(), a.iter() - .map(|&b| b as u64) + .map(|&b| u64::from(b)) .filter(|&val| val % modulo == m) .fold(None, |acc, val| { if val % (modulo - 1) == 0 { @@ -1460,8 +1587,8 @@ quickcheck! { acc: u64, } - let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0` - let lookup = a.iter().map(|&b| b as u64) // Avoid overflows + let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0` + let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows .into_grouping_map_by(|i| i % modulo) .fold_with(|_key, _val| Default::default(), |Accumulator { acc }, &key, val| { assert!(val % modulo == key); @@ -1470,7 +1597,7 @@ quickcheck! { }); let group_map_lookup = a.iter() - .map(|&b| b as u64) + .map(|&b| u64::from(b)) .map(|i| (i % modulo, i)) .into_group_map() .into_iter() @@ -1479,13 +1606,13 @@ quickcheck! { assert_eq!(lookup, group_map_lookup); for (&key, &Accumulator { acc: sum }) in lookup.iter() { - assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::()); + assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::()); } } fn correct_grouping_map_by_fold_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0` - let lookup = a.iter().map(|&b| b as u64) // Avoid overflows + let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0` + let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows .into_grouping_map_by(|i| i % modulo) .fold(0u64, |acc, &key, val| { assert!(val % modulo == key); @@ -1493,7 +1620,7 @@ quickcheck! { }); let group_map_lookup = a.iter() - .map(|&b| b as u64) + .map(|&b| u64::from(b)) .map(|i| (i % modulo, i)) .into_group_map() .into_iter() @@ -1502,13 +1629,13 @@ quickcheck! { assert_eq!(lookup, group_map_lookup); for (&key, &sum) in lookup.iter() { - assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::()); + assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::()); } } fn correct_grouping_map_by_reduce_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0` - let lookup = a.iter().map(|&b| b as u64) // Avoid overflows + let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0` + let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows .into_grouping_map_by(|i| i % modulo) .reduce(|acc, &key, val| { assert!(val % modulo == key); @@ -1516,7 +1643,7 @@ quickcheck! { }); let group_map_lookup = a.iter() - .map(|&b| b as u64) + .map(|&b| u64::from(b)) .map(|i| (i % modulo, i)) .into_group_map() .into_iter() @@ -1525,7 +1652,7 @@ quickcheck! { assert_eq!(lookup, group_map_lookup); for (&key, &sum) in lookup.iter() { - assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::()); + assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::()); } } @@ -1691,12 +1818,12 @@ quickcheck! { } fn correct_grouping_map_by_sum_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0` - let lookup = a.iter().map(|&b| b as u64) // Avoid overflows + let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0` + let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows .into_grouping_map_by(|i| i % modulo) .sum(); - let group_map_lookup = a.iter().map(|&b| b as u64) + let group_map_lookup = a.iter().map(|&b| u64::from(b)) .map(|i| (i % modulo, i)) .into_group_map() .into_iter() @@ -1705,17 +1832,17 @@ quickcheck! { assert_eq!(lookup, group_map_lookup); for (&key, &sum) in lookup.iter() { - assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::()); + assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::()); } } fn correct_grouping_map_by_product_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = Wrapping(if modulo == 0 { 1 } else { modulo } as u64); // Avoid `% 0` - let lookup = a.iter().map(|&b| Wrapping(b as u64)) // Avoid overflows + let modulo = Wrapping(u64::from(if modulo == 0 { 1 } else { modulo })); // Avoid `% 0` + let lookup = a.iter().map(|&b| Wrapping(u64::from(b))) // Avoid overflows .into_grouping_map_by(|i| i % modulo) .product(); - let group_map_lookup = a.iter().map(|&b| Wrapping(b as u64)) + let group_map_lookup = a.iter().map(|&b| Wrapping(u64::from(b))) .map(|i| (i % modulo, i)) .into_group_map() .into_iter() @@ -1727,7 +1854,7 @@ quickcheck! { assert_eq!( prod, a.iter() - .map(|&b| Wrapping(b as u64)) + .map(|&b| Wrapping(u64::from(b))) .filter(|&val| val % modulo == key) .product::>() ); @@ -1832,6 +1959,11 @@ quickcheck! { is_fused(a.combinations_with_replacement(3)) } + fn fused_array_combination_with_replacement(a: Iter) -> bool + { + is_fused(a.clone().array_combinations_with_replacement::<1>()) && + is_fused(a.array_combinations_with_replacement::<3>()) + } fn fused_tuple_combination(a: Iter) -> bool { is_fused(a.clone().fuse().tuple_combinations::<(_,)>()) && @@ -1966,4 +2098,42 @@ quickcheck! { itertools::equal(v.iter().tail(n), result) && itertools::equal(v.iter().filter(|_| true).tail(n), result) } + + fn strip_prefix_matches_str(haystack: String, needle: String) -> bool { + let expected = haystack.strip_prefix(&needle); + let got: Option = haystack + .chars() + .strip_prefix(needle.chars()) + .ok() + .map(Iterator::collect); + got.as_deref() == expected + } + + fn strip_prefix_by_matches_strip_prefix(v: Vec, n: u8) -> bool { + let prefix: Vec = v.iter().take(n as usize).copied().collect(); + let by_eq = v.iter().strip_prefix_by(&prefix, |a, b| **a == **b).ok(); + let plain = v.iter().strip_prefix(prefix.iter()).ok(); + match (by_eq, plain) { + (Some(a), Some(b)) => itertools::equal(a, b), + (None, None) => true, + _ => false, + } + } +} + +#[test] +fn strip_prefix_error_exposes_mismatch_and_remainders() { + let err = (1..6) + .strip_prefix([1, 2, 9, 4]) + .expect_err("third item mismatches"); + assert_eq!(err.mismatch, (Some(3), 9)); + assert_eq!(err.prefix.collect_vec(), vec![4]); + assert_eq!(err.iterator.collect_vec(), vec![4, 5]); +} + +#[test] +fn strip_prefix_error_signals_self_exhausted() { + let err = (1..3).strip_prefix([1, 2, 3]).expect_err("self exhausted"); + assert_eq!(err.mismatch, (None, 3)); + assert!(err.iterator.collect_vec().is_empty()); } diff --git a/third_party/rust/itertools/tests/specializations.rs b/third_party/rust/itertools/tests/specializations.rs index e6694c8e7a32..2c53cf7ae9c9 100644 --- a/third_party/rust/itertools/tests/specializations.rs +++ b/third_party/rust/itertools/tests/specializations.rs @@ -255,6 +255,7 @@ quickcheck! { test_double_ended_specializations(&it); } + #[allow(deprecated)] fn tuple_combinations(v: Vec) -> TestResult { if v.len() > 10 { return TestResult::discard(); @@ -299,6 +300,16 @@ quickcheck! { TestResult::passed() } + fn array_combinations_with_replacement(a: Vec) -> TestResult { + if a.len() > 10 { + return TestResult::discard(); + } + test_specializations(&a.iter().array_combinations_with_replacement::<1>()); + test_specializations(&a.iter().array_combinations_with_replacement::<2>()); + test_specializations(&a.iter().array_combinations_with_replacement::<3>()); + + TestResult::passed() + } fn permutations(a: Vec, n: u8) -> TestResult { if n > 3 || a.len() > 8 { return TestResult::discard(); @@ -503,7 +514,10 @@ quickcheck! { } check_results_specialized!(it, |i| i.count()); - check_results_specialized!(it, |i| i.last()); + check_results_specialized!(it, |i| { + #[allow(clippy::double_ended_iterator_last)] + i.last() + }); check_results_specialized!(it, |i| i.collect::>()); check_results_specialized!(it, |i| i.rev().collect::>()); check_results_specialized!(it, |i| { diff --git a/third_party/rust/itertools/tests/test_core.rs b/third_party/rust/itertools/tests/test_core.rs index 4936160850d7..adaa06e661c2 100644 --- a/third_party/rust/itertools/tests/test_core.rs +++ b/third_party/rust/itertools/tests/test_core.rs @@ -226,7 +226,7 @@ fn batching() { let pit = xs .iter() .cloned() - .batching(|it| it.next().and_then(|x| it.next().map(|y| (x, y)))); + .batching(|it| it.next_array::<2>().map(|[a, b]| (a, b))); it::assert_equal(pit, ys.iter().cloned()); } @@ -281,6 +281,7 @@ fn count_clones() { let f = Foo { n: Cell::new(0) }; let it = it::repeat_n(f, n); // drain it + #[allow(clippy::double_ended_iterator_last)] let last = it.last(); if n == 0 { assert_eq!(last, None); diff --git a/third_party/rust/itertools/tests/test_std.rs b/third_party/rust/itertools/tests/test_std.rs index ad391faad648..5f5cfd1eb0cb 100644 --- a/third_party/rust/itertools/tests/test_std.rs +++ b/third_party/rust/itertools/tests/test_std.rs @@ -9,6 +9,7 @@ use crate::it::multipeek; use crate::it::multizip; use crate::it::peek_nth; use crate::it::repeat_n; +use crate::it::AllEqualValueError; use crate::it::ExactlyOneError; use crate::it::FoldWhile; use crate::it::Itertools; @@ -20,8 +21,31 @@ use rand::{ Rng, SeedableRng, }; use rand::{seq::SliceRandom, thread_rng}; +use std::collections::HashMap; +use std::hash::BuildHasher; +use std::hash::RandomState; +use std::iter::empty; use std::{cmp::min, fmt::Debug, marker::PhantomData}; +// A Hasher which forwards it's calls to RandomState to make sure different hashers +// are accepted in the various *_with_hasher methods. +#[derive(Default)] +struct TestHasher(RandomState); + +impl TestHasher { + fn new() -> Self { + TestHasher(RandomState::new()) + } +} + +impl BuildHasher for TestHasher { + type Hasher = ::Hasher; + + fn build_hasher(&self) -> Self::Hasher { + self.0.build_hasher() + } +} + #[test] fn product3() { let prod = iproduct!(0..3, 0..2, 0..2); @@ -76,6 +100,10 @@ fn duplicates_by() { ys_rev.iter(), xs.iter().duplicates_by(|x| x[..2].to_string()).rev(), ); + + let _ = empty::() + .duplicates_by_with_hasher(|x| *x, TestHasher::new()) + .next(); } #[test] @@ -103,6 +131,10 @@ fn duplicates() { ); let ys_rev = vec![2, 1]; assert_eq!(ys_rev, xs.iter().duplicates().rev().cloned().collect_vec()); + + let _ = empty::() + .duplicates_with_hasher(TestHasher::new()) + .next(); } #[test] @@ -119,6 +151,8 @@ fn unique_by() { ys_rev.iter(), xs.iter().unique_by(|x| x[..2].to_string()).rev(), ); + + let _ = empty::().unique_by_with_hasher(|x| *x, TestHasher::new()); } #[test] @@ -136,6 +170,8 @@ fn unique() { it::assert_equal(ys.iter(), xs.iter().rev().unique().rev()); let ys_rev = [1, 0]; it::assert_equal(ys_rev.iter(), xs.iter().unique().rev()); + + let _ = empty::().unique_with_hasher(TestHasher::new()); } #[test] @@ -282,14 +318,17 @@ fn all_equal() { #[test] fn all_equal_value() { - assert_eq!("".chars().all_equal_value(), Err(None)); + assert_eq!("".chars().all_equal_value(), Err(AllEqualValueError(None))); assert_eq!("A".chars().all_equal_value(), Ok('A')); - assert_eq!("AABBCCC".chars().all_equal_value(), Err(Some(('A', 'B')))); + assert_eq!( + "AABBCCC".chars().all_equal_value(), + Err(AllEqualValueError(Some(['A', 'B']))) + ); assert_eq!("AAAAAAA".chars().all_equal_value(), Ok('A')); { let mut it = [1, 2, 3].iter().copied(); let result = it.all_equal_value(); - assert_eq!(result, Err(Some((1, 2)))); + assert_eq!(result, Err(AllEqualValueError(Some([1, 2])))); let remaining = it.next(); assert_eq!(remaining, Some(3)); assert!(it.next().is_none()); @@ -301,6 +340,8 @@ fn all_unique() { assert!("ABCDEFGH".chars().all_unique()); assert!(!"ABCDEFGA".chars().all_unique()); assert!(::std::iter::empty::().all_unique()); + + let _ = empty::().all_unique_with_hasher(TestHasher::new()); } #[test] @@ -443,13 +484,13 @@ fn kmerge_empty() { #[test] fn kmerge_size_hint() { - let its = (0..5).map(|_| (0..10)); + let its = (0..5).map(|_| 0..10); assert_eq!(its.kmerge().size_hint(), (50, Some(50))); } #[test] fn kmerge_empty_size_hint() { - let its = (0..5).map(|_| (0..0)); + let its = (0..5).map(|_| 0..0); assert_eq!(its.kmerge().size_hint(), (0, Some(0))); } @@ -496,7 +537,7 @@ qc::quickcheck! { fn k_smallest_range(n: i64, m: u16, k: u16) -> () { // u16 is used to constrain k and m to 0..2¹⁶, // otherwise the test could use too much memory. - let (k, m) = (k as usize, m as u64); + let (k, m) = (k as usize, u64::from(m)); let mut v: Vec<_> = (n..n.saturating_add(m as _)).collect(); // Generate a random permutation of n..n+m @@ -532,7 +573,7 @@ qc::quickcheck! { fn k_smallest_relaxed_range(n: i64, m: u16, k: u16) -> () { // u16 is used to constrain k and m to 0..2¹⁶, // otherwise the test could use too much memory. - let (k, m) = (k as usize, m as u64); + let (k, m) = (k as usize, u64::from(m)); let mut v: Vec<_> = (n..n.saturating_add(m as _)).collect(); // Generate a random permutation of n..n+m @@ -1066,9 +1107,15 @@ fn combinations() { ], ); - it::assert_equal((0..0).tuple_combinations::<(_, _)>(), >::new()); - it::assert_equal((0..1).tuple_combinations::<(_, _)>(), >::new()); - it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]); + #[allow(deprecated)] + { + it::assert_equal((0..0).tuple_combinations::<(_, _)>(), >::new()); + it::assert_equal((0..1).tuple_combinations::<(_, _)>(), >::new()); + it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]); + } + it::assert_equal((0..0).array_combinations::<2>(), >::new()); + it::assert_equal((0..1).array_combinations::<2>(), >::new()); + it::assert_equal((0..2).array_combinations::<2>(), vec![[0, 1]]); it::assert_equal((0..0).combinations(2), >>::new()); it::assert_equal((0..1).combinations(1), vec![vec![0]]); @@ -1256,6 +1303,30 @@ fn combinations_with_replacement_range_count() { } } +#[test] +#[cfg(not(miri))] +fn array_combinations_with_replacement() { + // Pool smaller than n + it::assert_equal( + (0..1).array_combinations_with_replacement::<2>(), + vec![[0, 0]], + ); + // Pool larger than n + it::assert_equal( + (0..3).array_combinations_with_replacement::<2>(), + vec![[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]], + ); + // Zero size + it::assert_equal((0..3).array_combinations_with_replacement::<0>(), vec![[]]); + // Zero size on empty pool + it::assert_equal((0..0).array_combinations_with_replacement::<0>(), vec![[]]); + // Empty pool + it::assert_equal( + (0..0).array_combinations_with_replacement::<2>(), + vec![] as Vec<[_; 2]>, + ); +} + #[test] fn powerset() { it::assert_equal((0..0).powerset(), vec![vec![]]); @@ -1507,7 +1578,7 @@ fn tree_reduce() { Some(s.to_string()) }; let num_strings = (0..i).map(|x| x.to_string()); - let actual = num_strings.tree_reduce(|a, b| format!("{} {} x", a, b)); + let actual = num_strings.tree_reduce(|a, b| format!("{a} {b} x")); assert_eq!(actual, expected); } } @@ -1567,3 +1638,40 @@ fn multiunzip() { ) ); } + +#[test] +fn into_group_map_with_hasher() { + let _: HashMap<_, _, TestHasher> = + empty::<(u8, u8)>().into_group_map_with_hasher(TestHasher::new()); +} + +#[test] +fn into_group_map_by_with_hasher() { + let _: HashMap<_, _, TestHasher> = + empty::<(u8, u8)>().into_group_map_by_with_hasher(|x| *x, TestHasher::new()); +} + +#[test] +fn into_grouping_map_with_hasher() { + let _: HashMap<_, Vec<_>, TestHasher> = empty::<(u8, u8)>() + .into_grouping_map_with_hasher(TestHasher::new()) + .collect(); +} + +#[test] +fn into_grouping_map_by_with_hasher() { + let _: HashMap<_, Vec<_>, TestHasher> = empty::<(u8, u8)>() + .into_grouping_map_by_with_hasher(|x| *x, TestHasher::new()) + .collect(); +} + +#[test] +fn counts_with_hasher() { + let _: HashMap<_, _, TestHasher> = empty::().counts_with_hasher(TestHasher::new()); +} + +#[test] +fn counts_by_with_hasher() { + let _: HashMap<_, _, TestHasher> = + empty::().counts_by_with_hasher(|x| x, TestHasher::new()); +} diff --git a/third_party/rust/itertools/tests/zip.rs b/third_party/rust/itertools/tests/zip.rs index daed31e32da4..d44efee0da87 100644 --- a/third_party/rust/itertools/tests/zip.rs +++ b/third_party/rust/itertools/tests/zip.rs @@ -54,3 +54,49 @@ fn test_double_ended_zip() { assert_eq!(it.next_back(), Some((1, 1))); assert_eq!(it.next_back(), None); } + +#[test] +/// The purpose of this test is not really to test the iterator mechanics itself, rather that it +/// compiles and accepts temporary values as inputs, as those would be valid when not used with the +/// izip! macro and zipped manually via .zip calls +fn test_izip_with_temporaries() { + struct Owned { + data: Vec, + } + + impl Owned { + fn new(val: i32) -> Self { + Self { + data: vec![val; 10], + } + } + + fn as_view(&self) -> View<'_> { + View { + data: self.data.as_slice(), + } + } + } + + struct View<'a> { + data: &'a [i32], + } + + impl View<'_> { + fn iter(&self) -> impl Iterator { + self.data.iter() + } + } + + let a = Owned::new(0); + let b = Owned::new(1); + let c = Owned::new(2); + + let mut sum = 0; + + for (x, y, z) in itertools::izip!(a.as_view().iter(), b.as_view().iter(), c.as_view().iter()) { + sum += x + y + z; + } + + assert_eq!(sum, 30); +}