Update itertools to 0.14.0

Test: m
Change-Id: I780e9a4636bf7d00b7ebce6adb19dffbcdc1050e
diff --git a/crates/itertools/.android-checksum.json b/crates/itertools/.android-checksum.json
index bad3edd..1d505e1 100644
--- a/crates/itertools/.android-checksum.json
+++ b/crates/itertools/.android-checksum.json
@@ -1 +1 @@
-{"package":null,"files":{".cargo-checksum.json":"257dc46557410c03abd76c73a69f9adf3e564bbbea257a4b98eeb26162b7f207","Android.bp":"5ee265653e6582d25b05825dc8a2e7e41729cde2b8e667337d995624e817789d","CHANGELOG.md":"f1847e87f3097ef6f806ea99742d417c54cef0c02c96c8a52df8f43f9c92f0db","CONTRIBUTING.md":"0d7ab7d906e3ffb5f7c83efeefe84579106cc9f12a87886f03fdb0ddc5b8f81e","Cargo.lock":"32bc950e9dd34296698a2d5c3ce1e60aa1d7a0526578ae3fa6aeab144dbc41a7","Cargo.toml":"e762efee6c058e7b9ee88bd45fd9fd7aa55bfd288a9af6baafe5dfcae6d192a5","LICENSE":"3c7cd2396b5b772507febd2615d3d5a55b80103845037df77c87ba6e64872f2c","LICENSE-APACHE":"3c7cd2396b5b772507febd2615d3d5a55b80103845037df77c87ba6e64872f2c","LICENSE-MIT":"25045647f8514b43237cf0efdc4ba7dc153f8793e19c9e4b4a65af7e1b78cb5b","METADATA":"f3168c1900d70cac03a3469f5f523109e334aa59e35b95e8724c91a260506fbb","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"9cde44f0b329cdf3c255738ca84b60032f6280349ed2bc63270a4556fb39a065","TEST_MAPPING":"07d90e0d0888f048c20648fd613f2d89945853092265fa9346a3d4254bf0de17","benches/bench1.rs":"3d593f853938bf0d3eaeed26cd39a3afb90c48a8e799a4d4ff0dc26c5eee85f1","benches/combinations.rs":"9b36ec7cf395c2d8892a027914d57b114302f9a0a499959a1ad1c8942742daf8","benches/combinations_with_replacement.rs":"9fa18af6ddfc6f812fcaca4bc77fba4d4a04577251e2bcc25ff2bf5b9478bcdd","benches/fold_specialization.rs":"048b22ee15ca3c8f2da52ea3394527106cd1d8296d59898a7f84ff85c79e68a9","benches/powerset.rs":"47fe0d3cb3ba056283b88d7250c4f250b58b98020aed775a3ee03d26cf63fed4","benches/specializations.rs":"58cf97f0c51b48a491b897f5e5c6ff90854b871f53a27f19db52d2cd44998442","benches/tree_reduce.rs":"88c65e4da528f6df83a37eb720a8441eb284e872a5daf184a1004109937417f3","benches/tuple_combinations.rs":"4bc2c02549fd3aac467fd2c40e4f3134901ef2cecc67d3ace338d42f5d7bddd8","benches/tuples.rs":"07a663fced16df1e519110ba5c2dd9483955f2f21e8fc5171eea60d52bc715d0","cargo_embargo.json":"1c412d446965f40b1f2eb1d39291bb0e0732cc3b9c5fb36737f432d930e23c6e","examples/iris.data":"f952e90ad557c796d4834705174aaf71bb0a235dd09ca9407eff9b5b72a9f76f","examples/iris.rs":"6c3b8e2763ee4fdec1ecd7a4942b2d1bbf71d9658feb866b7420cb7512945c99","src/adaptors/coalesce.rs":"0a14e65588912e47c86c4cc43be4173992ac69958e73e4ca75406bf1a72787c1","src/adaptors/map.rs":"d0d5adb862ba83a9ff8d7bc2c2aa3e794a00639cb93a8355b4388c3d726d5c22","src/adaptors/mod.rs":"87833680388fc63edb2f4c9775a20e2e7e9055da0b527aeeecac9c9c1ffa8ef4","src/adaptors/multi_product.rs":"833ccc206e0d6d0a6e5ec95835c6ef87b9c6ff0db510c3aaf9a5627cd5061feb","src/combinations.rs":"1cea853cdba4b0254520e19129266651dec5a874cd386d7df80f74c05a0f16f3","src/combinations_with_replacement.rs":"7ebf227e9a1999a302e3f4642f27b39a96bad81760a8e0a19c4ec5eb1a20559c","src/concat_impl.rs":"4c0774db0f60c30214dafa73441676e7e81a4d6d64e579a80cc1a3092852266b","src/cons_tuples_impl.rs":"8fe663096421ee4cb48433298d2d3dd574261219004cf862d763256ef0f5073e","src/diff.rs":"a75dbab47313046304d8accbb1a4511800a90a5da861fa800a1bf4a5a04eca3f","src/duplicates_impl.rs":"dd3d4e04af8a85479658115105646159640c1a2b9d2216f251922c97da8b2f49","src/either_or_both.rs":"7c990e808fd7ae8b855a8383be7cc77e7aa3b5fe52044c4a662f2e47e94a9c68","src/exactly_one_err.rs":"558badd3aad0c38c4344a8e1469af442043304af51cde3fb9b41ad4c1581f349","src/extrema_set.rs":"15e5e133bb8efa2a99e8d68b8cbf5466cad6d3d7a5baec1b11a467cb7511da5e","src/flatten_ok.rs":"0bd61298617834e035c68ac9e485bae7f9d89d0fa07b5a2a84818bbddc92abd4","src/format.rs":"266506a1caa9b14caed9a4c4ff0564025d5726fb5119c79db8489635a3f453de","src/free.rs":"75ca79438588826fa2aec14097197a0af139786417dc0902d04f7a8337fd40b1","src/group_map.rs":"f2e97e58f03f36a01e31da3f912bfe1dcd4b456d5c6e05f540c4ec8344891b4b","src/groupbylazy.rs":"6b27e9c5c801e54946dec9e29c5d4bca290d7200a84d4c93a8e4af3ad8c9e3cf","src/grouping_map.rs":"0b62f8987d14956ee7bfdb1d5bbdfe9f01e17b1585647f9ad310332e74ce2e7f","src/impl_macros.rs":"29d480f310b17a1e8c68504d1be6024a3ccf9b4350a93b2cd6ea9b7be279ac6a","src/intersperse.rs":"481b6729e3f98cd62405f0c181aa2bb528508bd084bf3a3054d57c810f6e5c43","src/iter_index.rs":"1d68bf19eed6f975d06131638534e5a7b382f5b03aeb29e1107412bb08ce36a1","src/k_smallest.rs":"ffda60dd32d662c75d3ed9cfa849458e5322fc20ecab0d2dd8cc75c9cbe9c753","src/kmerge_impl.rs":"eaff0331e8a85b5b6a2a3a2041e5546b6d765a2ea0fc948f570d577d8fc646a0","src/lazy_buffer.rs":"8fd6ff0e0700ad6f22543a9cfe209cd10e2284a2c63b769e2cfb9349e154c7d7","src/lib.rs":"590fe6fe598de46afb7eadc289438730913a7236b9a71fbb70db76855ac584dc","src/merge_join.rs":"91f824fb58859d0a0b7925f530a64e91218baf46feece8b5b76974ae5f05f8aa","src/minmax.rs":"6c1eb4f9048153adb841adcbc33c78f237fbadd3b8705289a9fef104b4920693","src/multipeek_impl.rs":"502c545ab39b8db9ea5482b37226c02290aa5ba169b58a9c2427bb38a6f18628","src/pad_tail.rs":"91babaf864d230a402d63c959f1d87a0ff6b6881bb582b213896f7fe5fa61d14","src/peek_nth.rs":"b293ccc75f50919d44653f4453cd27a28bd33f21448df57b1f87a72e38941417","src/peeking_take_while.rs":"9e0bd09c19ed1df98772b43ed16a646d6887ecb6af73e5ebf22889065fd0d770","src/permutations.rs":"1cc667ff17fa7b3a9227f7a96cb861770228c3a1cabb6e0a515cd46ab8ef46c3","src/powerset.rs":"2a55d1100eda58c94a0843a639120df6d26b15318c659404654fcfea0275880e","src/process_results_impl.rs":"1196dae4ae1118e090b46def6b4f4519392000f811c7a9ced031628553f63233","src/put_back_n_impl.rs":"da1b66a391cb0b1d5467fd6257e1dcc86b90a2c12ed03c0bd6cad73a71c3414d","src/rciter_impl.rs":"7774181fcf4b70155123faacd512ba059d18ef05a5a3dd7fb5fab61d7540d99f","src/repeatn.rs":"4d5be3a1d97e91ee94fdc8d508ebe7fb815279db1b06d0e38ddf69e58475ed4a","src/size_hint.rs":"3ef07e7c3fa75bd1469de67452f8eb992a4d6c3e7839e79ff883bfb02ed65839","src/sources.rs":"b9d87801a0c1d39efb657a6f4fa33e95e71fab2230a8e2ae3d02bb686f42cb99","src/take_while_inclusive.rs":"ec3a8501a874422d8a7e6f556c949cc411180e43116ed7fa5f92954829eb56da","src/tee.rs":"9f97c5b4bb44ce437b51e92619274a488bd32eab8a9897c192e64dea9d5fbd9b","src/tuple_impl.rs":"0ece5c00544ffe88c61d89ad7bb997127c86764f17fe1a53e6a0c019ba185984","src/unique_impl.rs":"a99c3ae80697791d7b663b1d8a981fdcfe6e1ca67155c4ac87b4ad1d8fb6e18e","src/unziptuple.rs":"e26d5ab3e522604e84b5286ab0d7f608394677db3b9a69beeb4d557f5871f8d4","src/with_position.rs":"9cdd85aa92ccdadf88dfcd9643a69af6d3e053c5597ef3b00ee62fdc5bbc611d","src/zip_eq_impl.rs":"38fa6317618064c666be842ac1452c04b4f90d2e90e4e2a54266312a13963031","src/zip_longest.rs":"3f9003b0b7c050d53f48d2d36997ea45bb428fa74e5ba13d1df98205f7a51084","src/ziptuple.rs":"552ab217529b637f12b5e39702008f0ac91d2dc0b5d5819b839766d740c64c9e","tests/adaptors_no_collect.rs":"1aa9c1a1f6144f7b7a126c1802c2a791e1bc7d0a6330971ab5d51c1f6ab9e2d9","tests/flatten_ok.rs":"05d7773126bc41913bd6a5db6617c4cf90bb051f6ad5e7c1718694b6a0b4e0c1","tests/laziness.rs":"660e0df9a95e5021d954b57fec5ca18aeb71a6fd8c13637faf0eef023642c084","tests/macros_hygiene.rs":"809cebecb915752fe8e2b5883f8725b0494181775ddbe231bb0945c686dc53b6","tests/merge_join.rs":"cf07e22a97cb496ae2a18ffbecaf797c9cc99f2a0de7958ebf0da86b21590cad","tests/peeking_take_while.rs":"8b0220981b437aa6756f2510ea4e25cf49a19a399a14a465dccff9ad08c48d55","tests/quick.rs":"700de3a8923974ee349a395febd047befb668b4aeb523cfa3c7d0442724ef8b4","tests/specializations.rs":"3d5e5305d4c23d780cd7003c78c87c9f8eccbf32d86680a6ad5da6c2081d7980","tests/test_core.rs":"c3986dcb99a72f8d36203a341acdd71771b96f354a2832f1b25ff0bc740bb6ae","tests/test_std.rs":"818af66b216bafdd527ff456ad4943187f28b59b9eb215c4c38981038192a988","tests/tuples.rs":"92df348f8816e17a3c02eeac420ae33e0a2c6ff994f8171aaecd3875863d2f0f","tests/zip.rs":"f1d057149f847eccaebc110b474df6bc6c65e002be09af64516c46675a10ba99"}}
\ No newline at end of file
+{"package":null,"files":{".cargo-checksum.json":"e4ab3828cab0255c2394a3c0b04bd22eeb1698b2fa7591a4e75b164c8f255260","Android.bp":"6db0a7d0d137b70817938262b39b68e4620d28ef2d1fb85d3cde789a9cff5874","CHANGELOG.md":"943156ca6b8384eb6ab7fd6b52ffb38f0874915fac724845fb1fde34ec56202a","CONTRIBUTING.md":"0d7ab7d906e3ffb5f7c83efeefe84579106cc9f12a87886f03fdb0ddc5b8f81e","Cargo.lock":"bc157173dcde8d4fcb537b05849527e45ba85d079866ae3027feb6d11bcfdaa7","Cargo.toml":"7ab158a0e9c5cac50f97adc234907c1569e51b2f9e47ba74addfd8540c8c337e","LICENSE":"3c7cd2396b5b772507febd2615d3d5a55b80103845037df77c87ba6e64872f2c","LICENSE-APACHE":"3c7cd2396b5b772507febd2615d3d5a55b80103845037df77c87ba6e64872f2c","LICENSE-MIT":"25045647f8514b43237cf0efdc4ba7dc153f8793e19c9e4b4a65af7e1b78cb5b","METADATA":"c48db4794e069d47a59163878e98a4854a6c7e40ff7bd9a512dddaa443b999bb","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"1b66d859b3ffc9629f9389d22b3ef05598e4675af432ba7ba7ba2fa474962174","TEST_MAPPING":"07d90e0d0888f048c20648fd613f2d89945853092265fa9346a3d4254bf0de17","benches/bench1.rs":"3d593f853938bf0d3eaeed26cd39a3afb90c48a8e799a4d4ff0dc26c5eee85f1","benches/combinations.rs":"9b36ec7cf395c2d8892a027914d57b114302f9a0a499959a1ad1c8942742daf8","benches/combinations_with_replacement.rs":"9fa18af6ddfc6f812fcaca4bc77fba4d4a04577251e2bcc25ff2bf5b9478bcdd","benches/fold_specialization.rs":"048b22ee15ca3c8f2da52ea3394527106cd1d8296d59898a7f84ff85c79e68a9","benches/k_smallest.rs":"bb2b1f1e05814a42da916884727ac550ee995c3b90070497c41d9906cbefbb1b","benches/powerset.rs":"47fe0d3cb3ba056283b88d7250c4f250b58b98020aed775a3ee03d26cf63fed4","benches/specializations.rs":"1662f3f02d989458de47c219ef6dd507f75ee9e0046fabd198ac4b2ddf83c299","benches/tree_reduce.rs":"88c65e4da528f6df83a37eb720a8441eb284e872a5daf184a1004109937417f3","benches/tuple_combinations.rs":"4bc2c02549fd3aac467fd2c40e4f3134901ef2cecc67d3ace338d42f5d7bddd8","benches/tuples.rs":"07a663fced16df1e519110ba5c2dd9483955f2f21e8fc5171eea60d52bc715d0","cargo_embargo.json":"1c412d446965f40b1f2eb1d39291bb0e0732cc3b9c5fb36737f432d930e23c6e","examples/iris.data":"f952e90ad557c796d4834705174aaf71bb0a235dd09ca9407eff9b5b72a9f76f","examples/iris.rs":"6c3b8e2763ee4fdec1ecd7a4942b2d1bbf71d9658feb866b7420cb7512945c99","src/adaptors/coalesce.rs":"0a14e65588912e47c86c4cc43be4173992ac69958e73e4ca75406bf1a72787c1","src/adaptors/map.rs":"d0d5adb862ba83a9ff8d7bc2c2aa3e794a00639cb93a8355b4388c3d726d5c22","src/adaptors/mod.rs":"42b75e89940d8ebb8cf8c16032d56100a12c73bc567316666d4710feec3e71b9","src/adaptors/multi_product.rs":"833ccc206e0d6d0a6e5ec95835c6ef87b9c6ff0db510c3aaf9a5627cd5061feb","src/combinations.rs":"011a33f4b1e2ae57380800d5878c27a736fab0ed7f3b676d0be655cdad8d22b7","src/combinations_with_replacement.rs":"1dd4c50b9add8cba32f47571449cd03bb93db52013c9e8ffe9ca3acb851c01c8","src/concat_impl.rs":"4ab66a9a9800bc20d061a23d6a7bca235f038865850860da77311a0ddf852fc1","src/cons_tuples_impl.rs":"cbfaec74702bb6397b1005b8460b1ba2cfb7c52771b9009dd730a8bff45c09b9","src/diff.rs":"a66f924d8f57718a36e13b5aee2fe142fbb4e2d8ab974a2a83c9f6405278d7d0","src/duplicates_impl.rs":"dd3d4e04af8a85479658115105646159640c1a2b9d2216f251922c97da8b2f49","src/either_or_both.rs":"7c990e808fd7ae8b855a8383be7cc77e7aa3b5fe52044c4a662f2e47e94a9c68","src/exactly_one_err.rs":"558badd3aad0c38c4344a8e1469af442043304af51cde3fb9b41ad4c1581f349","src/extrema_set.rs":"dbbb20f4f293a74dad55b0c0286a38b6849ce918c9085274aafbc7fbde9de013","src/flatten_ok.rs":"0bd61298617834e035c68ac9e485bae7f9d89d0fa07b5a2a84818bbddc92abd4","src/format.rs":"4c5f963ea4a9d4da941c2209496596d895d73db968b1e41b09be39589eb36ac6","src/free.rs":"b6f64938e164559b0a7eb2696d2f460efae6373f4edde12ce2d247b9a67bc526","src/group_map.rs":"f2e97e58f03f36a01e31da3f912bfe1dcd4b456d5c6e05f540c4ec8344891b4b","src/groupbylazy.rs":"6b27e9c5c801e54946dec9e29c5d4bca290d7200a84d4c93a8e4af3ad8c9e3cf","src/grouping_map.rs":"116a100889201637b519cc33dcf20fbf0ce403a1008fddc5f7dc82e6fb34fcf5","src/impl_macros.rs":"29d480f310b17a1e8c68504d1be6024a3ccf9b4350a93b2cd6ea9b7be279ac6a","src/intersperse.rs":"481b6729e3f98cd62405f0c181aa2bb528508bd084bf3a3054d57c810f6e5c43","src/iter_index.rs":"1d68bf19eed6f975d06131638534e5a7b382f5b03aeb29e1107412bb08ce36a1","src/k_smallest.rs":"381043da6b7af62574c5c5034dd55bb1eb7074cc32b1df1340c921e67463b150","src/kmerge_impl.rs":"9670e60ba6ef3c6c51713ccd3eee46f1744393daaa4833ebbe52df7c6965f3b6","src/lazy_buffer.rs":"0bf7a4fe8a7d3d23783bf61e674bfd0ba03cca55cc1d0549145758611f1bdbed","src/lib.rs":"a2156c5f51ce3559c21f6f5eb63e7d0c7fae75cc9e93ec54d09f106198507b07","src/merge_join.rs":"b7ef9d7a3654279e808f32b7751c752f2db5fa35521affd0ed560fa5303e06e1","src/minmax.rs":"6c1eb4f9048153adb841adcbc33c78f237fbadd3b8705289a9fef104b4920693","src/multipeek_impl.rs":"502c545ab39b8db9ea5482b37226c02290aa5ba169b58a9c2427bb38a6f18628","src/next_array.rs":"fd5904fc07fb4b9e4c48a2771a3d300ffabe9db0680ebe96ea754d21e6d2876f","src/pad_tail.rs":"91babaf864d230a402d63c959f1d87a0ff6b6881bb582b213896f7fe5fa61d14","src/peek_nth.rs":"b293ccc75f50919d44653f4453cd27a28bd33f21448df57b1f87a72e38941417","src/peeking_take_while.rs":"ff66fc7a97a9101a04ec5f4a0e56b5754c69ce7b27f3132c5d376b30a1f0b19d","src/permutations.rs":"1cc667ff17fa7b3a9227f7a96cb861770228c3a1cabb6e0a515cd46ab8ef46c3","src/powerset.rs":"2a55d1100eda58c94a0843a639120df6d26b15318c659404654fcfea0275880e","src/process_results_impl.rs":"67c7cd60171053c21939252b71aad6879d6ad251a6ea3d50af1ffb0d0b4241bd","src/put_back_n_impl.rs":"da1b66a391cb0b1d5467fd6257e1dcc86b90a2c12ed03c0bd6cad73a71c3414d","src/rciter_impl.rs":"3aa04cdf4cbd96ddff4b210e90652e346177663b1993836b0f88215043ab228b","src/repeatn.rs":"4d5be3a1d97e91ee94fdc8d508ebe7fb815279db1b06d0e38ddf69e58475ed4a","src/size_hint.rs":"3ef07e7c3fa75bd1469de67452f8eb992a4d6c3e7839e79ff883bfb02ed65839","src/sources.rs":"b9d87801a0c1d39efb657a6f4fa33e95e71fab2230a8e2ae3d02bb686f42cb99","src/take_while_inclusive.rs":"ec3a8501a874422d8a7e6f556c949cc411180e43116ed7fa5f92954829eb56da","src/tee.rs":"9f97c5b4bb44ce437b51e92619274a488bd32eab8a9897c192e64dea9d5fbd9b","src/tuple_impl.rs":"0ece5c00544ffe88c61d89ad7bb997127c86764f17fe1a53e6a0c019ba185984","src/unique_impl.rs":"a99c3ae80697791d7b663b1d8a981fdcfe6e1ca67155c4ac87b4ad1d8fb6e18e","src/unziptuple.rs":"e26d5ab3e522604e84b5286ab0d7f608394677db3b9a69beeb4d557f5871f8d4","src/with_position.rs":"9cdd85aa92ccdadf88dfcd9643a69af6d3e053c5597ef3b00ee62fdc5bbc611d","src/zip_eq_impl.rs":"10ea8763cf64c9f20172c5b041de10108f5c366f6f91bd153d00a8755d01ed94","src/zip_longest.rs":"3f9003b0b7c050d53f48d2d36997ea45bb428fa74e5ba13d1df98205f7a51084","src/ziptuple.rs":"552ab217529b637f12b5e39702008f0ac91d2dc0b5d5819b839766d740c64c9e","tests/adaptors_no_collect.rs":"1aa9c1a1f6144f7b7a126c1802c2a791e1bc7d0a6330971ab5d51c1f6ab9e2d9","tests/flatten_ok.rs":"05d7773126bc41913bd6a5db6617c4cf90bb051f6ad5e7c1718694b6a0b4e0c1","tests/laziness.rs":"660e0df9a95e5021d954b57fec5ca18aeb71a6fd8c13637faf0eef023642c084","tests/macros_hygiene.rs":"b5a9053e2a9fdc6a3f958092846b9201ae4c94a84cf853aafbd4079c8cc9aa50","tests/merge_join.rs":"cf07e22a97cb496ae2a18ffbecaf797c9cc99f2a0de7958ebf0da86b21590cad","tests/peeking_take_while.rs":"8b0220981b437aa6756f2510ea4e25cf49a19a399a14a465dccff9ad08c48d55","tests/quick.rs":"8673d4fa3aac895fddfbe0d772a162cb193cbd2f05e84ed89a281f66b4cbae99","tests/specializations.rs":"a7af5260416febe23c4175b6c744bfcaccc0ccff5034a9758b2f89ba837b7a24","tests/test_core.rs":"ff3e834c8a3cf0d12b2e4e90b696fd5406a9ca588517f5c5630c8fe5fae5556c","tests/test_std.rs":"4c761b1379cb4a48a8f995d7525f59263fd1942c33a486b72555f80115199d68","tests/tuples.rs":"92df348f8816e17a3c02eeac420ae33e0a2c6ff994f8171aaecd3875863d2f0f","tests/zip.rs":"3767be9b0e8bdbcf1a41a6230a968d14263cb5fb6941af4ecf4bbe7782a7a0b2"}}
\ No newline at end of file
diff --git a/crates/itertools/.cargo-checksum.json b/crates/itertools/.cargo-checksum.json
index 38bbe13..13a4681 100644
--- a/crates/itertools/.cargo-checksum.json
+++ b/crates/itertools/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"ceee4376468a3f7647f3bf4649e195a86873dd3091f23e3f992d248bd143fba2","CONTRIBUTING.md":"d5787d0fd4df15481e2e09a37234ac5dec22c007c890826991f633d890efa29e","Cargo.lock":"fd2c9ca8e299f51d7ed2a0f3760c393f03c544c817743ab7341c1f22b8c1d869","Cargo.toml":"49abb2101a0dd9cb137df206454b6620d04929a4975921fab6682ba834435620","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"fc812ab0d5756b62c2ae34f38365899204b53332d5e6a87a695b0fe15a466957","benches/bench1.rs":"d632c8b839d7b318d1cb7b81b9c62570c77dcdf0696b8ce3d52067c79c930f78","benches/combinations.rs":"5b3bd243336d6b6bdc111d66218f3f0a4ecdb10fb72e90db79959e3d8bb2cf6f","benches/combinations_with_replacement.rs":"11f29160652a2d90ce7ca4b1c339c4457888ab6867e2456ce1c62e3adf9be737","benches/fold_specialization.rs":"66ab13fd8576a662afb59ef72c5565f5c3d27f7f30a976450ee5a14958654fa2","benches/powerset.rs":"dc1fd729584147e5d8e4d19c6ca6f8706087d41c3c5beb7293d9ea43b4beab14","benches/specializations.rs":"d8320071a692147c1239881725079003be2f924f6124c3aa3bdf6a4596d66a66","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":"7064a1043baec815c02803d5043bd950e6a515f3a0247e44028ee080004dc225","src/adaptors/multi_product.rs":"ad501e8ae4e5089b9d2f2be1f9a4713da6a2103b14daa759e09918409f88e321","src/combinations.rs":"6c1cd55051eb59c595780b055ccabb07db72add134120dd8b2f5aa60c0f5fa6e","src/combinations_with_replacement.rs":"cad1885ca51e52a1dc324a0b06bd0d1d911f1dd58cf5d76bd9a9c78a09853b86","src/concat_impl.rs":"6094463eb57f77e115f6a3fe7f469992eef81c0c4caa9585b99a426d87f794fb","src/cons_tuples_impl.rs":"3ceee1ff0dbd4c3b43195a490b8f38b05de3a46e0fb691ba11fbbe1e7e3ad746","src/diff.rs":"046b3ac4a22036b9ec8741aba4e8f6729ae44bf14346b61c23192b88d9fc7c88","src/duplicates_impl.rs":"1be37249b4566edc8da611ed9766ec851a526e7513bd13d80fe97482dcfcf7f3","src/either_or_both.rs":"cac278666b5d3c1fd103d97d15ce4c40960ea459441aeae83c6502087fd2ad8d","src/exactly_one_err.rs":"90b6204551161d27394af72107765dbfe3b51a77f4770c2e506fa4938985a184","src/extrema_set.rs":"7e0d92ca1aafc1221e08d0297087b35373463d03228a0e65628cfd1734273e90","src/flatten_ok.rs":"62c18e5221a27949a00de49414306d6dfd601515817c1c8ae6189e3275756dd3","src/format.rs":"94675a6ac4500ec52bbf8463b2241b870fea8b5dd6b113accb8a00b2c1174871","src/free.rs":"6f3597a5ccf8a9b0606da7df6803f7368152ebcf7b7bcfd31b17fcff3a286139","src/group_map.rs":"c9da201137c6bb479b9308bfc38398b76950e39905f4ce8bc435c5318371522c","src/groupbylazy.rs":"5862629719258703aad47977ba1060f20fff15e962e18e6142758ebf6cd4a61c","src/grouping_map.rs":"8dac807a6cbf1893fdc147b4160000c452bfb5e533e1c774ed6bd3af91cf46da","src/impl_macros.rs":"97fc5f39574805e0c220aa462cf1ae7dcac5c1082d6ee5500e7d71c120db5f88","src/intersperse.rs":"55031819e985c3184275e254c9600ecbe01e9fb49f198039c5da82a87ea5b90e","src/iter_index.rs":"1b0ff8376a4ad855d44db8c662450c777db84e0f4997b53ca575c65b107bb83b","src/k_smallest.rs":"6a665742f6665e350a54ae3ff821252e7c599b57aee3239a03fa56a9d1930467","src/kmerge_impl.rs":"2e425d4189898566c5146e8f5bd258045c246f6babbe3ac5fef10ca08ae2efd2","src/lazy_buffer.rs":"a065f73c228f156bdf901824977ea9375f912823af4f9b05378e3f633d3b20e4","src/lib.rs":"75903dcd21573a8a77a205cfb8d335c60c2939771481c6431c29a0918d8dbfb0","src/merge_join.rs":"bb1fccddcc647fe21da1895a8808c06596d49900f5cf60a69a9c9141fc12af11","src/minmax.rs":"0ec34b172ca8efc4aacb96f3e5771bdc5e8ac882876ee0f59d698c3924717c48","src/multipeek_impl.rs":"79eef0be49ad66f15d41808e72c03976c4f7cff5838b69d17975d3ece266f3f8","src/pad_tail.rs":"e6bb5b086478600b0dbb8726cae8364bf83ab36d989ef467e1264eea43933b50","src/peek_nth.rs":"093f1a157b1c917f041af5244a5a46311affa2922126e36dc0ee2c501c79b58c","src/peeking_take_while.rs":"6967ba212f045145da7683a192471b2dcfcedf90d23922d70a5b7e2a1b36622e","src/permutations.rs":"b316084ee14e9e138d22f177367b3bfa24cb3e5e90ab20b9b00a9a23d653496f","src/powerset.rs":"7ab24fefc914b339dd92a6c8e639d0cad34479e09293b3346078856d6bc02d34","src/process_results_impl.rs":"a6f91aec53c56b042e15ecb8f8ca489c81e3ee92347dc9fa8352a5baac44a247","src/put_back_n_impl.rs":"5a58d7a31c03029f0726e4d42de3be869580cf76b73c6d1ef70dd40c240b03a0","src/rciter_impl.rs":"9a50cdc0106587be8ee49c2af5fcf84436b74d353c2846b401eb638c23b4733c","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":"4e0d38266c26982ea8b8d055994cb1298e93b7749caadbd7f25d2b6e0c8ce0d7","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":"c9e9f0546a8c12ea52311c0eadd77d75c782d4e10ae9e74d410ea2861d526c66","tests/merge_join.rs":"5fb506b989f4a331d46cdec5775ea594656985134196099eaf8d3905bdddcdd5","tests/peeking_take_while.rs":"f834361c5520dda15eb9e9ebe87507c905462201412b21859d9f83dab91d0e0b","tests/quick.rs":"60b1ca6d820aa505545f20d6082fd08c1e0470b5326b711567ec1c93d07f9ced","tests/specializations.rs":"7c6a461850a2b4f783801ef23b2303ad985c58f2295c569001369b3c9d4c6e33","tests/test_core.rs":"482e077e0c5fe78ba0a8a126d8c0821162d820a21936855fadede713b1d4e70a","tests/test_std.rs":"f788573adc9ae19eb4bd2886c3967b273dd881982af407f6f5b6276434df0f00","tests/tuples.rs":"014e4da776174bfe923270e2a359cd9c95b372fce4b952b8138909d6e2c52762","tests/zip.rs":"2f68d531170fa2f106efafaf38ae854281d93305bf1b2b8d4bea833072518ecd"},"package":"413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"60ec9a1801e015e49f7fbb299b608ac730d5b1a3fb298e6cf7935c0695ddf7fe","CONTRIBUTING.md":"d5787d0fd4df15481e2e09a37234ac5dec22c007c890826991f633d890efa29e","Cargo.lock":"4422e732d4ce6f650afb53a1dcffb1e53c86dd066c3dcd66bc9620acd898b99e","Cargo.toml":"77735549383196a4156a2246dd1cd6742029b223679b3004531456d33562b0ce","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
diff --git a/crates/itertools/Android.bp b/crates/itertools/Android.bp
index 18776c3..9e1cffa 100644
--- a/crates/itertools/Android.bp
+++ b/crates/itertools/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "itertools",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.13.0",
+    cargo_pkg_version: "0.14.0",
     crate_root: "src/lib.rs",
     edition: "2018",
     features: [
diff --git a/crates/itertools/CHANGELOG.md b/crates/itertools/CHANGELOG.md
index de9564c..6b08f68 100644
--- a/crates/itertools/CHANGELOG.md
+++ b/crates/itertools/CHANGELOG.md
@@ -1,5 +1,36 @@
 # Changelog
 
+## 0.14.0
+
+### Breaking
+- Increased MSRV to 1.63.0 (#960)
+- Removed generic parameter from `cons_tuples` (#988)
+
+### Added
+- Added `array_combinations` (#991)
+- Added `k_smallest_relaxed` and variants (#925)
+- Added `next_array` and `collect_array` (#560)
+- Implemented `DoubleEndedIterator` for `FilterOk` (#948)
+- Implemented `DoubleEndedIterator` for `FilterMapOk` (#950)
+
+### Changed
+- Allow `Q: ?Sized` in `Itertools::contains` (#971)
+- Improved hygiene of `chain!` (#943)
+- Improved `into_group_map_by` documentation (#1000)
+- Improved `tree_reduce` documentation (#955)
+- Improved discoverability of `merge_join_by` (#966)
+- Improved discoverability of `take_while_inclusive` (#972)
+- Improved documentation of `find_or_last` and `find_or_first` (#984)
+- Prevented exponentially large type sizes in `tuple_combinations` (#945)
+- Added `track_caller` attr for `asser_equal` (#976)
+
+### Notable Internal Changes
+- Fixed clippy lints (#956, #987, #1008)
+- Addressed warnings within doctests (#964)
+- CI: Run most tests with miri (#961)
+- CI: Speed up "cargo-semver-checks" action (#938)
+- Changed an instance of `default_features` in `Cargo.toml` to `default-features` (#985)
+
 ## 0.13.0
 
 ### Breaking
diff --git a/crates/itertools/Cargo.lock b/crates/itertools/Cargo.lock
index d2183c2..fbf369b 100644
--- a/crates/itertools/Cargo.lock
+++ b/crates/itertools/Cargo.lock
@@ -236,7 +236,7 @@
 
 [[package]]
 name = "itertools"
-version = "0.13.0"
+version = "0.14.0"
 dependencies = [
  "criterion",
  "either",
diff --git a/crates/itertools/Cargo.toml b/crates/itertools/Cargo.toml
index 21896fe..96f9597 100644
--- a/crates/itertools/Cargo.toml
+++ b/crates/itertools/Cargo.toml
@@ -11,10 +11,16 @@
 
 [package]
 edition = "2018"
-rust-version = "1.43.1"
+rust-version = "1.63.0"
 name = "itertools"
-version = "0.13.0"
+version = "0.14.0"
 authors = ["bluss"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "Extra iterator adaptors, iterator methods, free functions, and macros."
 documentation = "https://docs.rs/itertools/"
 readme = "README.md"
@@ -33,47 +39,120 @@
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-itertools/itertools"
 
-[profile.bench]
-debug = 2
+[features]
+default = ["use_std"]
+use_alloc = []
+use_std = [
+    "use_alloc",
+    "either/use_std",
+]
 
 [lib]
+name = "itertools"
+path = "src/lib.rs"
 test = false
 bench = false
 
-[[bench]]
-name = "tuple_combinations"
-harness = false
+[[example]]
+name = "iris"
+path = "examples/iris.rs"
 
-[[bench]]
+[[test]]
+name = "adaptors_no_collect"
+path = "tests/adaptors_no_collect.rs"
+
+[[test]]
+name = "flatten_ok"
+path = "tests/flatten_ok.rs"
+
+[[test]]
+name = "laziness"
+path = "tests/laziness.rs"
+
+[[test]]
+name = "macros_hygiene"
+path = "tests/macros_hygiene.rs"
+
+[[test]]
+name = "merge_join"
+path = "tests/merge_join.rs"
+
+[[test]]
+name = "peeking_take_while"
+path = "tests/peeking_take_while.rs"
+
+[[test]]
+name = "quick"
+path = "tests/quick.rs"
+
+[[test]]
+name = "specializations"
+path = "tests/specializations.rs"
+
+[[test]]
+name = "test_core"
+path = "tests/test_core.rs"
+
+[[test]]
+name = "test_std"
+path = "tests/test_std.rs"
+
+[[test]]
 name = "tuples"
-harness = false
+path = "tests/tuples.rs"
 
-[[bench]]
-name = "fold_specialization"
-harness = false
-
-[[bench]]
-name = "combinations_with_replacement"
-harness = false
-
-[[bench]]
-name = "tree_reduce"
-harness = false
+[[test]]
+name = "zip"
+path = "tests/zip.rs"
 
 [[bench]]
 name = "bench1"
+path = "benches/bench1.rs"
 harness = false
 
 [[bench]]
 name = "combinations"
+path = "benches/combinations.rs"
+harness = false
+
+[[bench]]
+name = "combinations_with_replacement"
+path = "benches/combinations_with_replacement.rs"
+harness = false
+
+[[bench]]
+name = "fold_specialization"
+path = "benches/fold_specialization.rs"
+harness = false
+
+[[bench]]
+name = "k_smallest"
+path = "benches/k_smallest.rs"
 harness = false
 
 [[bench]]
 name = "powerset"
+path = "benches/powerset.rs"
 harness = false
 
 [[bench]]
 name = "specializations"
+path = "benches/specializations.rs"
+harness = false
+
+[[bench]]
+name = "tree_reduce"
+path = "benches/tree_reduce.rs"
+harness = false
+
+[[bench]]
+name = "tuple_combinations"
+path = "benches/tuple_combinations.rs"
+harness = false
+
+[[bench]]
+name = "tuples"
+path = "benches/tuples.rs"
 harness = false
 
 [dependencies.either]
@@ -82,6 +161,7 @@
 
 [dev-dependencies.criterion]
 version = "0.4.0"
+features = ["html_reports"]
 
 [dev-dependencies.paste]
 version = "1.0.0"
@@ -91,15 +171,10 @@
 
 [dev-dependencies.quickcheck]
 version = "0.9"
-default_features = false
+default-features = false
 
 [dev-dependencies.rand]
 version = "0.7"
 
-[features]
-default = ["use_std"]
-use_alloc = []
-use_std = [
-    "use_alloc",
-    "either/use_std",
-]
+[profile.bench]
+debug = 2
diff --git a/crates/itertools/METADATA b/crates/itertools/METADATA
index 6bb1771..775971a 100644
--- a/crates/itertools/METADATA
+++ b/crates/itertools/METADATA
@@ -1,17 +1,17 @@
 name: "itertools"
 description: "Extra iterator adaptors, iterator methods, free functions, and macros."
 third_party {
-  version: "0.13.0"
+  version: "0.14.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2024
-    month: 9
-    day: 4
+    year: 2025
+    month: 1
+    day: 14
   }
   homepage: "https://crates.io/crates/itertools"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/itertools/itertools-0.13.0.crate"
-    version: "0.13.0"
+    value: "https://static.crates.io/crates/itertools/itertools-0.14.0.crate"
+    version: "0.14.0"
   }
 }
diff --git a/crates/itertools/README.md b/crates/itertools/README.md
index 982ef5d..46acc3f 100644
--- a/crates/itertools/README.md
+++ b/crates/itertools/README.md
@@ -8,7 +8,7 @@
 
 ```toml
 [dependencies]
-itertools = "0.13.0"
+itertools = "0.14.0"
 ```
 
 How to use in your crate:
diff --git a/crates/itertools/benches/k_smallest.rs b/crates/itertools/benches/k_smallest.rs
new file mode 100644
index 0000000..509ed7f
--- /dev/null
+++ b/crates/itertools/benches/k_smallest.rs
@@ -0,0 +1,61 @@
+use criterion::{black_box, criterion_group, criterion_main, Bencher, BenchmarkId, Criterion};
+use itertools::Itertools;
+use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng};
+
+fn strict(b: &mut Bencher, (k, vals): &(usize, &Vec<usize>)) {
+    b.iter(|| black_box(vals.iter()).k_smallest(*k))
+}
+
+fn relaxed(b: &mut Bencher, (k, vals): &(usize, &Vec<usize>)) {
+    b.iter(|| black_box(vals.iter()).k_smallest_relaxed(*k))
+}
+
+fn ascending(n: usize) -> Vec<usize> {
+    (0..n).collect()
+}
+
+fn random(n: usize) -> Vec<usize> {
+    let mut vals = (0..n).collect_vec();
+    vals.shuffle(&mut StdRng::seed_from_u64(42));
+    vals
+}
+
+fn descending(n: usize) -> Vec<usize> {
+    (0..n).rev().collect()
+}
+
+fn k_smallest(c: &mut Criterion, order: &str, vals: fn(usize) -> Vec<usize>) {
+    let mut g = c.benchmark_group(format!("k-smallest/{order}"));
+
+    for log_n in 20..23 {
+        let n = 1 << log_n;
+
+        let vals = vals(n);
+
+        for log_k in 7..10 {
+            let k = 1 << log_k;
+
+            let params = format!("{log_n}/{log_k}");
+            let input = (k, &vals);
+            g.bench_with_input(BenchmarkId::new("strict", &params), &input, strict);
+            g.bench_with_input(BenchmarkId::new("relaxed", &params), &input, relaxed);
+        }
+    }
+
+    g.finish()
+}
+
+fn k_smallest_asc(c: &mut Criterion) {
+    k_smallest(c, "asc", ascending);
+}
+
+fn k_smallest_rand(c: &mut Criterion) {
+    k_smallest(c, "rand", random);
+}
+
+fn k_smallest_desc(c: &mut Criterion) {
+    k_smallest(c, "desc", descending);
+}
+
+criterion_group!(benches, k_smallest_asc, k_smallest_rand, k_smallest_desc);
+criterion_main!(benches);
diff --git a/crates/itertools/benches/specializations.rs b/crates/itertools/benches/specializations.rs
index 18039fc..e70323f 100644
--- a/crates/itertools/benches/specializations.rs
+++ b/crates/itertools/benches/specializations.rs
@@ -1,4 +1,4 @@
-#![allow(unstable_name_collisions, clippy::incompatible_msrv)]
+#![allow(unstable_name_collisions)]
 
 use criterion::black_box;
 use criterion::BenchmarkId;
@@ -639,6 +639,7 @@
         v.iter().copied().map_ok(|x| x + 1)
     }
     filter_ok {
+        DoubleEndedIterator
         {
             let v = black_box((0_u32..1024)
                 .map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
@@ -647,6 +648,7 @@
         v.iter().copied().filter_ok(|x| x % 3 == 0)
     }
     filter_map_ok {
+        DoubleEndedIterator
         {
             let v = black_box((0_u32..1024)
                 .map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
diff --git a/crates/itertools/src/adaptors/mod.rs b/crates/itertools/src/adaptors/mod.rs
index 52e36c4..77192f2 100644
--- a/crates/itertools/src/adaptors/mod.rs
+++ b/crates/itertools/src/adaptors/mod.rs
@@ -515,7 +515,7 @@
     f: F,
 }
 
-impl<'a, I, F> fmt::Debug for TakeWhileRef<'a, I, F>
+impl<I, F> fmt::Debug for TakeWhileRef<'_, I, F>
 where
     I: Iterator + fmt::Debug,
 {
@@ -530,7 +530,7 @@
     TakeWhileRef { iter, f }
 }
 
-impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F>
+impl<I, F> Iterator for TakeWhileRef<'_, I, F>
 where
     I: Iterator + Clone,
     F: FnMut(&I::Item) -> bool,
@@ -773,16 +773,28 @@
             where
                 F: FnMut(B, Self::Item) -> B,
             {
+                // We outline this closure to prevent it from unnecessarily
+                // capturing the type parameters `I`, `B`, and `F`. Not doing
+                // so ended up causing exponentially big types during MIR
+                // inlining when building itertools with optimizations enabled.
+                //
+                // This change causes a small improvement to compile times in
+                // release mode.
+                type CurrTuple<A> = (A, $(ignore_ident!($X, A)),*);
+                type PrevTuple<A> = ($(ignore_ident!($X, A),)*);
+                fn map_fn<A: Clone>(z: &A) -> impl FnMut(PrevTuple<A>) -> CurrTuple<A> + '_ {
+                    move |($($X,)*)| (z.clone(), $($X),*)
+                }
                 let Self { c, item, mut iter } = self;
                 if let Some(z) = item.as_ref() {
                     init = c
-                        .map(|($($X,)*)| (z.clone(), $($X),*))
+                        .map(map_fn::<A>(z))
                         .fold(init, &mut f);
                 }
                 while let Some(z) = iter.next() {
                     let c: $P<I> = iter.clone().into();
                     init = c
-                        .map(|($($X,)*)| (z.clone(), $($X),*))
+                        .map(map_fn::<A>(&z))
                         .fold(init, &mut f);
                 }
                 init
@@ -924,6 +936,30 @@
     }
 }
 
+impl<I, F, T, E> DoubleEndedIterator for FilterOk<I, F>
+where
+    I: DoubleEndedIterator<Item = Result<T, E>>,
+    F: FnMut(&T) -> bool,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        let f = &mut self.f;
+        self.iter.rfind(|res| match res {
+            Ok(t) => f(t),
+            _ => true,
+        })
+    }
+
+    fn rfold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc
+    where
+        Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let mut f = self.f;
+        self.iter
+            .filter(|v| v.as_ref().map(&mut f).unwrap_or(true))
+            .rfold(init, fold_f)
+    }
+}
+
 impl<I, F, T, E> FusedIterator for FilterOk<I, F>
 where
     I: FusedIterator<Item = Result<T, E>>,
@@ -1005,6 +1041,30 @@
     }
 }
 
+impl<I, F, T, U, E> DoubleEndedIterator for FilterMapOk<I, F>
+where
+    I: DoubleEndedIterator<Item = Result<T, E>>,
+    F: FnMut(T) -> Option<U>,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        let f = &mut self.f;
+        self.iter.by_ref().rev().find_map(|res| match res {
+            Ok(t) => f(t).map(Ok),
+            Err(e) => Some(Err(e)),
+        })
+    }
+
+    fn rfold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc
+    where
+        Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let mut f = self.f;
+        self.iter
+            .filter_map(|v| transpose_result(v.map(&mut f)))
+            .rfold(init, fold_f)
+    }
+}
+
 impl<I, F, T, U, E> FusedIterator for FilterMapOk<I, F>
 where
     I: FusedIterator<Item = Result<T, E>>,
@@ -1048,9 +1108,7 @@
 
     fn next(&mut self) -> Option<Self::Item> {
         let f = &mut self.f;
-        // TODO: once MSRV >= 1.62, use `then_some`.
-        self.iter
-            .find_map(|(count, val)| if f(val) { Some(count) } else { None })
+        self.iter.find_map(|(count, val)| f(val).then_some(count))
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -1078,11 +1136,10 @@
 {
     fn next_back(&mut self) -> Option<Self::Item> {
         let f = &mut self.f;
-        // TODO: once MSRV >= 1.62, use `then_some`.
         self.iter
             .by_ref()
             .rev()
-            .find_map(|(count, val)| if f(val) { Some(count) } else { None })
+            .find_map(|(count, val)| f(val).then_some(count))
     }
 
     fn rfold<B, G>(self, init: B, mut func: G) -> B
diff --git a/crates/itertools/src/combinations.rs b/crates/itertools/src/combinations.rs
index 6bb2f3e..54a0275 100644
--- a/crates/itertools/src/combinations.rs
+++ b/crates/itertools/src/combinations.rs
@@ -1,3 +1,5 @@
+use core::array;
+use core::borrow::BorrowMut;
 use std::fmt;
 use std::iter::FusedIterator;
 
@@ -6,45 +8,101 @@
 
 use crate::adaptors::checked_binomial;
 
+/// Iterator for `Vec` valued combinations returned by [`.combinations()`](crate::Itertools::combinations)
+pub type Combinations<I> = CombinationsGeneric<I, Vec<usize>>;
+/// Iterator for const generic combinations returned by [`.array_combinations()`](crate::Itertools::array_combinations)
+pub type ArrayCombinations<I, const K: usize> = CombinationsGeneric<I, [usize; K]>;
+
+/// Create a new `Combinations` from a clonable iterator.
+pub fn combinations<I: Iterator>(iter: I, k: usize) -> Combinations<I>
+where
+    I::Item: Clone,
+{
+    Combinations::new(iter, (0..k).collect())
+}
+
+/// Create a new `ArrayCombinations` from a clonable iterator.
+pub fn array_combinations<I: Iterator, const K: usize>(iter: I) -> ArrayCombinations<I, K>
+where
+    I::Item: Clone,
+{
+    ArrayCombinations::new(iter, array::from_fn(|i| i))
+}
+
 /// An iterator to iterate through all the `k`-length combinations in an iterator.
 ///
-/// See [`.combinations()`](crate::Itertools::combinations) for more information.
+/// See [`.combinations()`](crate::Itertools::combinations) and [`.array_combinations()`](crate::Itertools::array_combinations) for more information.
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-pub struct Combinations<I: Iterator> {
-    indices: Vec<usize>,
+pub struct CombinationsGeneric<I: Iterator, Idx> {
+    indices: Idx,
     pool: LazyBuffer<I>,
     first: bool,
 }
 
-impl<I> Clone for Combinations<I>
+/// A type holding indices of elements in a pool or buffer of items from an inner iterator
+/// and used to pick out different combinations in a generic way.
+pub trait PoolIndex<T>: BorrowMut<[usize]> {
+    type Item;
+
+    fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Self::Item
+    where
+        T: Clone;
+
+    fn len(&self) -> usize {
+        self.borrow().len()
+    }
+}
+
+impl<T> PoolIndex<T> for Vec<usize> {
+    type Item = Vec<T>;
+
+    fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Vec<T>
+    where
+        T: Clone,
+    {
+        pool.get_at(self)
+    }
+}
+
+impl<T, const K: usize> PoolIndex<T> for [usize; K] {
+    type Item = [T; K];
+
+    fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> [T; K]
+    where
+        T: Clone,
+    {
+        pool.get_array(*self)
+    }
+}
+
+impl<I, Idx> Clone for CombinationsGeneric<I, Idx>
 where
-    I: Clone + Iterator,
+    I: Iterator + Clone,
     I::Item: Clone,
+    Idx: Clone,
 {
     clone_fields!(indices, pool, first);
 }
 
-impl<I> fmt::Debug for Combinations<I>
+impl<I, Idx> fmt::Debug for CombinationsGeneric<I, Idx>
 where
     I: Iterator + fmt::Debug,
     I::Item: fmt::Debug,
+    Idx: fmt::Debug,
 {
     debug_fmt_fields!(Combinations, indices, pool, first);
 }
 
-/// Create a new `Combinations` from a clonable iterator.
-pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
-where
-    I: Iterator,
-{
-    Combinations {
-        indices: (0..k).collect(),
-        pool: LazyBuffer::new(iter),
-        first: true,
+impl<I: Iterator, Idx: PoolIndex<I::Item>> CombinationsGeneric<I, Idx> {
+    /// 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<I: Iterator> Combinations<I> {
     /// Returns the length of a combination produced by this iterator.
     #[inline]
     pub fn k(&self) -> usize {
@@ -64,27 +122,7 @@
         &self.pool
     }
 
-    /// Resets this `Combinations` back to an initial state for combinations of length
-    /// `k` over the same pool data source. If `k` is larger than the current length
-    /// of the data pool an attempt is made to prefill the pool so that it holds `k`
-    /// elements.
-    pub(crate) fn reset(&mut self, k: usize) {
-        self.first = true;
-
-        if k < self.indices.len() {
-            self.indices.truncate(k);
-            for i in 0..k {
-                self.indices[i] = i;
-            }
-        } else {
-            for i in 0..self.indices.len() {
-                self.indices[i] = i;
-            }
-            self.indices.extend(self.indices.len()..k);
-            self.pool.prefill(k);
-        }
-    }
-
+    /// Return the length of the inner iterator and the count of remaining combinations.
     pub(crate) fn n_and_count(self) -> (usize, usize) {
         let Self {
             indices,
@@ -92,7 +130,7 @@
             first,
         } = self;
         let n = pool.count();
-        (n, remaining_for(n, first, &indices).unwrap())
+        (n, remaining_for(n, first, indices.borrow()).unwrap())
     }
 
     /// Initialises the iterator by filling a buffer with elements from the
@@ -113,19 +151,21 @@
     ///
     /// Returns true if we've run out of combinations, false otherwise.
     fn increment_indices(&mut self) -> bool {
-        if self.indices.is_empty() {
+        // Borrow once instead of noise each time it's indexed
+        let indices = self.indices.borrow_mut();
+
+        if indices.is_empty() {
             return true; // Done
         }
-
         // Scan from the end, looking for an index to increment
-        let mut i: usize = self.indices.len() - 1;
+        let mut i: usize = indices.len() - 1;
 
         // Check if we need to consume more from the iterator
-        if self.indices[i] == self.pool.len() - 1 {
+        if indices[i] == self.pool.len() - 1 {
             self.pool.get_next(); // may change pool size
         }
 
-        while self.indices[i] == i + self.pool.len() - self.indices.len() {
+        while indices[i] == i + self.pool.len() - indices.len() {
             if i > 0 {
                 i -= 1;
             } else {
@@ -135,11 +175,10 @@
         }
 
         // Increment index, and reset the ones to its right
-        self.indices[i] += 1;
-        for j in i + 1..self.indices.len() {
-            self.indices[j] = self.indices[j - 1] + 1;
+        indices[i] += 1;
+        for j in i + 1..indices.len() {
+            indices[j] = indices[j - 1] + 1;
         }
-
         // If we've made it this far, we haven't run out of combos
         false
     }
@@ -147,6 +186,7 @@
     /// Returns the n-th item or the number of successful steps.
     pub(crate) fn try_nth(&mut self, n: usize) -> Result<<Self as Iterator>::Item, usize>
     where
+        I: Iterator,
         I::Item: Clone,
     {
         let done = if self.first {
@@ -162,16 +202,17 @@
                 return Err(i + 1);
             }
         }
-        Ok(self.pool.get_at(&self.indices))
+        Ok(self.indices.extract_item(&self.pool))
     }
 }
 
-impl<I> Iterator for Combinations<I>
+impl<I, Idx> Iterator for CombinationsGeneric<I, Idx>
 where
     I: Iterator,
     I::Item: Clone,
+    Idx: PoolIndex<I::Item>,
 {
-    type Item = Vec<I::Item>;
+    type Item = Idx::Item;
     fn next(&mut self) -> Option<Self::Item> {
         let done = if self.first {
             self.init()
@@ -183,7 +224,7 @@
             return None;
         }
 
-        Some(self.pool.get_at(&self.indices))
+        Some(self.indices.extract_item(&self.pool))
     }
 
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
@@ -192,8 +233,8 @@
 
     fn size_hint(&self) -> (usize, Option<usize>) {
         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)
     }
 
@@ -203,13 +244,37 @@
     }
 }
 
-impl<I> FusedIterator for Combinations<I>
+impl<I, Idx> FusedIterator for CombinationsGeneric<I, Idx>
 where
     I: Iterator,
     I::Item: Clone,
+    Idx: PoolIndex<I::Item>,
 {
 }
 
+impl<I: Iterator> Combinations<I> {
+    /// Resets this `Combinations` back to an initial state for combinations of length
+    /// `k` over the same pool data source. If `k` is larger than the current length
+    /// of the data pool an attempt is made to prefill the pool so that it holds `k`
+    /// elements.
+    pub(crate) fn reset(&mut self, k: usize) {
+        self.first = true;
+
+        if k < self.indices.len() {
+            self.indices.truncate(k);
+            for i in 0..k {
+                self.indices[i] = i;
+            }
+        } else {
+            for i in 0..self.indices.len() {
+                self.indices[i] = i;
+            }
+            self.indices.extend(self.indices.len()..k);
+            self.pool.prefill(k);
+        }
+    }
+}
+
 /// For a given size `n`, return the count of remaining combinations or None if it would overflow.
 fn remaining_for(n: usize, first: bool, indices: &[usize]) -> Option<usize> {
     let k = indices.len();
diff --git a/crates/itertools/src/combinations_with_replacement.rs b/crates/itertools/src/combinations_with_replacement.rs
index f363f9b..c17e752 100644
--- a/crates/itertools/src/combinations_with_replacement.rs
+++ b/crates/itertools/src/combinations_with_replacement.rs
@@ -73,11 +73,7 @@
             Some((increment_from, increment_value)) => {
                 // We need to update the rightmost non-max value
                 // and all those to the right
-                for i in &mut self.indices[increment_from..] {
-                    *i = increment_value;
-                }
-                // TODO: once MSRV >= 1.50, use `fill` instead:
-                // self.indices[increment_from..].fill(increment_value);
+                self.indices[increment_from..].fill(increment_value);
                 false
             }
             // Otherwise, we're done
diff --git a/crates/itertools/src/concat_impl.rs b/crates/itertools/src/concat_impl.rs
index ec7b91c..dc80839 100644
--- a/crates/itertools/src/concat_impl.rs
+++ b/crates/itertools/src/concat_impl.rs
@@ -1,8 +1,6 @@
-use crate::Itertools;
-
 /// Combine all an iterator's elements into one element by using [`Extend`].
 ///
-/// [`IntoIterator`]-enabled version of [`Itertools::concat`].
+/// [`IntoIterator`]-enabled version of [`Itertools::concat`](crate::Itertools::concat).
 ///
 /// This combinator will extend the first item with each of the rest of the
 /// items of the iterator. If the iterator is empty, the default value of
@@ -19,10 +17,9 @@
     I: IntoIterator,
     I::Item: Extend<<<I as IntoIterator>::Item as IntoIterator>::Item> + IntoIterator + Default,
 {
-    #[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce`
     iterable
         .into_iter()
-        .fold1(|mut a, b| {
+        .reduce(|mut a, b| {
             a.extend(b);
             a
         })
diff --git a/crates/itertools/src/cons_tuples_impl.rs b/crates/itertools/src/cons_tuples_impl.rs
index 9ab3094..7e86260 100644
--- a/crates/itertools/src/cons_tuples_impl.rs
+++ b/crates/itertools/src/cons_tuples_impl.rs
@@ -1,24 +1,15 @@
+use crate::adaptors::map::{MapSpecialCase, MapSpecialCaseFn};
+
 macro_rules! impl_cons_iter(
     ($_A:ident, $_B:ident, ) => (); // stop
 
     ($A:ident, $($B:ident,)*) => (
         impl_cons_iter!($($B,)*);
         #[allow(non_snake_case)]
-        impl<X, Iter, $($B),*> Iterator for ConsTuples<Iter, (($($B,)*), X)>
-            where Iter: Iterator<Item = (($($B,)*), X)>,
-        {
-            type Item = ($($B,)* X, );
-            fn next(&mut self) -> Option<Self::Item> {
-                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
-            }
-
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                self.iter.size_hint()
-            }
-            fn fold<Acc, Fold>(self, accum: Acc, mut f: Fold) -> Acc
-                where Fold: FnMut(Acc, Self::Item) -> Acc,
-            {
-                self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, )))
+        impl<$($B),*, X> MapSpecialCaseFn<(($($B,)*), X)> for ConsTuplesFn {
+            type Out = ($($B,)* X, );
+            fn call(&mut self, (($($B,)*), X): (($($B,)*), X)) -> Self::Out {
+                ($($B,)* X, )
             }
         }
     );
@@ -26,33 +17,23 @@
 
 impl_cons_iter!(A, B, C, D, E, F, G, H, I, J, K, L,);
 
+#[derive(Debug, Clone)]
+pub struct ConsTuplesFn;
+
 /// An iterator that maps an iterator of tuples like
 /// `((A, B), C)` to an iterator of `(A, B, C)`.
 ///
 /// Used by the `iproduct!()` macro.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-#[derive(Debug)]
-pub struct ConsTuples<I, J>
-where
-    I: Iterator<Item = J>,
-{
-    iter: I,
-}
-
-impl<I, J> Clone for ConsTuples<I, J>
-where
-    I: Clone + Iterator<Item = J>,
-{
-    clone_fields!(iter);
-}
+pub type ConsTuples<I> = MapSpecialCase<I, ConsTuplesFn>;
 
 /// Create an iterator that maps for example iterators of
 /// `((A, B), C)` to `(A, B, C)`.
-pub fn cons_tuples<I, J>(iterable: I) -> ConsTuples<I::IntoIter, J>
+pub fn cons_tuples<I>(iterable: I) -> ConsTuples<I::IntoIter>
 where
-    I: IntoIterator<Item = J>,
+    I: IntoIterator,
 {
     ConsTuples {
         iter: iterable.into_iter(),
+        f: ConsTuplesFn,
     }
 }
diff --git a/crates/itertools/src/diff.rs b/crates/itertools/src/diff.rs
index c6d9965..df88d80 100644
--- a/crates/itertools/src/diff.rs
+++ b/crates/itertools/src/diff.rs
@@ -1,7 +1,7 @@
 //! "Diff"ing iterators for caching elements to sequential collections without requiring the new
 //! elements' iterator to be `Clone`.
 //!
-//! - [`Diff`] (produced by the [`diff_with`] function)
+//! [`Diff`] (produced by the [`diff_with`] function)
 //! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
 //! a lock-step comparison.
 
diff --git a/crates/itertools/src/extrema_set.rs b/crates/itertools/src/extrema_set.rs
index d24114c..7d35382 100644
--- a/crates/itertools/src/extrema_set.rs
+++ b/crates/itertools/src/extrema_set.rs
@@ -1,4 +1,3 @@
-#![cfg(feature = "use_alloc")]
 use alloc::{vec, vec::Vec};
 use std::cmp::Ordering;
 
diff --git a/crates/itertools/src/format.rs b/crates/itertools/src/format.rs
index 15cee34..3abdda3 100644
--- a/crates/itertools/src/format.rs
+++ b/crates/itertools/src/format.rs
@@ -47,7 +47,7 @@
     }
 }
 
-impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
+impl<I, F> fmt::Display for FormatWith<'_, I, F>
 where
     I: Iterator,
     F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
@@ -71,7 +71,7 @@
     }
 }
 
-impl<'a, I, F> fmt::Debug for FormatWith<'a, I, F>
+impl<I, F> fmt::Debug for FormatWith<'_, I, F>
 where
     I: Iterator,
     F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
@@ -81,7 +81,7 @@
     }
 }
 
-impl<'a, I> Format<'a, I>
+impl<I> Format<'_, I>
 where
     I: Iterator,
 {
@@ -125,7 +125,7 @@
 
 impl_format! {Display Debug UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
 
-impl<'a, I, F> Clone for FormatWith<'a, I, F>
+impl<I, F> Clone for FormatWith<'_, I, F>
 where
     (I, F): Clone,
 {
@@ -135,7 +135,7 @@
             inner: Option<(I, F)>,
         }
         // This ensures we preserve the state of the original `FormatWith` if `Clone` panics
-        impl<'r, 'a, I, F> Drop for PutBackOnDrop<'r, 'a, I, F> {
+        impl<I, F> Drop for PutBackOnDrop<'_, '_, I, F> {
             fn drop(&mut self) {
                 self.into.inner.set(self.inner.take())
             }
@@ -151,7 +151,7 @@
     }
 }
 
-impl<'a, I> Clone for Format<'a, I>
+impl<I> Clone for Format<'_, I>
 where
     I: Clone,
 {
@@ -161,7 +161,7 @@
             inner: Option<I>,
         }
         // This ensures we preserve the state of the original `FormatWith` if `Clone` panics
-        impl<'r, 'a, I> Drop for PutBackOnDrop<'r, 'a, I> {
+        impl<I> Drop for PutBackOnDrop<'_, '_, I> {
             fn drop(&mut self) {
                 self.into.inner.set(self.inner.take())
             }
diff --git a/crates/itertools/src/free.rs b/crates/itertools/src/free.rs
index 8d0bcf3..4c68205 100644
--- a/crates/itertools/src/free.rs
+++ b/crates/itertools/src/free.rs
@@ -36,7 +36,7 @@
 /// ```
 /// use itertools::intersperse;
 ///
-/// itertools::assert_equal(intersperse((0..3), 8), vec![0, 8, 1, 8, 2]);
+/// itertools::assert_equal(intersperse(0..3, 8), vec![0, 8, 1, 8, 2]);
 /// ```
 pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
 where
@@ -55,7 +55,7 @@
 /// use itertools::intersperse_with;
 ///
 /// let mut i = 10;
-/// itertools::assert_equal(intersperse_with((0..3), || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
+/// itertools::assert_equal(intersperse_with(0..3, || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
 /// assert_eq!(i, 8);
 /// ```
 pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
@@ -75,6 +75,7 @@
 ///
 /// for (i, elt) in enumerate(&[1, 2, 3]) {
 ///     /* loop body */
+///     # let _ = (i, elt);
 /// }
 /// ```
 pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
@@ -93,6 +94,7 @@
 ///
 /// for elt in rev(&[1, 2, 3]) {
 ///     /* loop body */
+///     # let _ = elt;
 /// }
 /// ```
 pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
diff --git a/crates/itertools/src/grouping_map.rs b/crates/itertools/src/grouping_map.rs
index b4aae9e..86cb55d 100644
--- a/crates/itertools/src/grouping_map.rs
+++ b/crates/itertools/src/grouping_map.rs
@@ -1,5 +1,3 @@
-#![cfg(feature = "use_std")]
-
 use crate::{
     adaptors::map::{MapSpecialCase, MapSpecialCaseFn},
     MinMaxResult,
diff --git a/crates/itertools/src/k_smallest.rs b/crates/itertools/src/k_smallest.rs
index 7b2f62e..7e4ace2 100644
--- a/crates/itertools/src/k_smallest.rs
+++ b/crates/itertools/src/k_smallest.rs
@@ -88,6 +88,46 @@
     storage
 }
 
+pub(crate) fn k_smallest_relaxed_general<I, F>(iter: I, k: usize, mut comparator: F) -> Vec<I::Item>
+where
+    I: Iterator,
+    F: FnMut(&I::Item, &I::Item) -> Ordering,
+{
+    if k == 0 {
+        iter.last();
+        return Vec::new();
+    }
+
+    let mut iter = iter.fuse();
+    let mut buf = iter.by_ref().take(2 * k).collect::<Vec<_>>();
+
+    if buf.len() < k {
+        buf.sort_unstable_by(&mut comparator);
+        return buf;
+    }
+
+    buf.select_nth_unstable_by(k - 1, &mut comparator);
+    buf.truncate(k);
+
+    iter.for_each(|val| {
+        if comparator(&val, &buf[k - 1]) != Ordering::Less {
+            return;
+        }
+
+        assert_ne!(buf.len(), buf.capacity());
+        buf.push(val);
+
+        if buf.len() == 2 * k {
+            buf.select_nth_unstable_by(k - 1, &mut comparator);
+            buf.truncate(k);
+        }
+    });
+
+    buf.sort_unstable_by(&mut comparator);
+    buf.truncate(k);
+    buf
+}
+
 #[inline]
 pub(crate) fn key_to_cmp<T, K, F>(mut key: F) -> impl FnMut(&T, &T) -> Ordering
 where
diff --git a/crates/itertools/src/kmerge_impl.rs b/crates/itertools/src/kmerge_impl.rs
index 0be3840..9ea73f9 100644
--- a/crates/itertools/src/kmerge_impl.rs
+++ b/crates/itertools/src/kmerge_impl.rs
@@ -1,5 +1,4 @@
 use crate::size_hint;
-use crate::Itertools;
 
 use alloc::vec::Vec;
 use std::fmt;
@@ -128,13 +127,14 @@
 /// Create an iterator that merges elements of the contained iterators using
 /// the ordering function.
 ///
-/// [`IntoIterator`] enabled version of [`Itertools::kmerge`].
+/// [`IntoIterator`] enabled version of [`Itertools::kmerge`](crate::Itertools::kmerge).
 ///
 /// ```
 /// use itertools::kmerge;
 ///
 /// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
 ///     /* loop body */
+///     # let _ = elt;
 /// }
 /// ```
 pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
@@ -172,7 +172,7 @@
 
 /// Create an iterator that merges elements of the contained iterators.
 ///
-/// [`IntoIterator`] enabled version of [`Itertools::kmerge_by`].
+/// [`IntoIterator`] enabled version of [`Itertools::kmerge_by`](crate::Itertools::kmerge_by).
 pub fn kmerge_by<I, F>(
     iterable: I,
     mut less_than: F,
@@ -223,11 +223,10 @@
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        #[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce`
         self.heap
             .iter()
             .map(|i| i.size_hint())
-            .fold1(size_hint::add)
+            .reduce(size_hint::add)
             .unwrap_or((0, Some(0)))
     }
 }
diff --git a/crates/itertools/src/lazy_buffer.rs b/crates/itertools/src/lazy_buffer.rs
index fefcff8..fafa5f7 100644
--- a/crates/itertools/src/lazy_buffer.rs
+++ b/crates/itertools/src/lazy_buffer.rs
@@ -59,6 +59,10 @@
     pub fn get_at(&self, indices: &[usize]) -> Vec<I::Item> {
         indices.iter().map(|i| self.buffer[*i].clone()).collect()
     }
+
+    pub fn get_array<const K: usize>(&self, indices: [usize; K]) -> [I::Item; K] {
+        indices.map(|i| self.buffer[i].clone())
+    }
 }
 
 impl<I, J> Index<J> for LazyBuffer<I>
diff --git a/crates/itertools/src/lib.rs b/crates/itertools/src/lib.rs
index f4de79c..20226d8 100644
--- a/crates/itertools/src/lib.rs
+++ b/crates/itertools/src/lib.rs
@@ -1,6 +1,7 @@
 #![warn(missing_docs, clippy::default_numeric_fallback)]
 #![crate_name = "itertools"]
 #![cfg_attr(not(feature = "use_std"), no_std)]
+#![doc(test(attr(deny(warnings), allow(deprecated, unstable_name_collisions))))]
 
 //! Extra iterator adaptors, functions and macros.
 //!
@@ -8,6 +9,7 @@
 //! the [`Itertools`] trait:
 //!
 //! ```
+//! # #[allow(unused_imports)]
 //! use itertools::Itertools;
 //! ```
 //!
@@ -29,6 +31,7 @@
 //!
 //! for elt in interleave(&[1, 2, 3], &[2, 3, 4]) {
 //!     /* loop body */
+//!     # let _ = elt;
 //! }
 //! ```
 //!
@@ -46,7 +49,7 @@
 //!
 //! ## Rust Version
 //!
-//! This version of itertools requires Rust 1.43.1 or later.
+//! This version of itertools requires Rust 1.63.0 or later.
 
 #[cfg(not(feature = "use_std"))]
 extern crate core as std;
@@ -94,7 +97,7 @@
         TakeWhileRef, TupleCombinations, Update, WhileSome,
     };
     #[cfg(feature = "use_alloc")]
-    pub use crate::combinations::Combinations;
+    pub use crate::combinations::{ArrayCombinations, Combinations};
     #[cfg(feature = "use_alloc")]
     pub use crate::combinations_with_replacement::CombinationsWithReplacement;
     pub use crate::cons_tuples_impl::ConsTuples;
@@ -206,6 +209,7 @@
 mod minmax;
 #[cfg(feature = "use_alloc")]
 mod multipeek_impl;
+mod next_array;
 mod pad_tail;
 #[cfg(feature = "use_alloc")]
 mod peek_nth;
@@ -248,6 +252,7 @@
 /// // from (0, 0, 0), (0, 0, 1), .., (0, 1, 0), (0, 1, 1), .. etc until (3, 3, 3)
 /// for (i, j, k) in iproduct!(0..4, 0..4, 0..4) {
 ///    // ..
+///    # let _ = (i, j, k);
 /// }
 /// # }
 /// ```
@@ -262,7 +267,10 @@
         $crate::__std_iter::once(())
     );
     ($I:expr $(,)?) => (
-        $crate::__std_iter::IntoIterator::into_iter($I).map(|elt| (elt,))
+        $crate::__std_iter::Iterator::map(
+            $crate::__std_iter::IntoIterator::into_iter($I),
+            |elt| (elt,)
+        )
     );
     ($I:expr, $J:expr $(,)?) => (
         $crate::Itertools::cartesian_product(
@@ -330,19 +338,24 @@
 
     // binary
     ($first:expr, $second:expr $(,)*) => {
-        $crate::izip!($first)
-            .zip($second)
+        $crate::__std_iter::Iterator::zip(
+            $crate::__std_iter::IntoIterator::into_iter($first),
+            $second,
+        )
     };
 
     // n-ary where n > 2
     ( $first:expr $( , $rest:expr )* $(,)* ) => {
-        $crate::izip!($first)
+        {
+            let iter = $crate::__std_iter::IntoIterator::into_iter($first);
             $(
-                .zip($rest)
+                let iter = $crate::__std_iter::Iterator::zip(iter, $rest);
             )*
-            .map(
+            $crate::__std_iter::Iterator::map(
+                iter,
                 $crate::izip!(@closure a => (a) $( , $rest )*)
             )
+        }
     };
 }
 
@@ -367,16 +380,16 @@
 ///
 /// Invocations of `chain!` with one argument expand to [`arg.into_iter()`](IntoIterator):
 /// ```
-/// use std::{ops::Range, slice};
+/// use std::ops::Range;
 /// use itertools::chain;
-/// let _: <Range<_> as IntoIterator>::IntoIter = chain!((2..6),); // trailing comma optional!
+/// let _: <Range<_> as IntoIterator>::IntoIter = chain!(2..6,); // trailing comma optional!
 /// let _:     <&[_] as IntoIterator>::IntoIter = chain!(&[2, 3, 4]);
 /// ```
 ///
 /// Invocations of `chain!` with multiple arguments [`.into_iter()`](IntoIterator) each
 /// argument, and then [`chain`] them together:
 /// ```
-/// use std::{iter::*, ops::Range, slice};
+/// use std::{iter::*, slice};
 /// use itertools::{assert_equal, chain};
 ///
 /// // e.g., this:
@@ -393,16 +406,16 @@
 /// ```
 macro_rules! chain {
     () => {
-        core::iter::empty()
+        $crate::__std_iter::empty()
     };
     ($first:expr $(, $rest:expr )* $(,)?) => {
         {
-            let iter = core::iter::IntoIterator::into_iter($first);
+            let iter = $crate::__std_iter::IntoIterator::into_iter($first);
             $(
                 let iter =
-                    core::iter::Iterator::chain(
+                    $crate::__std_iter::Iterator::chain(
                         iter,
-                        core::iter::IntoIterator::into_iter($rest));
+                        $crate::__std_iter::IntoIterator::into_iter($rest));
             )*
             iter
         }
@@ -415,13 +428,13 @@
 /// This trait defines a number of methods. They are divided into two groups:
 ///
 /// * *Adaptors* take an iterator and parameter as input, and return
-/// a new iterator value. These are listed first in the trait. An example
-/// of an adaptor is [`.interleave()`](Itertools::interleave)
+///   a new iterator value. These are listed first in the trait. An example
+///   of an adaptor is [`.interleave()`](Itertools::interleave)
 ///
 /// * *Regular methods* are those that don't return iterators and instead
-/// return a regular value of some other kind.
-/// [`.next_tuple()`](Itertools::next_tuple) is an example and the first regular
-/// method in the list.
+///   return a regular value of some other kind.
+///   [`.next_tuple()`](Itertools::next_tuple) is an example and the first regular
+///   method in the list.
 pub trait Itertools: Iterator {
     // adaptors
 
@@ -1043,7 +1056,6 @@
     /// let it = a.merge_by(b, |x, y| x.1 <= y.1);
     /// itertools::assert_equal(it, vec![(0, 'a'), (0, 'b'), (1, 'c'), (1, 'd')]);
     /// ```
-
     fn merge_by<J, F>(self, other: J, is_first: F) -> MergeBy<Self, J::IntoIter, F>
     where
         Self: Sized,
@@ -1079,7 +1091,9 @@
     /// let b = (0..10).step_by(3);
     ///
     /// itertools::assert_equal(
-    ///     a.merge_join_by(b, |i, j| i.cmp(j)),
+    ///     // This performs a diff in the style of the Unix command comm(1),
+    ///     // generalized to arbitrary types rather than text.
+    ///     a.merge_join_by(b, Ord::cmp),
     ///     vec![Both(0, 0), Left(2), Right(3), Left(4), Both(6, 6), Left(1), Right(9)]
     /// );
     /// ```
@@ -1111,6 +1125,7 @@
     /// );
     /// ```
     #[inline]
+    #[doc(alias = "comm")]
     fn merge_join_by<J, F, T>(self, other: J, cmp_fn: F) -> MergeJoinBy<Self, J::IntoIter, F>
     where
         J: IntoIterator,
@@ -1582,6 +1597,7 @@
     ///     .collect();
     /// let expected: Vec<_> = vec![1, 2, 3].into_iter().map(NoCloneImpl).collect();
     /// assert_eq!(filtered, expected);
+    #[doc(alias = "take_until")]
     fn take_while_inclusive<F>(self, accept: F) -> TakeWhileInclusive<Self, F>
     where
         Self: Sized,
@@ -1658,6 +1674,53 @@
         adaptors::tuple_combinations(self)
     }
 
+    /// Return an iterator adaptor that iterates over the combinations of the
+    /// elements from an iterator.
+    ///
+    /// Iterator element type is [Self::Item; K]. The iterator produces a new
+    /// array per iteration, and clones the iterator elements.
+    ///
+    /// # Guarantees
+    ///
+    /// If the adapted iterator is deterministic,
+    /// this iterator adapter yields items in a reliable order.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// let mut v = Vec::new();
+    /// for [a, b] in (1..5).array_combinations() {
+    ///     v.push([a, b]);
+    /// }
+    /// assert_eq!(v, vec![[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]);
+    ///
+    /// let mut it = (1..5).array_combinations();
+    /// assert_eq!(Some([1, 2, 3]), it.next());
+    /// assert_eq!(Some([1, 2, 4]), it.next());
+    /// assert_eq!(Some([1, 3, 4]), it.next());
+    /// assert_eq!(Some([2, 3, 4]), it.next());
+    /// assert_eq!(None, it.next());
+    ///
+    /// // this requires a type hint
+    /// let it = (1..5).array_combinations::<3>();
+    /// itertools::assert_equal(it, vec![[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]);
+    ///
+    /// // you can also specify the complete type
+    /// use itertools::ArrayCombinations;
+    /// use std::ops::Range;
+    ///
+    /// let it: ArrayCombinations<Range<u32>, 3> = (1..5).array_combinations();
+    /// itertools::assert_equal(it, vec![[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn array_combinations<const K: usize>(self) -> ArrayCombinations<Self, K>
+    where
+        Self: Sized + Clone,
+        Self::Item: Clone,
+    {
+        combinations::array_combinations(self)
+    }
+
     /// Return an iterator adaptor that iterates over the `k`-length combinations of
     /// the elements from an iterator.
     ///
@@ -1894,7 +1957,7 @@
     /// use itertools::Itertools;
     ///
     /// let input = vec![vec![1], vec![3, 2, 1]];
-    /// let it = input.into_iter().update(|mut v| v.push(0));
+    /// let it = input.into_iter().update(|v| v.push(0));
     /// itertools::assert_equal(it, vec![vec![1, 0], vec![3, 2, 1, 0]]);
     /// ```
     fn update<F>(self, updater: F) -> Update<Self, F>
@@ -1906,6 +1969,50 @@
     }
 
     // non-adaptor methods
+    /// Advances the iterator and returns the next items grouped in an array of
+    /// a specific size.
+    ///
+    /// If there are enough elements to be grouped in an array, then the array
+    /// is returned inside `Some`, otherwise `None` is returned.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// let mut iter = 1..5;
+    ///
+    /// assert_eq!(Some([1, 2]), iter.next_array());
+    /// ```
+    fn next_array<const N: usize>(&mut self) -> Option<[Self::Item; N]>
+    where
+        Self: Sized,
+    {
+        next_array::next_array(self)
+    }
+
+    /// Collects all items from the iterator into an array of a specific size.
+    ///
+    /// If the number of elements inside the iterator is **exactly** equal to
+    /// the array size, then the array is returned inside `Some`, otherwise
+    /// `None` is returned.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// let iter = 1..3;
+    ///
+    /// if let Some([x, y]) = iter.collect_array() {
+    ///     assert_eq!([x, y], [1, 2])
+    /// } else {
+    ///     panic!("Expected two elements")
+    /// }
+    /// ```
+    fn collect_array<const N: usize>(mut self) -> Option<[Self::Item; N]>
+    where
+        Self: Sized,
+    {
+        self.next_array().filter(|_| self.next().is_none())
+    }
+
     /// Advances the iterator and returns the next items grouped in a tuple of
     /// a specific size (up to 12).
     ///
@@ -1986,6 +2093,15 @@
     /// assert_eq!(numbers.iter().find_or_last(|&&x| x > 5), Some(&4));
     /// assert_eq!(numbers.iter().find_or_last(|&&x| x > 2), Some(&3));
     /// assert_eq!(std::iter::empty::<i32>().find_or_last(|&x| x > 5), None);
+    ///
+    /// // An iterator of Results can return the first Ok or the last Err:
+    /// let input = vec![Err(()), Ok(11), Err(()), Ok(22)];
+    /// assert_eq!(input.into_iter().find_or_last(Result::is_ok), Some(Ok(11)));
+    ///
+    /// let input: Vec<Result<(), i32>> = vec![Err(11), Err(22)];
+    /// assert_eq!(input.into_iter().find_or_last(Result::is_ok), Some(Err(22)));
+    ///
+    /// assert_eq!(std::iter::empty::<Result<(), i32>>().find_or_last(Result::is_ok), None);
     /// ```
     fn find_or_last<P>(mut self, mut predicate: P) -> Option<Self::Item>
     where
@@ -2014,6 +2130,15 @@
     /// assert_eq!(numbers.iter().find_or_first(|&&x| x > 5), Some(&1));
     /// assert_eq!(numbers.iter().find_or_first(|&&x| x > 2), Some(&3));
     /// assert_eq!(std::iter::empty::<i32>().find_or_first(|&x| x > 5), None);
+    ///
+    /// // An iterator of Results can return the first Ok or the first Err:
+    /// let input = vec![Err(()), Ok(11), Err(()), Ok(22)];
+    /// assert_eq!(input.into_iter().find_or_first(Result::is_ok), Some(Ok(11)));
+    ///
+    /// let input: Vec<Result<(), i32>> = vec![Err(11), Err(22)];
+    /// assert_eq!(input.into_iter().find_or_first(Result::is_ok), Some(Err(11)));
+    ///
+    /// assert_eq!(std::iter::empty::<Result<(), i32>>().find_or_first(Result::is_ok), None);
     /// ```
     fn find_or_first<P>(mut self, mut predicate: P) -> Option<Self::Item>
     where
@@ -2056,7 +2181,7 @@
     where
         Self: Sized,
         Self::Item: Borrow<Q>,
-        Q: PartialEq,
+        Q: PartialEq + ?Sized,
     {
         self.any(|x| x.borrow() == query)
     }
@@ -2154,7 +2279,7 @@
     /// ```
     /// use itertools::Itertools;
     ///
-    /// let mut iter = "αβγ".chars().dropping(2);
+    /// let iter = "αβγ".chars().dropping(2);
     /// itertools::assert_equal(iter, "γ".chars());
     /// ```
     ///
@@ -2238,14 +2363,17 @@
     ///
     /// fn process_dir_entries(entries: &[fs::DirEntry]) {
     ///     // ...
+    ///     # let _ = entries;
     /// }
     ///
-    /// fn do_stuff() -> std::io::Result<()> {
+    /// fn do_stuff() -> io::Result<()> {
     ///     let entries: Vec<_> = fs::read_dir(".")?.try_collect()?;
     ///     process_dir_entries(&entries);
     ///
     ///     Ok(())
     /// }
+    ///
+    /// # let _ = do_stuff;
     /// ```
     fn try_collect<T, U, E>(self) -> Result<U, E>
     where
@@ -2396,6 +2524,7 @@
     /// accum = f(accum, 1);
     /// accum = f(accum, 2);
     /// accum = f(accum, 3);
+    /// # let _ = accum;
     /// ```
     ///
     /// With a `start` value of 0 and an addition as folding function,
@@ -2520,34 +2649,64 @@
     ///
     /// If `f` is associative you should also decide carefully:
     ///
-    /// - if `f` is a trivial operation like `u32::wrapping_add`, prefer the normal
-    /// [`Iterator::reduce`] instead since it will most likely result in the generation of simpler
-    /// code because the compiler is able to optimize it
-    /// - otherwise if `f` is non-trivial like `format!`, you should use `tree_reduce` since it
-    /// reduces the number of operations from `O(n)` to `O(ln(n))`
+    /// For an iterator producing `n` elements, both [`Iterator::reduce`] and `tree_reduce` will
+    /// call `f` `n - 1` times. However, `tree_reduce` will call `f` on earlier intermediate
+    /// results, which is beneficial for `f` that allocate and produce longer results for longer
+    /// arguments. For example if `f` combines arguments using `format!`, then `tree_reduce` will
+    /// operate on average on shorter arguments resulting in less bytes being allocated overall.
     ///
-    /// Here "non-trivial" means:
+    /// Moreover, the output of `tree_reduce` is preferable to that of [`Iterator::reduce`] in
+    /// certain cases. For example, building a binary search tree using `tree_reduce` will result in
+    /// a balanced tree with height `O(ln(n))`, while [`Iterator::reduce`] will output a tree with
+    /// height `O(n)`, essentially a linked list.
     ///
-    /// - any allocating operation
-    /// - any function that is a composition of many operations
+    /// If `f` does not benefit from such a reordering, like `u32::wrapping_add`, prefer the
+    /// normal [`Iterator::reduce`] instead since it will most likely result in the generation of
+    /// simpler code because the compiler is able to optimize it.
     ///
     /// ```
     /// use itertools::Itertools;
     ///
-    /// // The same tree as above
-    /// let num_strings = (1..8).map(|x| x.to_string());
-    /// assert_eq!(num_strings.tree_reduce(|x, y| format!("f({}, {})", x, y)),
-    ///     Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))")));
+    /// let f = |a: String, b: String| {
+    ///     format!("f({a}, {b})")
+    /// };
     ///
-    /// // Like fold1, an empty iterator produces None
+    /// // The same tree as above
+    /// assert_eq!((1..8).map(|x| x.to_string()).tree_reduce(f),
+    ///            Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))")));
+    ///
+    /// // Like reduce, an empty iterator produces None
     /// assert_eq!((0..0).tree_reduce(|x, y| x * y), None);
     ///
-    /// // tree_reduce matches fold1 for associative operations...
+    /// // tree_reduce matches reduce for associative operations...
     /// assert_eq!((0..10).tree_reduce(|x, y| x + y),
-    ///     (0..10).fold1(|x, y| x + y));
+    ///     (0..10).reduce(|x, y| x + y));
+    ///
     /// // ...but not for non-associative ones
     /// assert_ne!((0..10).tree_reduce(|x, y| x - y),
-    ///     (0..10).fold1(|x, y| x - y));
+    ///     (0..10).reduce(|x, y| x - y));
+    ///
+    /// let mut total_len_reduce = 0;
+    /// let reduce_res = (1..100).map(|x| x.to_string())
+    ///     .reduce(|a, b| {
+    ///         let r = f(a, b);
+    ///         total_len_reduce += r.len();
+    ///         r
+    ///     })
+    ///     .unwrap();
+    ///
+    /// let mut total_len_tree_reduce = 0;
+    /// let tree_reduce_res = (1..100).map(|x| x.to_string())
+    ///     .tree_reduce(|a, b| {
+    ///         let r = f(a, b);
+    ///         total_len_tree_reduce += r.len();
+    ///         r
+    ///     })
+    ///     .unwrap();
+    ///
+    /// assert_eq!(total_len_reduce, 33299);
+    /// assert_eq!(total_len_tree_reduce, 4228);
+    /// assert_eq!(reduce_res.len(), tree_reduce_res.len());
     /// ```
     fn tree_reduce<F>(mut self, mut f: F) -> Option<Self::Item>
     where
@@ -3115,6 +3274,105 @@
         self.k_smallest_by(k, k_smallest::key_to_cmp(key))
     }
 
+    /// Sort the k smallest elements into a new iterator, in ascending order, relaxing the amount of memory required.
+    ///
+    /// **Note:** This consumes the entire iterator, and returns the result
+    /// as a new iterator that owns its elements.  If the input contains
+    /// less than k elements, the result is equivalent to `self.sorted()`.
+    ///
+    /// This is guaranteed to use `2 * k * sizeof(Self::Item) + O(1)` memory
+    /// and `O(n + k log k)` time, with `n` the number of elements in the input,
+    /// meaning it uses more memory than the minimum obtained by [`k_smallest`](Itertools::k_smallest)
+    /// but achieves linear time in the number of elements.
+    ///
+    /// The sorted iterator, if directly collected to a `Vec`, is converted
+    /// without any extra copying or allocation cost.
+    ///
+    /// **Note:** This is functionally-equivalent to `self.sorted().take(k)`
+    /// but much more efficient.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// // A random permutation of 0..15
+    /// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
+    ///
+    /// let five_smallest = numbers
+    ///     .into_iter()
+    ///     .k_smallest_relaxed(5);
+    ///
+    /// itertools::assert_equal(five_smallest, 0..5);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn k_smallest_relaxed(self, k: usize) -> VecIntoIter<Self::Item>
+    where
+        Self: Sized,
+        Self::Item: Ord,
+    {
+        self.k_smallest_relaxed_by(k, Ord::cmp)
+    }
+
+    /// Sort the k smallest elements into a new iterator using the provided comparison, relaxing the amount of memory required.
+    ///
+    /// The sorted iterator, if directly collected to a `Vec`, is converted
+    /// without any extra copying or allocation cost.
+    ///
+    /// This corresponds to `self.sorted_by(cmp).take(k)` in the same way that
+    /// [`k_smallest_relaxed`](Itertools::k_smallest_relaxed) corresponds to `self.sorted().take(k)`,
+    /// in both semantics and complexity.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// // A random permutation of 0..15
+    /// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
+    ///
+    /// let five_smallest = numbers
+    ///     .into_iter()
+    ///     .k_smallest_relaxed_by(5, |a, b| (a % 7).cmp(&(b % 7)).then(a.cmp(b)));
+    ///
+    /// itertools::assert_equal(five_smallest, vec![0, 7, 14, 1, 8]);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn k_smallest_relaxed_by<F>(self, k: usize, cmp: F) -> VecIntoIter<Self::Item>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item, &Self::Item) -> Ordering,
+    {
+        k_smallest::k_smallest_relaxed_general(self, k, cmp).into_iter()
+    }
+
+    /// Return the elements producing the k smallest outputs of the provided function, relaxing the amount of memory required.
+    ///
+    /// The sorted iterator, if directly collected to a `Vec`, is converted
+    /// without any extra copying or allocation cost.
+    ///
+    /// This corresponds to `self.sorted_by_key(key).take(k)` in the same way that
+    /// [`k_smallest_relaxed`](Itertools::k_smallest_relaxed) corresponds to `self.sorted().take(k)`,
+    /// in both semantics and complexity.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// // A random permutation of 0..15
+    /// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
+    ///
+    /// let five_smallest = numbers
+    ///     .into_iter()
+    ///     .k_smallest_relaxed_by_key(5, |n| (n % 7, *n));
+    ///
+    /// itertools::assert_equal(five_smallest, vec![0, 7, 14, 1, 8]);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn k_smallest_relaxed_by_key<F, K>(self, k: usize, key: F) -> VecIntoIter<Self::Item>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item) -> K,
+        K: Ord,
+    {
+        self.k_smallest_relaxed_by(k, k_smallest::key_to_cmp(key))
+    }
+
     /// Sort the k largest elements into a new iterator, in descending order.
     ///
     /// The sorted iterator, if directly collected to a `Vec`, is converted
@@ -3205,6 +3463,94 @@
         self.k_largest_by(k, k_smallest::key_to_cmp(key))
     }
 
+    /// Sort the k largest elements into a new iterator, in descending order, relaxing the amount of memory required.
+    ///
+    /// The sorted iterator, if directly collected to a `Vec`, is converted
+    /// without any extra copying or allocation cost.
+    ///
+    /// It is semantically equivalent to [`k_smallest_relaxed`](Itertools::k_smallest_relaxed)
+    /// with a reversed `Ord`.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// // A random permutation of 0..15
+    /// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
+    ///
+    /// let five_largest = numbers
+    ///     .into_iter()
+    ///     .k_largest_relaxed(5);
+    ///
+    /// itertools::assert_equal(five_largest, vec![14, 13, 12, 11, 10]);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn k_largest_relaxed(self, k: usize) -> VecIntoIter<Self::Item>
+    where
+        Self: Sized,
+        Self::Item: Ord,
+    {
+        self.k_largest_relaxed_by(k, Self::Item::cmp)
+    }
+
+    /// Sort the k largest elements into a new iterator using the provided comparison, relaxing the amount of memory required.
+    ///
+    /// The sorted iterator, if directly collected to a `Vec`, is converted
+    /// without any extra copying or allocation cost.
+    ///
+    /// Functionally equivalent to [`k_smallest_relaxed_by`](Itertools::k_smallest_relaxed_by)
+    /// with a reversed `Ord`.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// // A random permutation of 0..15
+    /// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
+    ///
+    /// let five_largest = numbers
+    ///     .into_iter()
+    ///     .k_largest_relaxed_by(5, |a, b| (a % 7).cmp(&(b % 7)).then(a.cmp(b)));
+    ///
+    /// itertools::assert_equal(five_largest, vec![13, 6, 12, 5, 11]);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn k_largest_relaxed_by<F>(self, k: usize, mut cmp: F) -> VecIntoIter<Self::Item>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item, &Self::Item) -> Ordering,
+    {
+        self.k_smallest_relaxed_by(k, move |a, b| cmp(b, a))
+    }
+
+    /// Return the elements producing the k largest outputs of the provided function, relaxing the amount of memory required.
+    ///
+    /// The sorted iterator, if directly collected to a `Vec`, is converted
+    /// without any extra copying or allocation cost.
+    ///
+    /// Functionally equivalent to [`k_smallest_relaxed_by_key`](Itertools::k_smallest_relaxed_by_key)
+    /// with a reversed `Ord`.
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// // A random permutation of 0..15
+    /// let numbers = vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5];
+    ///
+    /// let five_largest = numbers
+    ///     .into_iter()
+    ///     .k_largest_relaxed_by_key(5, |n| (n % 7, *n));
+    ///
+    /// itertools::assert_equal(five_largest, vec![13, 6, 12, 5, 11]);
+    /// ```
+    #[cfg(feature = "use_alloc")]
+    fn k_largest_relaxed_by_key<F, K>(self, k: usize, key: F) -> VecIntoIter<Self::Item>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item) -> K,
+        K: Ord,
+    {
+        self.k_largest_relaxed_by(k, k_smallest::key_to_cmp(key))
+    }
+
     /// Consumes the iterator and return an iterator of the last `n` elements.
     ///
     /// The iterator, if directly collected to a `VecDeque`, is converted
@@ -3357,8 +3703,8 @@
         group_map::into_group_map(self)
     }
 
-    /// Return an `Iterator` on a `HashMap`. Keys mapped to `Vec`s of values. The key is specified
-    /// in the closure.
+    /// Return a `HashMap` of keys mapped to `Vec`s of values. The key is specified
+    /// in the closure. The values are taken from the input iterator.
     ///
     /// Essentially a shorthand for `.into_grouping_map_by(f).collect::<Vec<_>>()`.
     ///
@@ -3370,7 +3716,7 @@
     /// let lookup: HashMap<u32,Vec<(u32, u32)>> =
     ///     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)]);
@@ -4125,7 +4471,7 @@
     /// # Examples
     /// ```
     /// # use itertools::Itertools;
-    /// let counts = [1, 1, 1, 3, 3, 5].into_iter().counts();
+    /// let counts = [1, 1, 1, 3, 3, 5].iter().counts();
     /// assert_eq!(counts[&1], 3);
     /// assert_eq!(counts[&3], 2);
     /// assert_eq!(counts[&5], 1);
@@ -4151,6 +4497,7 @@
     /// # use itertools::Itertools;
     /// struct Character {
     ///   first_name: &'static str,
+    ///   # #[allow(dead_code)]
     ///   last_name:  &'static str,
     /// }
     ///
@@ -4268,6 +4615,7 @@
 /// assert_equal("exceed".split('c'), "excess".split('c'));
 /// // ^PANIC: panicked at 'Failed assertion Some("eed") == Some("ess") for iteration 1'.
 /// ```
+#[track_caller]
 pub fn assert_equal<I, J>(a: I, b: J)
 where
     I: IntoIterator,
diff --git a/crates/itertools/src/merge_join.rs b/crates/itertools/src/merge_join.rs
index c0de35f..5f4a605 100644
--- a/crates/itertools/src/merge_join.rs
+++ b/crates/itertools/src/merge_join.rs
@@ -31,6 +31,7 @@
 ///
 /// for elt in merge(&[1, 2, 3], &[2, 3, 4]) {
 ///     /* loop body */
+///     # let _ = elt;
 /// }
 /// ```
 pub fn merge<I, J>(
diff --git a/crates/itertools/src/next_array.rs b/crates/itertools/src/next_array.rs
new file mode 100644
index 0000000..86480b1
--- /dev/null
+++ b/crates/itertools/src/next_array.rs
@@ -0,0 +1,269 @@
+use core::mem::{self, MaybeUninit};
+
+/// An array of at most `N` elements.
+struct ArrayBuilder<T, const N: usize> {
+    /// The (possibly uninitialized) elements of the `ArrayBuilder`.
+    ///
+    /// # Safety
+    ///
+    /// The elements of `arr[..len]` are valid `T`s.
+    arr: [MaybeUninit<T>; N],
+
+    /// The number of leading elements of `arr` that are valid `T`s, len <= N.
+    len: usize,
+}
+
+impl<T, const N: usize> ArrayBuilder<T, N> {
+    /// Initializes a new, empty `ArrayBuilder`.
+    pub fn new() -> Self {
+        // SAFETY: The safety invariant of `arr` trivially holds for `len = 0`.
+        Self {
+            arr: [(); N].map(|_| MaybeUninit::uninit()),
+            len: 0,
+        }
+    }
+
+    /// Pushes `value` onto the end of the array.
+    ///
+    /// # Panics
+    ///
+    /// This panics if `self.len >= N`.
+    #[inline(always)]
+    pub fn push(&mut self, value: T) {
+        // PANICS: This will panic if `self.len >= N`.
+        let place = &mut self.arr[self.len];
+        // SAFETY: The safety invariant of `self.arr` applies to elements at
+        // indices `0..self.len` — not to the element at `self.len`. Writing to
+        // the element at index `self.len` therefore does not violate the safety
+        // invariant of `self.arr`. Even if this line panics, we have not
+        // created any intermediate invalid state.
+        *place = MaybeUninit::new(value);
+        // Lemma: `self.len < N`. By invariant, `self.len <= N`. Above, we index
+        // into `self.arr`, which has size `N`, at index `self.len`. If `self.len == N`
+        // at that point, that index would be out-of-bounds, and the index
+        // operation would panic. Thus, `self.len != N`, and since `self.len <= N`,
+        // that means that `self.len < N`.
+        //
+        // PANICS: Since `self.len < N`, and since `N <= usize::MAX`,
+        // `self.len + 1 <= usize::MAX`, and so `self.len += 1` will not
+        // overflow. Overflow is the only panic condition of `+=`.
+        //
+        // SAFETY:
+        // - We are required to uphold the invariant that `self.len <= N`.
+        //   Since, by the preceding lemma, `self.len < N` at this point in the
+        //   code, `self.len += 1` results in `self.len <= N`.
+        // - We are required to uphold the invariant that `self.arr[..self.len]`
+        //   are valid instances of `T`. Since this invariant already held when
+        //   this method was called, and since we only increment `self.len`
+        //   by 1 here, we only need to prove that the element at
+        //   `self.arr[self.len]` (using the value of `self.len` before incrementing)
+        //   is valid. Above, we construct `place` to point to `self.arr[self.len]`,
+        //   and then initialize `*place` to `MaybeUninit::new(value)`, which is
+        //   a valid `T` by construction.
+        self.len += 1;
+    }
+
+    /// Consumes the elements in the `ArrayBuilder` and returns them as an array
+    /// `[T; N]`.
+    ///
+    /// If `self.len() < N`, this returns `None`.
+    pub fn take(&mut self) -> Option<[T; N]> {
+        if self.len == N {
+            // SAFETY: Decreasing the value of `self.len` cannot violate the
+            // safety invariant on `self.arr`.
+            self.len = 0;
+
+            // SAFETY: Since `self.len` is 0, `self.arr` may safely contain
+            // uninitialized elements.
+            let arr = mem::replace(&mut self.arr, [(); N].map(|_| MaybeUninit::uninit()));
+
+            Some(arr.map(|v| {
+                // SAFETY: We know that all elements of `arr` are valid because
+                // we checked that `len == N`.
+                unsafe { v.assume_init() }
+            }))
+        } else {
+            None
+        }
+    }
+}
+
+impl<T, const N: usize> AsMut<[T]> for ArrayBuilder<T, N> {
+    fn as_mut(&mut self) -> &mut [T] {
+        let valid = &mut self.arr[..self.len];
+        // SAFETY: By invariant on `self.arr`, the elements of `self.arr` at
+        // indices `0..self.len` are in a valid state. Since `valid` references
+        // only these elements, the safety precondition of
+        // `slice_assume_init_mut` is satisfied.
+        unsafe { slice_assume_init_mut(valid) }
+    }
+}
+
+impl<T, const N: usize> Drop for ArrayBuilder<T, N> {
+    // We provide a non-trivial `Drop` impl, because the trivial impl would be a
+    // no-op; `MaybeUninit<T>` has no innate awareness of its own validity, and
+    // so it can only forget its contents. By leveraging the safety invariant of
+    // `self.arr`, we do know which elements of `self.arr` are valid, and can
+    // selectively run their destructors.
+    fn drop(&mut self) {
+        // SAFETY:
+        // - by invariant on `&mut [T]`, `self.as_mut()` is:
+        //   - valid for reads and writes
+        //   - properly aligned
+        //   - non-null
+        // - the dropped `T` are valid for dropping; they do not have any
+        //   additional library invariants that we've violated
+        // - no other pointers to `valid` exist (since we're in the context of
+        //   `drop`)
+        unsafe { core::ptr::drop_in_place(self.as_mut()) }
+    }
+}
+
+/// Assuming all the elements are initialized, get a mutable slice to them.
+///
+/// # Safety
+///
+/// The caller guarantees that the elements `T` referenced by `slice` are in a
+/// valid state.
+unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
+    // SAFETY: Casting `&mut [MaybeUninit<T>]` to `&mut [T]` is sound, because
+    // `MaybeUninit<T>` is guaranteed to have the same size, alignment and ABI
+    // as `T`, and because the caller has guaranteed that `slice` is in the
+    // valid state.
+    unsafe { &mut *(slice as *mut [MaybeUninit<T>] as *mut [T]) }
+}
+
+/// Equivalent to `it.next_array()`.
+pub(crate) fn next_array<I, const N: usize>(it: &mut I) -> Option<[I::Item; N]>
+where
+    I: Iterator,
+{
+    let mut builder = ArrayBuilder::new();
+    for _ in 0..N {
+        builder.push(it.next()?);
+    }
+    builder.take()
+}
+
+#[cfg(test)]
+mod test {
+    use super::ArrayBuilder;
+
+    #[test]
+    fn zero_len_take() {
+        let mut builder = ArrayBuilder::<(), 0>::new();
+        let taken = builder.take();
+        assert_eq!(taken, Some([(); 0]));
+    }
+
+    #[test]
+    #[should_panic]
+    fn zero_len_push() {
+        let mut builder = ArrayBuilder::<(), 0>::new();
+        builder.push(());
+    }
+
+    #[test]
+    fn push_4() {
+        let mut builder = ArrayBuilder::<(), 4>::new();
+        assert_eq!(builder.take(), None);
+
+        builder.push(());
+        assert_eq!(builder.take(), None);
+
+        builder.push(());
+        assert_eq!(builder.take(), None);
+
+        builder.push(());
+        assert_eq!(builder.take(), None);
+
+        builder.push(());
+        assert_eq!(builder.take(), Some([(); 4]));
+    }
+
+    #[test]
+    fn tracked_drop() {
+        use std::panic::{catch_unwind, AssertUnwindSafe};
+        use std::sync::atomic::{AtomicU16, Ordering};
+
+        static DROPPED: AtomicU16 = AtomicU16::new(0);
+
+        #[derive(Debug, PartialEq)]
+        struct TrackedDrop;
+
+        impl Drop for TrackedDrop {
+            fn drop(&mut self) {
+                DROPPED.fetch_add(1, Ordering::Relaxed);
+            }
+        }
+
+        {
+            let builder = ArrayBuilder::<TrackedDrop, 0>::new();
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
+            drop(builder);
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
+        }
+
+        {
+            let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
+            builder.push(TrackedDrop);
+            assert_eq!(builder.take(), None);
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
+            drop(builder);
+            assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 1);
+        }
+
+        {
+            let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
+            builder.push(TrackedDrop);
+            builder.push(TrackedDrop);
+            assert!(matches!(builder.take(), Some(_)));
+            assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 2);
+            drop(builder);
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
+        }
+
+        {
+            let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
+
+            builder.push(TrackedDrop);
+            builder.push(TrackedDrop);
+
+            assert!(catch_unwind(AssertUnwindSafe(|| {
+                builder.push(TrackedDrop);
+            }))
+            .is_err());
+
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 1);
+
+            drop(builder);
+
+            assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 3);
+        }
+
+        {
+            let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
+
+            builder.push(TrackedDrop);
+            builder.push(TrackedDrop);
+
+            assert!(catch_unwind(AssertUnwindSafe(|| {
+                builder.push(TrackedDrop);
+            }))
+            .is_err());
+
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 1);
+
+            assert!(matches!(builder.take(), Some(_)));
+
+            assert_eq!(DROPPED.load(Ordering::Relaxed), 3);
+
+            builder.push(TrackedDrop);
+            builder.push(TrackedDrop);
+
+            assert!(matches!(builder.take(), Some(_)));
+
+            assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 5);
+        }
+    }
+}
diff --git a/crates/itertools/src/peeking_take_while.rs b/crates/itertools/src/peeking_take_while.rs
index 19872a9..f3259a9 100644
--- a/crates/itertools/src/peeking_take_while.rs
+++ b/crates/itertools/src/peeking_take_while.rs
@@ -22,7 +22,7 @@
         F: FnOnce(&Self::Item) -> bool;
 }
 
-impl<'a, I> PeekingNext for &'a mut I
+impl<I> PeekingNext for &mut I
 where
     I: PeekingNext,
 {
@@ -133,7 +133,7 @@
     PeekingTakeWhile { iter, f }
 }
 
-impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F>
+impl<I, F> Iterator for PeekingTakeWhile<'_, I, F>
 where
     I: PeekingNext,
     F: FnMut(&I::Item) -> bool,
@@ -148,7 +148,7 @@
     }
 }
 
-impl<'a, I, F> PeekingNext for PeekingTakeWhile<'a, I, F>
+impl<I, F> PeekingNext for PeekingTakeWhile<'_, I, F>
 where
     I: PeekingNext,
     F: FnMut(&I::Item) -> bool,
diff --git a/crates/itertools/src/process_results_impl.rs b/crates/itertools/src/process_results_impl.rs
index ad6c60d..31389c5 100644
--- a/crates/itertools/src/process_results_impl.rs
+++ b/crates/itertools/src/process_results_impl.rs
@@ -13,7 +13,7 @@
     iter: I,
 }
 
-impl<'a, I, E> ProcessResults<'a, I, E> {
+impl<I, E> ProcessResults<'_, I, E> {
     #[inline(always)]
     fn next_body<T>(&mut self, item: Option<Result<T, E>>) -> Option<T> {
         match item {
@@ -27,7 +27,7 @@
     }
 }
 
-impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
+impl<I, T, E> Iterator for ProcessResults<'_, I, E>
 where
     I: Iterator<Item = Result<T, E>>,
 {
@@ -60,7 +60,7 @@
     }
 }
 
-impl<'a, I, T, E> DoubleEndedIterator for ProcessResults<'a, I, E>
+impl<I, T, E> DoubleEndedIterator for ProcessResults<'_, I, E>
 where
     I: Iterator<Item = Result<T, E>>,
     I: DoubleEndedIterator,
diff --git a/crates/itertools/src/rciter_impl.rs b/crates/itertools/src/rciter_impl.rs
index e3b7532..96a0fd6 100644
--- a/crates/itertools/src/rciter_impl.rs
+++ b/crates/itertools/src/rciter_impl.rs
@@ -87,7 +87,7 @@
 }
 
 /// Return an iterator from `&RcIter<I>` (by simply cloning it).
-impl<'a, I> IntoIterator for &'a RcIter<I>
+impl<I> IntoIterator for &RcIter<I>
 where
     I: Iterator,
 {
diff --git a/crates/itertools/src/zip_eq_impl.rs b/crates/itertools/src/zip_eq_impl.rs
index 6d3b682..3240a40 100644
--- a/crates/itertools/src/zip_eq_impl.rs
+++ b/crates/itertools/src/zip_eq_impl.rs
@@ -21,6 +21,7 @@
 /// let data = [1, 2, 3, 4, 5];
 /// for (a, b) in zip_eq(&data[..data.len() - 1], &data[1..]) {
 ///     /* loop body */
+///     # let _ = (a, b);
 /// }
 /// ```
 pub fn zip_eq<I, J>(i: I, j: J) -> ZipEq<I::IntoIter, J::IntoIter>
diff --git a/crates/itertools/tests/macros_hygiene.rs b/crates/itertools/tests/macros_hygiene.rs
index 20b59fb..e6e8955 100644
--- a/crates/itertools/tests/macros_hygiene.rs
+++ b/crates/itertools/tests/macros_hygiene.rs
@@ -1,3 +1,8 @@
+mod alloc {}
+mod core {}
+mod either {}
+mod std {}
+
 #[test]
 fn iproduct_hygiene() {
     let _ = itertools::iproduct!();
@@ -12,3 +17,11 @@
     let _ = itertools::izip!(0..6, 0..9);
     let _ = itertools::izip!(0..6, 0..9, 0..12);
 }
+
+#[test]
+fn chain_hygiene() {
+    let _: ::std::iter::Empty<i32> = itertools::chain!();
+    let _ = itertools::chain!(0..6);
+    let _ = itertools::chain!(0..6, 0..9);
+    let _ = itertools::chain!(0..6, 0..9, 0..12);
+}
diff --git a/crates/itertools/tests/quick.rs b/crates/itertools/tests/quick.rs
index 5b8fd6a..672901e 100644
--- a/crates/itertools/tests/quick.rs
+++ b/crates/itertools/tests/quick.rs
@@ -2,7 +2,11 @@
 //! and adaptors.
 //!
 //! In particular we test the tedious size_hint and exact size correctness.
+//!
+//! **NOTE:** Due to performance limitations, these tests are not run with miri!
+//! They cannot be relied upon to discover soundness issues.
 
+#![cfg(not(miri))]
 #![allow(deprecated, unstable_name_collisions)]
 
 use itertools::free::{
@@ -253,7 +257,6 @@
         let mut it = get_it();
 
         for _ in 0..(counts.len() - 1) {
-            #[allow(clippy::manual_assert)]
             if it.next().is_none() {
                 panic!("Iterator shouldn't be finished, may not be deterministic");
             }
@@ -1512,13 +1515,12 @@
                 acc + val
             });
 
-        // TODO: Swap `fold1` with stdlib's `reduce` when it's stabilized
         let group_map_lookup = a.iter()
             .map(|&b| b as u64)
             .map(|i| (i % modulo, i))
             .into_group_map()
             .into_iter()
-            .map(|(key, vals)| (key, vals.into_iter().fold1(|acc, val| acc + val).unwrap()))
+            .map(|(key, vals)| (key, vals.into_iter().reduce(|acc, val| acc + val).unwrap()))
             .collect::<HashMap<_,_>>();
         assert_eq!(lookup, group_map_lookup);
 
diff --git a/crates/itertools/tests/specializations.rs b/crates/itertools/tests/specializations.rs
index 7123114..e6694c8 100644
--- a/crates/itertools/tests/specializations.rs
+++ b/crates/itertools/tests/specializations.rs
@@ -1,3 +1,10 @@
+//! Test specializations of methods with default impls match the behavior of the
+//! default impls.
+//!
+//! **NOTE:** Due to performance limitations, these tests are not run with miri!
+//! They cannot be relied upon to discover soundness issues.
+
+#![cfg(not(miri))]
 #![allow(unstable_name_collisions)]
 
 use itertools::Itertools;
@@ -266,6 +273,16 @@
         test_specializations(&v.into_iter().intersperse_with(|| 0));
     }
 
+    fn array_combinations(v: Vec<u8>) -> TestResult {
+        if v.len() > 10 {
+            return TestResult::discard();
+        }
+        test_specializations(&v.iter().array_combinations::<1>());
+        test_specializations(&v.iter().array_combinations::<2>());
+        test_specializations(&v.iter().array_combinations::<3>());
+        TestResult::passed()
+    }
+
     fn combinations(a: Vec<u8>, n: u8) -> TestResult {
         if n > 3 || a.len() > 8 {
             return TestResult::discard();
@@ -447,11 +464,15 @@
     }
 
     fn filter_ok(v: Vec<Result<u8, char>>) -> () {
-        test_specializations(&v.into_iter().filter_ok(|&i| i < 20));
+        let it = v.into_iter().filter_ok(|&i| i < 20);
+        test_specializations(&it);
+        test_double_ended_specializations(&it);
     }
 
     fn filter_map_ok(v: Vec<Result<u8, char>>) -> () {
-        test_specializations(&v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None }));
+        let it = v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None });
+        test_specializations(&it);
+        test_double_ended_specializations(&it);
     }
 
     // `SmallIter2<u8>` because `Vec<u8>` is too slow and we get bad coverage from a singleton like Option<u8>
diff --git a/crates/itertools/tests/test_core.rs b/crates/itertools/tests/test_core.rs
index 32af246..4936160 100644
--- a/crates/itertools/tests/test_core.rs
+++ b/crates/itertools/tests/test_core.rs
@@ -372,3 +372,28 @@
     assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
     assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
 }
+
+#[test]
+fn next_array() {
+    let v = [1, 2, 3, 4, 5];
+    let mut iter = v.iter();
+    assert_eq!(iter.next_array(), Some([]));
+    assert_eq!(iter.next_array().map(|[&x, &y]| [x, y]), Some([1, 2]));
+    assert_eq!(iter.next_array().map(|[&x, &y]| [x, y]), Some([3, 4]));
+    assert_eq!(iter.next_array::<2>(), None);
+}
+
+#[test]
+fn collect_array() {
+    let v = [1, 2];
+    let iter = v.iter().cloned();
+    assert_eq!(iter.collect_array(), Some([1, 2]));
+
+    let v = [1];
+    let iter = v.iter().cloned();
+    assert_eq!(iter.collect_array::<2>(), None);
+
+    let v = [1, 2, 3];
+    let iter = v.iter().cloned();
+    assert_eq!(iter.collect_array::<2>(), None);
+}
diff --git a/crates/itertools/tests/test_std.rs b/crates/itertools/tests/test_std.rs
index 00246d5..ad391fa 100644
--- a/crates/itertools/tests/test_std.rs
+++ b/crates/itertools/tests/test_std.rs
@@ -491,6 +491,7 @@
     it::assert_equal(v, vec![4, 3, 2, 1, 0]);
 }
 
+#[cfg(not(miri))]
 qc::quickcheck! {
     fn k_smallest_range(n: i64, m: u16, k: u16) -> () {
         // u16 is used to constrain k and m to 0..2¹⁶,
@@ -527,6 +528,42 @@
         it::assert_equal(largest_by, sorted_largest.clone());
         it::assert_equal(largest_by_key, sorted_largest);
     }
+
+    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 mut v: Vec<_> = (n..n.saturating_add(m as _)).collect();
+        // Generate a random permutation of n..n+m
+        v.shuffle(&mut thread_rng());
+
+        // Construct the right answers for the top and bottom elements
+        let mut sorted = v.clone();
+        sorted.sort();
+        // how many elements are we checking
+        let num_elements = min(k, m as _);
+
+        // Compute the top and bottom k in various combinations
+        let sorted_smallest = sorted[..num_elements].iter().cloned();
+        let smallest = v.iter().cloned().k_smallest_relaxed(k);
+        let smallest_by = v.iter().cloned().k_smallest_relaxed_by(k, Ord::cmp);
+        let smallest_by_key = v.iter().cloned().k_smallest_relaxed_by_key(k, |&x| x);
+
+        let sorted_largest = sorted[sorted.len() - num_elements..].iter().rev().cloned();
+        let largest = v.iter().cloned().k_largest_relaxed(k);
+        let largest_by = v.iter().cloned().k_largest_relaxed_by(k, Ord::cmp);
+        let largest_by_key = v.iter().cloned().k_largest_relaxed_by_key(k, |&x| x);
+
+        // Check the variations produce the same answers and that they're right
+        it::assert_equal(smallest, sorted_smallest.clone());
+        it::assert_equal(smallest_by, sorted_smallest.clone());
+        it::assert_equal(smallest_by_key, sorted_smallest);
+
+        it::assert_equal(largest, sorted_largest.clone());
+        it::assert_equal(largest_by, sorted_largest.clone());
+        it::assert_equal(largest_by_key, sorted_largest);
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -571,8 +608,11 @@
     I::Item: Ord + Debug,
 {
     let j = i.clone();
+    let i1 = i.clone();
+    let j1 = i.clone();
     let k = k as usize;
-    it::assert_equal(i.k_smallest(k), j.sorted().take(k))
+    it::assert_equal(i.k_smallest(k), j.sorted().take(k));
+    it::assert_equal(i1.k_smallest_relaxed(k), j1.sorted().take(k));
 }
 
 // Similar to `k_smallest_sort` but for our custom heap implementation.
@@ -582,8 +622,11 @@
     I::Item: Ord + Debug,
 {
     let j = i.clone();
+    let i1 = i.clone();
+    let j1 = i.clone();
     let k = k as usize;
-    it::assert_equal(i.k_smallest_by(k, Ord::cmp), j.sorted().take(k))
+    it::assert_equal(i.k_smallest_by(k, Ord::cmp), j.sorted().take(k));
+    it::assert_equal(i1.k_smallest_relaxed_by(k, Ord::cmp), j1.sorted().take(k));
 }
 
 macro_rules! generic_test {
@@ -598,7 +641,9 @@
     };
 }
 
+#[cfg(not(miri))]
 generic_test!(k_smallest_sort, u8, u16, u32, u64, i8, i16, i32, i64);
+#[cfg(not(miri))]
 generic_test!(k_smallest_by_sort, u8, u16, u32, u64, i8, i16, i32, i64);
 
 #[test]
@@ -1055,8 +1100,8 @@
 
 #[test]
 fn combinations_range_count() {
-    for n in 0..=10 {
-        for k in 0..=10 {
+    for n in 0..=7 {
+        for k in 0..=7 {
             let len = binomial(n, k);
             let mut it = (0..n).combinations(k);
             assert_eq!(len, it.clone().count());
@@ -1077,7 +1122,7 @@
 
 #[test]
 fn combinations_inexact_size_hints() {
-    for k in 0..=10 {
+    for k in 0..=7 {
         let mut numbers = (0..18).filter(|i| i % 2 == 0); // 9 elements
         let mut it = numbers.clone().combinations(k);
         let real_n = numbers.clone().count();
@@ -1129,8 +1174,8 @@
 
 #[test]
 fn permutations_range_count() {
-    for n in 0..=7 {
-        for k in 0..=7 {
+    for n in 0..=4 {
+        for k in 0..=4 {
             let len = if k <= n { (n - k + 1..=n).product() } else { 0 };
             let mut it = (0..n).permutations(k);
             assert_eq!(len, it.clone().count());
@@ -1162,6 +1207,7 @@
 }
 
 #[test]
+#[cfg(not(miri))]
 fn combinations_with_replacement() {
     // Pool smaller than n
     it::assert_equal((0..1).combinations_with_replacement(2), vec![vec![0, 0]]);
@@ -1190,8 +1236,8 @@
 
 #[test]
 fn combinations_with_replacement_range_count() {
-    for n in 0..=7 {
-        for k in 0..=7 {
+    for n in 0..=4 {
+        for k in 0..=4 {
             let len = binomial(usize::saturating_sub(n + k, 1), k);
             let mut it = (0..n).combinations_with_replacement(k);
             assert_eq!(len, it.clone().count());
@@ -1236,7 +1282,7 @@
     assert_eq!((0..8).powerset().count(), 1 << 8);
     assert_eq!((0..16).powerset().count(), 1 << 16);
 
-    for n in 0..=10 {
+    for n in 0..=4 {
         let mut it = (0..n).powerset();
         let len = 2_usize.pow(n);
         assert_eq!(len, it.clone().count());
diff --git a/crates/itertools/tests/zip.rs b/crates/itertools/tests/zip.rs
index 716ac20..daed31e 100644
--- a/crates/itertools/tests/zip.rs
+++ b/crates/itertools/tests/zip.rs
@@ -20,7 +20,7 @@
     let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
     let v2 = &[10, 11, 12];
 
-    assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None));
+    assert_eq!(c.zip_longest(v.iter()).size_hint(), (usize::MAX, None));
 
     assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
 }
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 39eaecd..4dd188c 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -241,7 +241,7 @@
  "inotify-sys",
  "instant",
  "intrusive-collections",
- "itertools 0.13.0",
+ "itertools 0.14.0",
  "itoa",
  "jni",
  "jni-sys",
@@ -2771,9 +2771,9 @@
 
 [[package]]
 name = "itertools"
-version = "0.13.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
 dependencies = [
  "either",
 ]
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 419e9da..44fdb9d 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -156,7 +156,7 @@
 inotify-sys = "=0.1.5"
 instant = "=0.1.12"
 intrusive-collections = "=0.9.7"
-itertools = "=0.13.0"
+itertools = "=0.14.0"
 itoa = "=1.0.14"
 jni = "=0.21.1"
 jni-sys = "=0.3.0"